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