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.SESSION_ID, coreSession.getSessionId());
071            properties.put(CoreEventConstants.DOC_LIFE_CYCLE, document.getCurrentLifeCycleState());
072            eventContext = new DocumentEventContext(coreSession, principal, document);
073        } else {
074            eventContext = new EventContextImpl(coreSession, principal);
075        }
076        properties.put(DocumentEventContext.COMMENT_PROPERTY_KEY, comment);
077        properties.put(DocumentEventContext.CATEGORY_PROPERTY_KEY, category);
078        properties.put(TaskService.TASK_INSTANCE_EVENT_PROPERTIES_KEY, task);
079        String disableNotif = task.getVariable(TaskEventNames.DISABLE_NOTIFICATION_SERVICE);
080        if (disableNotif != null && Boolean.TRUE.equals(Boolean.valueOf(disableNotif))) {
081            properties.put(TaskEventNames.DISABLE_NOTIFICATION_SERVICE, Boolean.TRUE);
082        }
083        eventContext.setProperties(properties);
084
085        Event event = eventContext.newEvent(eventId);
086        getEventProducer().fireEvent(event);
087    }
088
089    /**
090     * @since 7.2
091     */
092    public static void notifyTaskEnded(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment,
093            String eventName, Map<String, Serializable> extraEventProperties) {
094
095        // try to resolve document when notifying
096        DocumentModel document;
097
098        List<String> docIds = new ArrayList<>();
099        docIds.addAll(task.getTargetDocumentsIds());
100        // also handle compatibility with deprecated jbpm tasks
101        String docIdVar = task.getVariable(TaskService.VariableName.documentId.name());
102        if (!docIds.contains(docIdVar)) {
103            docIds.add(docIdVar);
104        }
105        String docRepo = task.getVariable(TaskService.VariableName.documentRepositoryName.name());
106        List<DocumentModel> documents = new ArrayList<>();
107        if (coreSession.getRepositoryName().equals(docRepo)) {
108            try {
109                for (String id : docIds) {
110                    document = coreSession.getDocument(new IdRef(id));
111                    documents.add(document);
112                }
113            } catch (DocumentNotFoundException e) {
114                log.error(String.format("Could not fetch document with id '%s:(%s)' for notification", docRepo, docIds),
115                        e);
116            }
117        } else {
118            log.error(String.format(
119                    "Could not resolve document for notification: "
120                            + "document is on repository '%s' and given session is on " + "repository '%s'",
121                    docRepo, coreSession.getRepositoryName()));
122        }
123
124        final Map<String, Serializable> eventProperties = new HashMap<>();
125        ArrayList<String> notificationRecipients = new ArrayList<>();
126        notificationRecipients.add(task.getInitiator());
127        notificationRecipients.addAll(task.getActors());
128        eventProperties.put(NotificationConstants.RECIPIENTS_KEY, notificationRecipients);
129        if (extraEventProperties != null) {
130            eventProperties.putAll(extraEventProperties);
131        }
132        boolean taskEndedByDelegatedActor = task.getDelegatedActors() != null
133                && task.getDelegatedActors().contains(principal.getName());
134        for (DocumentModel doc : documents) {
135            notifyEvent(coreSession, doc, principal, task, eventName, eventProperties, comment, null);
136            if (taskEndedByDelegatedActor) {
137                notifyEvent(coreSession, doc, principal, task, eventName, eventProperties,
138                        String.format("Task ended by an delegated actor '%s' ", principal.getName())
139                                + (!StringUtils.isEmpty(comment) ? " with the following comment: " + comment : ""),
140                        null);
141            }
142        }
143    }
144
145    public static EventProducer getEventProducer() {
146        return Framework.getService(EventProducer.class);
147    }
148}