001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     ldoguin, Antoine Taillefer
016 *
017 * $Id$
018 */
019
020package org.nuxeo.ecm.platform.task.core.service;
021
022import java.io.Serializable;
023import java.util.ArrayList;
024import java.util.Date;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028
029import org.apache.commons.lang.StringUtils;
030import org.nuxeo.common.utils.Path;
031import org.nuxeo.ecm.core.api.CoreSession;
032import org.nuxeo.ecm.core.api.DocumentModel;
033import org.nuxeo.ecm.core.api.DocumentModelList;
034import org.nuxeo.ecm.core.api.DocumentNotFoundException;
035import org.nuxeo.ecm.core.api.DocumentRef;
036import org.nuxeo.ecm.core.api.IdRef;
037import org.nuxeo.ecm.core.api.NuxeoException;
038import org.nuxeo.ecm.core.api.NuxeoPrincipal;
039import org.nuxeo.ecm.core.api.PathRef;
040import org.nuxeo.ecm.core.api.SortInfo;
041import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
042import org.nuxeo.ecm.core.api.security.ACE;
043import org.nuxeo.ecm.core.api.security.ACL;
044import org.nuxeo.ecm.core.api.security.ACP;
045import org.nuxeo.ecm.core.api.security.SecurityConstants;
046import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
047import org.nuxeo.ecm.platform.task.Task;
048import org.nuxeo.ecm.platform.task.TaskConstants;
049import org.nuxeo.ecm.platform.task.TaskEventNames;
050import org.nuxeo.ecm.platform.task.TaskPersisterDescriptor;
051import org.nuxeo.ecm.platform.task.TaskProvider;
052import org.nuxeo.ecm.platform.task.TaskProviderDescriptor;
053import org.nuxeo.ecm.platform.task.TaskService;
054import org.nuxeo.runtime.model.ComponentContext;
055import org.nuxeo.runtime.model.ComponentInstance;
056import org.nuxeo.runtime.model.ComponentName;
057import org.nuxeo.runtime.model.DefaultComponent;
058
059/**
060 * @author <a href="mailto:ldoguin@nuxeo.com">Laurent Doguin</a>
061 * @since 5.5
062 */
063public class TaskServiceImpl extends DefaultComponent implements TaskService {
064
065    private static final long serialVersionUID = 1L;
066
067    public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.platform.task.core.TaskService");
068
069    public static final String DEFAULT_TASK_PROVIDER = "documentTaskProvider";
070
071    private static final String TASK_PROVIDER_XP = "taskProvider";
072
073    private static final String TASK_PERSISTER_XP = "taskPersister";
074
075    private Map<String, TaskProvider> tasksProviders;
076
077    private String parentPath = "/task-root";
078
079    @Override
080    public void activate(ComponentContext context) {
081        super.activate(context);
082        tasksProviders = new HashMap<String, TaskProvider>();
083    }
084
085    @Override
086    public void deactivate(ComponentContext context) {
087        super.deactivate(context);
088        tasksProviders = null;
089    }
090
091    @Override
092    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
093        if (extensionPoint.equals(TASK_PROVIDER_XP)) {
094            if (contribution instanceof TaskProviderDescriptor) {
095                TaskProviderDescriptor taskProviderDescriptor = (TaskProviderDescriptor) contribution;
096                String providerId = taskProviderDescriptor.getId();
097                if (taskProviderDescriptor.isEnabled()) {
098                    tasksProviders.put(providerId, taskProviderDescriptor.getNewInstance());
099                } else {
100                    if (tasksProviders.get(providerId) != null) {
101                        tasksProviders.remove(providerId);
102                    }
103                }
104            }
105        } else if (extensionPoint.equals(TASK_PERSISTER_XP)) {
106            if (contribution instanceof TaskPersisterDescriptor) {
107                TaskPersisterDescriptor taskPersisterDescriptor = (TaskPersisterDescriptor) contribution;
108                parentPath = taskPersisterDescriptor.getPath();
109            }
110        }
111    }
112
113    @Override
114    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
115        if (extensionPoint.equals(TASK_PROVIDER_XP)) {
116            if (contribution instanceof TaskProviderDescriptor) {
117                TaskProviderDescriptor taskProviderDescriptor = (TaskProviderDescriptor) contribution;
118                String providerId = taskProviderDescriptor.getId();
119                if (tasksProviders.get(providerId) != null) {
120                    tasksProviders.remove(providerId);
121                }
122            }
123        }
124    }
125
126    @Override
127    public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document,
128            String taskName, List<String> actorIds, boolean createOneTaskPerActor, String directive, String comment,
129            Date dueDate, Map<String, String> taskVariables, String parentPath) {
130        return createTask(coreSession, principal, document, taskName, null, null, actorIds, createOneTaskPerActor,
131                directive, comment, dueDate, taskVariables, parentPath);
132    }
133
134    /**
135     * @since 5.6
136     */
137    @Override
138    public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document,
139            String taskDocumentType, String taskName, String taskType, String processId, List<String> actorIds,
140            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
141            Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo)
142            {
143        List<DocumentModel> docs = new ArrayList<DocumentModel>();
144        docs.add(document);
145        return createTask(coreSession, principal, docs, taskDocumentType, taskName, taskType, processId, actorIds,
146                createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath, eventInfo);
147    }
148
149    /**
150     * @since 5.6
151     */
152    @Override
153    public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document,
154            String taskName, String taskType, String processId, List<String> prefixedActorIds,
155            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
156            Map<String, String> taskVariables, String parentPath) {
157        return createTask(coreSession, principal, document, TaskConstants.TASK_TYPE_NAME, taskName, taskType,
158                processId, prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables,
159                parentPath, null);
160    }
161
162    @Override
163    public String acceptTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment)
164            {
165        return endTask(coreSession, principal, task, comment, TaskEventNames.WORKFLOW_TASK_COMPLETED, true);
166    }
167
168    @Override
169    public String rejectTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment)
170            {
171        return endTask(coreSession, principal, task, comment, TaskEventNames.WORKFLOW_TASK_REJECTED, false);
172    }
173
174    /**
175     * Use the task provider held by the {@link Task#TASK_PROVIDER_KEY} task variable to end the {@code task}. If null
176     * use the {@link #DEFAULT_TASK_PROVIDER}.
177     */
178    @Override
179    public String endTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment,
180            String eventName, boolean isValidated) {
181
182        if (!canEndTask(principal, task)) {
183            throw new NuxeoException(String.format("User with id '%s' cannot end this task", principal.getName()));
184        }
185        String taskProviderId = task.getVariable(Task.TASK_PROVIDER_KEY);
186        if (taskProviderId == null) {
187            taskProviderId = DEFAULT_TASK_PROVIDER;
188        }
189        TaskProvider taskProvider = tasksProviders.get(taskProviderId);
190        if (taskProvider == null) {
191            throw new NuxeoException(
192                    String.format(
193                            "No task provider registered, cannot end task. Please contribute at least the default task provider: %s.",
194                            DEFAULT_TASK_PROVIDER));
195        }
196        return taskProvider.endTask(coreSession, principal, task, comment, eventName, isValidated);
197    }
198
199    @Override
200    public boolean canEndTask(NuxeoPrincipal principal, Task task) {
201        if (task != null && (!task.isCancelled() && !task.hasEnded())) {
202            return principal.isAdministrator() || principal.getName().equals(task.getInitiator())
203                    || isTaskAssignedToUser(task, principal, true);
204        }
205        return false;
206    }
207
208    protected boolean isTaskAssignedToUser(Task task, NuxeoPrincipal user, boolean checkDelegatedActors)
209            {
210        if (task != null && user != null) {
211            // user actors
212            List<String> actors = user.getAllGroups();
213            actors.add(user.getName());
214
215            // initiator
216            if (actors.contains(task.getInitiator())) {
217                return true;
218            }
219            // users
220            List<String> users = task.getActors();
221            if (checkDelegatedActors) {
222                users.addAll(task.getDelegatedActors());
223            }
224            if (users != null) {
225                for (String userName : users) {
226                    if (userName.contains(":")) {
227                        if (actors.contains(userName.split(":")[1])) {
228                            return true;
229                        }
230                    }
231                    if (actors.contains(userName)) {
232                        return true;
233                    }
234                }
235            }
236        }
237        return false;
238    }
239
240    @Override
241    public Task getTask(CoreSession coreSession, String taskId) {
242        DocumentRef docRef = new IdRef(taskId);
243        DocumentModel taskDoc = coreSession.getDocument(docRef);
244        if (taskDoc != null) {
245            Task task = taskDoc.getAdapter(Task.class);
246            if (task != null) {
247                return task;
248            }
249        }
250        return null;
251    }
252
253    @Override
254    public void deleteTask(CoreSession coreSession, String taskId) {
255        final DocumentRef docRef = new IdRef(taskId);
256        UnrestrictedSessionRunner runner = new UnrestrictedSessionRunner(coreSession) {
257            @Override
258            public void run() {
259                session.removeDocument(docRef);
260            }
261        };
262        runner.runUnrestricted();
263    }
264
265    @Override
266    public DocumentModel getTargetDocumentModel(Task task, CoreSession coreSession) {
267        try {
268            return coreSession.getDocument(new IdRef(task.getTargetDocumentId()));
269        } catch (DocumentNotFoundException e) {
270            return null;
271        }
272    }
273
274    @Override
275    public List<Task> getCurrentTaskInstances(CoreSession coreSession) {
276        List<Task> tasks = new ArrayList<Task>();
277        List<Task> newTasks;
278        for (TaskProvider taskProvider : tasksProviders.values()) {
279            newTasks = taskProvider.getCurrentTaskInstances(coreSession);
280            if (newTasks != null) {
281                tasks.addAll(newTasks);
282            }
283        }
284        return tasks;
285    }
286
287    /**
288     * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances})
289     *
290     * @since 5.9.3
291     */
292    @Override
293    public List<Task> getCurrentTaskInstances(CoreSession coreSession, List<SortInfo> sortInfos) {
294        List<Task> tasks = new ArrayList<Task>();
295        List<Task> newTasks;
296        for (TaskProvider taskProvider : tasksProviders.values()) {
297            newTasks = taskProvider.getCurrentTaskInstances(coreSession, sortInfos);
298            if (newTasks != null) {
299                tasks.addAll(newTasks);
300            }
301        }
302        return tasks;
303    }
304
305    @Override
306    public List<Task> getAllCurrentTaskInstances(CoreSession coreSession, List<SortInfo> sortInfos) {
307        List<Task> tasks = new ArrayList<Task>();
308        List<Task> newTasks;
309        for (TaskProvider taskProvider : tasksProviders.values()) {
310            newTasks = taskProvider.getAllCurrentTaskInstances(coreSession,
311                    sortInfos);
312            if (newTasks != null) {
313                tasks.addAll(newTasks);
314            }
315        }
316        return tasks;
317    }
318
319    /**
320     * Returns a list of task instances assigned to one of the actors in the list or to its pool.
321     *
322     * @param actors a list used as actorId to retrieve the tasks.
323     * @return
324     */
325    @Override
326    public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession) {
327        List<Task> tasks = new ArrayList<Task>();
328        List<Task> newTasks;
329        for (TaskProvider taskProvider : tasksProviders.values()) {
330            newTasks = taskProvider.getCurrentTaskInstances(actors, coreSession);
331            if (newTasks != null) {
332                tasks.addAll(newTasks);
333            }
334        }
335        return tasks;
336    }
337
338    /**
339     * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances})
340     *
341     * @since 5.9.3
342     */
343    @Override
344    public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession, List<SortInfo> sortInfos)
345            {
346        List<Task> tasks = new ArrayList<Task>();
347        List<Task> newTasks;
348        for (TaskProvider taskProvider : tasksProviders.values()) {
349            newTasks = taskProvider.getCurrentTaskInstances(actors, coreSession, sortInfos);
350            if (newTasks != null) {
351                tasks.addAll(newTasks);
352            }
353        }
354        return tasks;
355    }
356
357    @Override
358    public List<Task> getTaskInstances(DocumentModel dm, NuxeoPrincipal user, CoreSession coreSession)
359            {
360        List<Task> tasks = new ArrayList<Task>();
361        List<Task> newTasks;
362        for (TaskProvider taskProvider : tasksProviders.values()) {
363            newTasks = taskProvider.getTaskInstances(dm, user, coreSession);
364            if (newTasks != null) {
365                tasks.addAll(newTasks);
366            }
367        }
368        return tasks;
369    }
370
371    @Override
372    public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, CoreSession coreSession)
373            {
374        List<Task> tasks = new ArrayList<Task>();
375        List<Task> newTasks;
376        for (TaskProvider taskProvider : tasksProviders.values()) {
377            newTasks = taskProvider.getTaskInstances(dm, actors, coreSession);
378            if (newTasks != null) {
379                tasks.addAll(newTasks);
380            }
381        }
382        return tasks;
383    }
384
385    @Override
386    public List<Task> getAllTaskInstances(String processId, CoreSession session) {
387        List<Task> tasks = new ArrayList<Task>();
388        List<Task> newTasks;
389        for (TaskProvider taskProvider : tasksProviders.values()) {
390            newTasks = taskProvider.getAllTaskInstances(processId, session);
391            if (newTasks != null) {
392                tasks.addAll(newTasks);
393            }
394        }
395        return tasks;
396    }
397
398    @Override
399    public List<Task> getAllTaskInstances(String processId, NuxeoPrincipal user, CoreSession session)
400            {
401        List<Task> tasks = new ArrayList<Task>();
402        List<Task> newTasks;
403        for (TaskProvider taskProvider : tasksProviders.values()) {
404            newTasks = taskProvider.getAllTaskInstances(processId, user, session);
405            if (newTasks != null) {
406                tasks.addAll(newTasks);
407            }
408        }
409        return tasks;
410    }
411
412    @Override
413    public List<Task> getAllTaskInstances(String processId, List<String> actors, CoreSession session)
414            {
415        List<Task> tasks = new ArrayList<Task>();
416        List<Task> newTasks;
417        for (TaskProvider taskProvider : tasksProviders.values()) {
418            newTasks = taskProvider.getAllTaskInstances(processId, actors, session);
419            if (newTasks != null) {
420                tasks.addAll(newTasks);
421            }
422        }
423        return tasks;
424    }
425
426    /**
427     * @deprecated since 5.6
428     */
429    @Deprecated
430    protected List<Task> wrapDocModelInTask(DocumentModelList taskDocuments) {
431        List<Task> tasks = new ArrayList<Task>();
432        for (DocumentModel doc : taskDocuments) {
433            tasks.add(doc.getAdapter(Task.class));
434        }
435        return tasks;
436    }
437
438    @Override
439    public String getTaskRootParentPath(CoreSession coreSession) {
440        GetTaskRootParentPathUnrestricted runner = new GetTaskRootParentPathUnrestricted(coreSession);
441        runner.runUnrestricted();
442        return runner.getParentPath();
443    }
444
445    public class GetTaskRootParentPathUnrestricted extends UnrestrictedSessionRunner {
446
447        protected DocumentModel taskRootDoc;
448
449        public GetTaskRootParentPathUnrestricted(CoreSession session) {
450            super(session);
451        }
452
453        @Override
454        public void run() {
455            DocumentRef pathRef = new PathRef(parentPath);
456            if (session.exists(pathRef)) {
457                taskRootDoc = session.getDocument(pathRef);
458            } else {
459                Path path = new Path(parentPath);
460                taskRootDoc = session.createDocumentModel(path.removeLastSegments(1).toString(), path.lastSegment(),
461                        TaskConstants.TASK_ROOT_TYPE_NAME);
462                taskRootDoc = session.createDocument(taskRootDoc);
463                ACP acp = taskRootDoc.getACP();
464                ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL);
465                acl.add(new ACE("Everyone", "Everything", false));
466                taskRootDoc.setACP(acp, true);
467                taskRootDoc = session.saveDocument(taskRootDoc);
468            }
469        }
470
471        public DocumentModel getTaskRootDoc() {
472            return taskRootDoc;
473        }
474
475        public String getParentPath() {
476            return taskRootDoc.getPathAsString();
477        }
478    }
479
480    @Override
481    public List<Task> getAllTaskInstances(String processId, String nodeId, CoreSession session) {
482        List<Task> tasks = new ArrayList<Task>();
483        List<Task> newTasks;
484        for (TaskProvider taskProvider : tasksProviders.values()) {
485            newTasks = taskProvider.getAllTaskInstances(processId, nodeId, session);
486            if (newTasks != null) {
487                tasks.addAll(newTasks);
488            }
489        }
490        return tasks;
491    }
492
493    @Override
494    public void reassignTask(CoreSession session, final String taskId, final List<String> newActors,
495            final String comment) {
496
497        new UnrestrictedSessionRunner(session) {
498
499            @Override
500            public void run() {
501                DocumentModel taskDoc = session.getDocument(new IdRef(taskId));
502                Task task = taskDoc.getAdapter(Task.class);
503                if (task == null) {
504                    throw new NuxeoException("Invalid taskId: " + taskId);
505                }
506                List<String> currentAssignees = task.getActors();
507                List<String> currentActors = new ArrayList<String>();
508                for (String currentAssignee : currentAssignees) {
509                    if (currentAssignee.startsWith(NotificationConstants.GROUP_PREFIX)
510                            || currentAssignee.startsWith(NotificationConstants.USER_PREFIX)) {
511                        // prefixed assignees with "user:" or "group:"
512                        currentActors.add(currentAssignee.substring(currentAssignee.indexOf(":") + 1));
513                    } else {
514                        currentActors.add(currentAssignee);
515                    }
516                }
517                String taskInitator = task.getInitiator();
518
519                // remove ACLs set for current assignees
520                ACP acp = taskDoc.getACP();
521                ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL);
522                List<ACE> toRemove = new ArrayList<ACE>();
523
524                for (ACE ace : acl.getACEs()) {
525                    if (currentActors.contains(ace.getUsername()) || taskInitator.equals(ace.getUsername())) {
526                        toRemove.add(ace);
527                    }
528                }
529                acl.removeAll(toRemove);
530
531                // grant EVERYTHING on task doc to the new actors
532                List<String> actorIds = new ArrayList<String>();
533                for (String actor : newActors) {
534                    if (actor.startsWith(NotificationConstants.GROUP_PREFIX)
535                            || actor.startsWith(NotificationConstants.USER_PREFIX)) {
536                        // prefixed assignees with "user:" or "group:"
537                        actorIds.add(actor.substring(actor.indexOf(":") + 1));
538                    } else {
539                        actorIds.add(actor);
540                    }
541                }
542                for (String actorId : actorIds) {
543                    acl.add(new ACE(actorId, SecurityConstants.EVERYTHING, true));
544                }
545
546                taskDoc.setACP(acp, true);
547                task.setActors(actorIds);
548                String currentUser = ((NuxeoPrincipal) session.getPrincipal()).getActingUser();
549                task.addComment(currentUser, comment);
550                session.saveDocument(taskDoc);
551
552                List<DocumentModel> docs = new ArrayList<DocumentModel>();
553                for (String string : task.getTargetDocumentsIds()) {
554                    docs.add(session.getDocument(new IdRef(string)));
555
556                }
557                notifyEvent(session, task, docs, TaskEventNames.WORKFLOW_TASK_REASSIGNED,
558                        new HashMap<String, Serializable>(), comment, (NuxeoPrincipal) session.getPrincipal(), actorIds);
559
560            }
561        }.runUnrestricted();
562
563    }
564
565    @Override
566    public void delegateTask(CoreSession session, final String taskId, final List<String> delegatedActors,
567            final String comment) {
568
569        new UnrestrictedSessionRunner(session) {
570            @Override
571            public void run() {
572                DocumentModel taskDoc = session.getDocument(new IdRef(taskId));
573                Task task = taskDoc.getAdapter(Task.class);
574                if (task == null) {
575                    throw new NuxeoException("Invalid taskId: " + taskId);
576                }
577                // grant EVERYTHING on task doc to the delegated actors
578                List<String> actorIds = new ArrayList<String>();
579                ACP acp = taskDoc.getACP();
580                ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL);
581
582                for (String actor : delegatedActors) {
583                    if (actor.startsWith(NotificationConstants.GROUP_PREFIX)
584                            || actor.startsWith(NotificationConstants.USER_PREFIX)) {
585                        // prefixed assignees with "user:" or "group:"
586                        actorIds.add(actor.substring(actor.indexOf(":") + 1));
587                    } else {
588                        actorIds.add(actor);
589                    }
590                }
591                for (String actorId : actorIds) {
592                    ACE ace = new ACE(actorId, SecurityConstants.EVERYTHING, true);
593                    if (!acl.contains(ace)) {
594                        acl.add(ace);
595                    }
596                }
597                taskDoc.setACP(acp, true);
598
599                List<String> allDelegatedActors = new ArrayList<String>();
600                allDelegatedActors.addAll(task.getDelegatedActors());
601                for (String actor : actorIds) {
602                    if (!allDelegatedActors.contains(actor)) {
603                        allDelegatedActors.add(actor);
604                    }
605                }
606                task.setDelegatedActors(allDelegatedActors);
607
608                String currentUser = ((NuxeoPrincipal) session.getPrincipal()).getActingUser();
609                task.addComment(currentUser, comment);
610                session.saveDocument(taskDoc);
611                List<DocumentModel> docs = new ArrayList<DocumentModel>();
612                for (String string : task.getTargetDocumentsIds()) {
613                    docs.add(session.getDocument(new IdRef(string)));
614
615                }
616                notifyEvent(session, task, docs, TaskEventNames.WORKFLOW_TASK_DELEGATED,
617                        new HashMap<String, Serializable>(),
618                        String.format("Task delegated by '%s' to '%s'", currentUser, StringUtils.join(actorIds, ","))
619                                + (!StringUtils.isEmpty(comment) ? " with the following comment: " + comment : ""),
620                        (NuxeoPrincipal) session.getPrincipal(), actorIds);
621            }
622
623        }.runUnrestricted();
624    }
625
626    protected void notifyEvent(CoreSession session, Task task, List<DocumentModel> docs, String event,
627            Map<String, Serializable> eventInfo, String comment, NuxeoPrincipal principal, List<String> actorIds)
628            {
629        Map<String, Serializable> eventProperties = new HashMap<String, Serializable>();
630        ArrayList<String> notificationRecipients = new ArrayList<String>();
631        notificationRecipients.addAll(actorIds);
632        eventProperties.put(NotificationConstants.RECIPIENTS_KEY,
633                notificationRecipients.toArray(new String[notificationRecipients.size()]));
634        if (eventInfo != null) {
635            eventProperties.putAll(eventInfo);
636        }
637        for (DocumentModel doc : docs) {
638            TaskEventNotificationHelper.notifyEvent(session, doc, principal, task, event, eventProperties, comment,
639                    null);
640        }
641    }
642
643    @Override
644    public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, boolean includeDelegatedTasks,
645            CoreSession session) {
646        List<Task> tasks = new ArrayList<Task>();
647        for (TaskProvider taskProvider : tasksProviders.values()) {
648            tasks.addAll(taskProvider.getTaskInstances(dm, actors, includeDelegatedTasks, session));
649        }
650        return tasks;
651    }
652
653    /**
654     * @since 5.8
655     * @deprecated since 7.4 use
656     *             {@link #org.nuxeo.ecm.platform.task.core.service.TaskServiceImpl.createTaskWithProcessName(CoreSession,
657     *             NuxeoPrincipal, List<DocumentModel>, String, String, String, String, String, List<String>, boolean,
658     *             String, String, Date, Map<String, String>, String, Map<String, Serializable>)
659     *             createTaskWithProcessName} instead
660     */
661    @Override
662    @Deprecated
663    public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, List<DocumentModel> documents,
664            String taskDocumentType, String taskName, String taskType, String processId, List<String> actorIds,
665            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
666            Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo) {
667        return createTaskForProcess(coreSession, principal, documents, taskDocumentType, taskName, taskType, processId,
668                null, actorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath,
669                eventInfo);
670    }
671
672    /**
673     * @since 7.4
674     */
675    @Override
676    public List<Task> createTaskForProcess(CoreSession coreSession, NuxeoPrincipal principal, List<DocumentModel> documents,
677            String taskDocumentType, String taskName, String taskType, String processId, String processName, List<String> actorIds,
678            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
679            Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo)
680            {
681        if (StringUtils.isBlank(parentPath)) {
682            parentPath = getTaskRootParentPath(coreSession);
683        }
684        CreateTaskUnrestricted runner = new CreateTaskUnrestricted(coreSession, principal, documents, taskDocumentType,
685                taskName, taskType, processId, processName, actorIds, createOneTaskPerActor, directive, comment,
686                dueDate, taskVariables, parentPath);
687        runner.runUnrestricted();
688
689        List<Task> tasks = runner.getTasks();
690
691        for (Task task : tasks) {
692            // notify
693            notifyEvent(coreSession, task, documents, TaskEventNames.WORKFLOW_TASK_ASSIGNED, eventInfo, comment,
694                    principal, task.getActors());
695        }
696        return tasks;
697    }
698}