001/*
002 * (C) Copyright 2012-2016 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 *     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.lang.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,
058            Task task, String eventId, Map<String, Serializable> properties, String comment, String category)
059            {
060        // Default category
061        if (category == null) {
062            category = DocumentEventCategories.EVENT_DOCUMENT_CATEGORY;
063        }
064        if (properties == null) {
065            properties = new HashMap<>();
066        }
067
068        EventContext eventContext;
069        if (document != null) {
070            properties.put(CoreEventConstants.REPOSITORY_NAME, document.getRepositoryName());
071            properties.put(CoreEventConstants.SESSION_ID, coreSession.getSessionId());
072            properties.put(CoreEventConstants.DOC_LIFE_CYCLE, document.getCurrentLifeCycleState());
073            eventContext = new DocumentEventContext(coreSession, principal, document);
074        } else {
075            eventContext = new EventContextImpl(coreSession, principal);
076        }
077        properties.put(DocumentEventContext.COMMENT_PROPERTY_KEY, comment);
078        properties.put(DocumentEventContext.CATEGORY_PROPERTY_KEY, category);
079        properties.put(TaskService.TASK_INSTANCE_EVENT_PROPERTIES_KEY, task);
080        String disableNotif = task.getVariable(TaskEventNames.DISABLE_NOTIFICATION_SERVICE);
081        if (disableNotif != null && Boolean.TRUE.equals(Boolean.valueOf(disableNotif))) {
082            properties.put(TaskEventNames.DISABLE_NOTIFICATION_SERVICE, Boolean.TRUE);
083        }
084        eventContext.setProperties(properties);
085
086        Event event = eventContext.newEvent(eventId);
087        getEventProducer().fireEvent(event);
088    }
089
090    /**
091     * @since 7.2
092     */
093    public static void notifyTaskEnded(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment,
094            String eventName, Map<String, Serializable> extraEventProperties) {
095
096        // try to resolve document when notifying
097        DocumentModel document;
098
099        List<String> docIds = new ArrayList<>();
100        docIds.addAll(task.getTargetDocumentsIds());
101        // also handle compatibility with deprecated jbpm tasks
102        String docIdVar = task.getVariable(TaskService.VariableName.documentId.name());
103        if (!docIds.contains(docIdVar)) {
104            docIds.add(docIdVar);
105        }
106        String docRepo = task.getVariable(TaskService.VariableName.documentRepositoryName.name());
107        List<DocumentModel> documents = new ArrayList<>();
108        if (coreSession.getRepositoryName().equals(docRepo)) {
109            try {
110                for (String id : docIds) {
111                    document = coreSession.getDocument(new IdRef(id));
112                    documents.add(document);
113                }
114            } catch (DocumentNotFoundException e) {
115                log.error(String.format("Could not fetch document with id '%s:(%s)' for notification", docRepo, docIds), e);
116            }
117        } else {
118            log.error(String.format("Could not resolve document for notification: "
119                    + "document is on repository '%s' and given session is on " + "repository '%s'", docRepo,
120                    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,
135                    comment, null);
136            if (taskEndedByDelegatedActor) {
137                notifyEvent(
138                        coreSession,
139                        doc,
140                        principal,
141                        task,
142                        eventName,
143                        eventProperties,
144                        String.format("Task ended by an delegated actor '%s' ", principal.getName())
145                                + (!StringUtils.isEmpty(comment) ? " with the following comment: " + comment : ""),
146                        null);
147            }
148        }
149    }
150
151    public static EventProducer getEventProducer() {
152        return Framework.getService(EventProducer.class);
153    }
154}