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