001/* 002 * (C) Copyright 2010-2011 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 016 */ 017 018package org.nuxeo.ecm.platform.routing.dm.operation; 019 020import java.security.Principal; 021import java.util.ArrayList; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.commons.lang.StringUtils; 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import org.nuxeo.ecm.automation.OperationContext; 030import org.nuxeo.ecm.automation.OperationException; 031import org.nuxeo.ecm.automation.core.Constants; 032import org.nuxeo.ecm.automation.core.annotations.Context; 033import org.nuxeo.ecm.automation.core.annotations.Operation; 034import org.nuxeo.ecm.automation.core.annotations.OperationMethod; 035import org.nuxeo.ecm.automation.core.annotations.Param; 036import org.nuxeo.ecm.automation.core.collectors.DocumentModelCollector; 037import org.nuxeo.ecm.automation.core.util.Properties; 038import org.nuxeo.ecm.automation.core.util.StringList; 039import org.nuxeo.ecm.core.api.CoreSession; 040import org.nuxeo.ecm.core.api.DocumentModel; 041import org.nuxeo.ecm.core.api.DocumentModelList; 042import org.nuxeo.ecm.core.api.NuxeoPrincipal; 043import org.nuxeo.ecm.core.api.PropertyException; 044import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 045import org.nuxeo.ecm.platform.routing.api.DocumentRouteStep; 046import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants; 047import org.nuxeo.ecm.platform.routing.api.DocumentRoutingService; 048import org.nuxeo.ecm.platform.routing.dm.adapter.TaskStep; 049import org.nuxeo.ecm.platform.routing.dm.api.RoutingTaskConstants; 050import org.nuxeo.ecm.platform.task.Task; 051import org.nuxeo.ecm.platform.task.TaskEventNames; 052import org.nuxeo.ecm.platform.task.TaskService; 053import org.nuxeo.ecm.platform.usermanager.UserManager; 054 055/** 056 * Creates a routing task 057 * 058 * @author ldoguin 059 * @since 5.6 060 * @deprecated since 5.9.2 - Use only routes of type 'graph' 061 */ 062@Deprecated 063@Operation(id = CreateRoutingTask.ID, category = Constants.CAT_SERVICES, label = "Create task", since = "5.6", description = "Enable to create a routingTask bound to a route and its document. " 064 + "In <b>accept operation chain</b> and <b>reject operation chain</b> fields, " 065 + "you can put the operation chain ID of your choice among the one you contributed. " 066 + "Those operations will be executed when the user validates the task, " 067 + "depending on whether he accepts or rejects the task. " 068 + "Extra (String) properties can be set on the taskVariables from the input document or from the step.", addToStudio = false) 069public class CreateRoutingTask { 070 071 public static final String ID = "Workflow.CreateRoutingTask"; 072 073 private static final Log log = LogFactory.getLog(CreateRoutingTask.class); 074 075 public enum OperationTaskVariableName { 076 acceptOperationChain, rejectOperationChain, createdFromCreateTaskOperation, taskDocuments 077 } 078 079 public static final String STEP_PREFIX = "StepTask:"; 080 081 public static final String DOCUMENT_PREFIX = "Document:"; 082 083 @Context 084 protected OperationContext ctx; 085 086 @Context 087 protected CoreSession coreSession; 088 089 @Context 090 UserManager userManager; 091 092 @Context 093 protected TaskService taskService; 094 095 @Context 096 protected DocumentRoutingService routing; 097 098 @Param(name = "accept operation chain", required = false, order = 4) 099 protected String acceptOperationChain; 100 101 @Param(name = "reject operation chain", required = false, order = 5) 102 protected String rejectOperationChain; 103 104 @Param(name = "mappingTaskVariables", required = false) 105 protected Properties mappingTaskVariables; 106 107 @Param(name = "mappingProperties", required = false) 108 protected Properties mappingProperties; 109 110 @OperationMethod(collector = DocumentModelCollector.class) 111 public DocumentModel createTask(DocumentModel document) throws OperationException { 112 Principal pal = coreSession.getPrincipal(); 113 if (!(pal instanceof NuxeoPrincipal)) { 114 throw new OperationException("Principal is not an instance of NuxeoPrincipal"); 115 } 116 117 DocumentRouteStep step = (DocumentRouteStep) ctx.get(DocumentRoutingConstants.OPERATION_STEP_DOCUMENT_KEY); 118 DocumentModel stepDocument = step.getDocument(); 119 TaskStep taskStep = stepDocument.getAdapter(TaskStep.class); 120 List<String> actors = taskStep.getActors(); 121 122 if (actors.isEmpty()) { 123 // no actors: do nothing 124 log.debug("No actors could be resolved => do not create any task"); 125 return document; 126 } 127 128 // create the task, passing operation chains in task variables 129 Map<String, String> taskVariables = new HashMap<String, String>(); 130 taskVariables.put(DocumentRoutingConstants.OPERATION_STEP_DOCUMENT_KEY, step.getDocument().getId()); 131 taskVariables.put(OperationTaskVariableName.createdFromCreateTaskOperation.name(), "true"); 132 if (!StringUtils.isEmpty(acceptOperationChain)) { 133 taskVariables.put(OperationTaskVariableName.acceptOperationChain.name(), acceptOperationChain); 134 } 135 if (!StringUtils.isEmpty(rejectOperationChain)) { 136 taskVariables.put(OperationTaskVariableName.rejectOperationChain.name(), rejectOperationChain); 137 } 138 139 // disable notification service 140 taskVariables.put(TaskEventNames.DISABLE_NOTIFICATION_SERVICE, "true"); 141 142 if (routing == null) { 143 throw new OperationException("Service routingTaskService not found"); 144 } 145 if (mappingTaskVariables != null) { 146 mapPropertiesToTaskVariables(taskVariables, stepDocument, document, mappingTaskVariables); 147 } 148 // TODO: call method with number of comments after NXP-8068 is merged 149 List<Task> tasks = taskService.createTask(coreSession, (NuxeoPrincipal) pal, document, taskStep.getName(), 150 actors, false, taskStep.getDirective(), null, taskStep.getDueDate(), taskVariables, null); 151 routing.makeRoutingTasks(coreSession, tasks); 152 DocumentModelList docList = new DocumentModelListImpl(tasks.size()); 153 for (Task task : tasks) { 154 docList.add(((mappingProperties == null) ? (task.getDocument()) : mapPropertiesToTaskDocument(coreSession, 155 stepDocument, task.getDocument(), document, mappingProperties))); 156 } 157 158 // all the actors should be able to validate the step creating the task 159 for (String actor : actors) { 160 step.setCanReadStep(coreSession, actor); 161 step.setCanValidateStep(coreSession, actor); 162 step.setCanUpdateStep(coreSession, actor); 163 } 164 ctx.put(OperationTaskVariableName.taskDocuments.name(), docList); 165 166 ctx.put(RoutingTaskConstants.ROUTING_TASK_ACTORS_KEY, new StringList(getAllActors(actors))); 167 return document; 168 } 169 170 protected void mapPropertiesToTaskVariables(Map<String, String> taskVariables, DocumentModel stepDoc, 171 DocumentModel inputDoc, Properties mappingProperties) { 172 for (Map.Entry<String, String> prop : mappingProperties.entrySet()) { 173 String getter = prop.getKey(); 174 String setter = prop.getValue(); 175 DocumentModel setterDoc = null; 176 if (setter.startsWith(DOCUMENT_PREFIX)) { 177 setterDoc = inputDoc; 178 setter = setter.substring(DOCUMENT_PREFIX.length()); 179 } else if (setter.startsWith(STEP_PREFIX)) { 180 setterDoc = stepDoc; 181 setter = setter.substring(STEP_PREFIX.length()); 182 } 183 try { 184 taskVariables.put(getter, (String) setterDoc.getPropertyValue(setter)); 185 } catch (PropertyException e) { 186 log.error("Could not map property on the task document in the taskVariables ", e); 187 } 188 } 189 } 190 191 DocumentModel mapPropertiesToTaskDocument(CoreSession session, DocumentModel stepDoc, DocumentModel taskDoc, 192 DocumentModel inputDoc, Properties mappingProperties) { 193 for (Map.Entry<String, String> prop : mappingProperties.entrySet()) { 194 String getter = prop.getKey(); 195 String setter = prop.getValue(); 196 DocumentModel setterDoc = null; 197 if (setter.startsWith(DOCUMENT_PREFIX)) { 198 setterDoc = inputDoc; 199 setter = setter.substring(DOCUMENT_PREFIX.length()); 200 } else if (setter.startsWith(STEP_PREFIX)) { 201 setterDoc = stepDoc; 202 setter = setter.substring(STEP_PREFIX.length()); 203 } 204 try { 205 taskDoc.setPropertyValue(getter, setterDoc.getPropertyValue(setter)); 206 } catch (PropertyException e) { 207 log.error("Could not map property on the task document in the taskVariables ", e); 208 } 209 } 210 return session.saveDocument(taskDoc); 211 } 212 213 protected List<String> getAllActors(List<String> actors) { 214 List<String> allActors = new ArrayList<String>(); 215 for (String actor : actors) { 216 if (userManager.getGroup(actor) != null) { 217 List<String> allSimpleUsers = userManager.getUsersInGroupAndSubGroups(actor); 218 for (String string : allSimpleUsers) { 219 if (!allActors.contains(string)) { 220 allActors.add(string); 221 } 222 } 223 continue; 224 } 225 if (!allActors.contains(actor)) { 226 allActors.add(actor); 227 } 228 } 229 return allActors; 230 } 231 232}