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