001/*
002 * (C) Copyright 2012-2018 Nuxeo (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 *     Antoine Taillefer
018 */
019package org.nuxeo.ecm.platform.task.core.service;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.core.api.CoreSession;
031import org.nuxeo.ecm.core.api.DocumentModel;
032import org.nuxeo.ecm.core.api.DocumentNotFoundException;
033import org.nuxeo.ecm.core.api.IdRef;
034import org.nuxeo.ecm.core.api.NuxeoPrincipal;
035import org.nuxeo.ecm.core.api.event.CoreEventConstants;
036import org.nuxeo.ecm.core.api.event.DocumentEventCategories;
037import org.nuxeo.ecm.core.event.Event;
038import org.nuxeo.ecm.core.event.EventContext;
039import org.nuxeo.ecm.core.event.EventProducer;
040import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
041import org.nuxeo.ecm.core.event.impl.EventContextImpl;
042import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
043import org.nuxeo.ecm.platform.task.Task;
044import org.nuxeo.ecm.platform.task.TaskEventNames;
045import org.nuxeo.ecm.platform.task.TaskService;
046import org.nuxeo.runtime.api.Framework;
047
048/**
049 * Helper for notifying task related events.
050 *
051 * @since 5.6
052 */
053public final class TaskEventNotificationHelper {
054
055    private final static Log log = LogFactory.getLog(TaskEventNotificationHelper.class);
056
057    public static void notifyEvent(CoreSession coreSession, DocumentModel document, NuxeoPrincipal principal, Task task,
058            String eventId, Map<String, Serializable> properties, String comment, String category) {
059        // Default category
060        if (category == null) {
061            category = DocumentEventCategories.EVENT_DOCUMENT_CATEGORY;
062        }
063        if (properties == null) {
064            properties = new HashMap<>();
065        }
066
067        EventContext eventContext;
068        if (document != null) {
069            properties.put(CoreEventConstants.REPOSITORY_NAME, document.getRepositoryName());
070            properties.put(CoreEventConstants.DOC_LIFE_CYCLE, document.getCurrentLifeCycleState());
071            eventContext = new DocumentEventContext(coreSession, principal, document);
072        } else {
073            eventContext = new EventContextImpl(coreSession, principal);
074        }
075        properties.put(DocumentEventContext.COMMENT_PROPERTY_KEY, comment);
076        properties.put(DocumentEventContext.CATEGORY_PROPERTY_KEY, category);
077        properties.put(TaskService.TASK_INSTANCE_EVENT_PROPERTIES_KEY, task);
078        String disableNotif = task.getVariable(TaskEventNames.DISABLE_NOTIFICATION_SERVICE);
079        if (disableNotif != null && Boolean.TRUE.equals(Boolean.valueOf(disableNotif))) {
080            properties.put(TaskEventNames.DISABLE_NOTIFICATION_SERVICE, Boolean.TRUE);
081        }
082        eventContext.setProperties(properties);
083
084        Event event = eventContext.newEvent(eventId);
085        getEventProducer().fireEvent(event);
086    }
087
088    /**
089     * @since 7.2
090     */
091    public static void notifyTaskEnded(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment,
092            String eventName, Map<String, Serializable> extraEventProperties) {
093
094        // try to resolve document when notifying
095        DocumentModel document;
096
097        List<String> docIds = new ArrayList<>();
098        docIds.addAll(task.getTargetDocumentsIds());
099        // also handle compatibility with deprecated jbpm tasks
100        String docIdVar = task.getVariable(TaskService.VariableName.documentId.name());
101        if (!docIds.contains(docIdVar)) {
102            docIds.add(docIdVar);
103        }
104        String docRepo = task.getVariable(TaskService.VariableName.documentRepositoryName.name());
105        List<DocumentModel> documents = new ArrayList<>();
106        if (coreSession.getRepositoryName().equals(docRepo)) {
107            try {
108                for (String id : docIds) {
109                    document = coreSession.getDocument(new IdRef(id));
110                    documents.add(document);
111                }
112            } catch (DocumentNotFoundException e) {
113                log.error(String.format("Could not fetch document with id '%s:(%s)' for notification", docRepo, docIds),
114                        e);
115            }
116        } else {
117            log.error(String.format(
118                    "Could not resolve document for notification: "
119                            + "document is on repository '%s' and given session is on " + "repository '%s'",
120                    docRepo, coreSession.getRepositoryName()));
121        }
122
123        final Map<String, Serializable> eventProperties = new HashMap<>();
124        ArrayList<String> notificationRecipients = new ArrayList<>();
125        notificationRecipients.add(task.getInitiator());
126        notificationRecipients.addAll(task.getActors());
127        eventProperties.put(NotificationConstants.RECIPIENTS_KEY, notificationRecipients);
128        if (extraEventProperties != null) {
129            eventProperties.putAll(extraEventProperties);
130        }
131        boolean taskEndedByDelegatedActor = task.getDelegatedActors() != null
132                && task.getDelegatedActors().contains(principal.getName());
133        for (DocumentModel doc : documents) {
134            notifyEvent(coreSession, doc, principal, task, eventName, eventProperties, comment, null);
135            if (taskEndedByDelegatedActor) {
136                notifyEvent(coreSession, doc, principal, task, eventName, eventProperties,
137                        String.format("Task ended by an delegated actor '%s' ", principal.getName())
138                                + (!StringUtils.isEmpty(comment) ? " with the following comment: " + comment : ""),
139                        null);
140            }
141        }
142    }
143
144    public static EventProducer getEventProducer() {
145        return Framework.getService(EventProducer.class);
146    }
147}