1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.engine.simulation;
17
18 import org.apache.log4j.MDC;
19 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
20 import org.kuali.rice.kew.actionitem.ActionItem;
21 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
22 import org.kuali.rice.kew.actionrequest.KimGroupRecipient;
23 import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
24 import org.kuali.rice.kew.actionrequest.Recipient;
25 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
26 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
27 import org.kuali.rice.kew.api.WorkflowRuntimeException;
28 import org.kuali.rice.kew.api.exception.DocumentSimulatedRouteException;
29 import org.kuali.rice.kew.doctype.bo.DocumentType;
30 import org.kuali.rice.kew.engine.ActivationContext;
31 import org.kuali.rice.kew.engine.EngineState;
32 import org.kuali.rice.kew.engine.OrchestrationConfig;
33 import org.kuali.rice.kew.engine.ProcessContext;
34 import org.kuali.rice.kew.engine.RouteContext;
35 import org.kuali.rice.kew.engine.StandardWorkflowEngine;
36 import org.kuali.rice.kew.engine.node.Branch;
37 import org.kuali.rice.kew.engine.node.NoOpNode;
38 import org.kuali.rice.kew.engine.node.NodeJotter;
39 import org.kuali.rice.kew.engine.node.NodeType;
40 import org.kuali.rice.kew.engine.node.ProcessDefinitionBo;
41 import org.kuali.rice.kew.engine.node.RequestsNode;
42 import org.kuali.rice.kew.engine.node.RouteNode;
43 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
44 import org.kuali.rice.kew.engine.node.SimpleNode;
45 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
46 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
47 import org.kuali.rice.kew.api.exception.ResourceUnavailableException;
48 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
49 import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
50 import org.kuali.rice.kew.service.KEWServiceLocator;
51 import org.kuali.rice.kew.api.KewApiConstants;
52 import org.kuali.rice.kew.util.PerformanceLogger;
53 import org.kuali.rice.kew.util.Utilities;
54 import org.kuali.rice.kim.api.group.Group;
55 import org.kuali.rice.kim.api.identity.Person;
56
57 import java.io.ByteArrayInputStream;
58 import java.io.ByteArrayOutputStream;
59 import java.io.IOException;
60 import java.io.ObjectInputStream;
61 import java.io.ObjectOutputStream;
62 import java.io.Serializable;
63 import java.sql.Timestamp;
64 import java.util.ArrayList;
65 import java.util.Collections;
66 import java.util.HashSet;
67 import java.util.Iterator;
68 import java.util.List;
69 import java.util.Set;
70
71
72
73
74
75
76
77
78 public class SimulationEngine extends StandardWorkflowEngine implements SimulationWorkflowEngine {
79
80 public SimulationEngine () {
81 super();
82 }
83 public SimulationEngine(RouteNodeService routeNodeService, RouteHeaderService routeHeaderService,
84 ParameterService parameterService, OrchestrationConfig config) {
85 super(routeNodeService, routeHeaderService, parameterService, config);
86 }
87
88 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SimulationEngine.class);
89
90 private SimulationCriteria criteria;
91 private SimulationResults results;
92
93 @Override
94 public SimulationResults runSimulation(SimulationCriteria criteria) throws Exception {
95 try {
96 this.criteria = criteria;
97 this.results = new SimulationResults();
98 validateCriteria(criteria);
99 process(criteria.getDocumentId(), null);
100 return results;
101 } finally {
102
103 this.criteria = null;
104 this.results = null;
105 }
106 }
107
108 @Override
109 public void process(String documentId, String nodeInstanceId) throws InvalidActionTakenException, DocumentSimulatedRouteException {
110 RouteContext context = RouteContext.createNewRouteContext();
111 try {
112 ActivationContext activationContext = new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION);
113 if (criteria.isActivateRequests() == null) {
114 activationContext.setActivateRequests(!criteria.getActionsToTake().isEmpty());
115 } else {
116 activationContext.setActivateRequests(criteria.isActivateRequests().booleanValue());
117 }
118 context.setActivationContext(activationContext);
119 context.setEngineState(new EngineState());
120
121 RequestsNode.setSupressPolicyErrors(context);
122 DocumentRouteHeaderValue document = createSimulationDocument(documentId, criteria, context);
123 document.setInitiatorWorkflowId("simulation");
124 if ( (criteria.isDocumentSimulation()) && ( (document.isProcessed()) || (document.isFinal()) ) ) {
125 results.setDocument(document);
126 return;
127 }
128 routeDocumentIfNecessary(document, criteria, context);
129 results.setDocument(document);
130 documentId = document.getDocumentId();
131
132
133 boolean mdcHadDocId = MDC.get("docId") != null;
134 if (!mdcHadDocId) { MDC.put("docId", documentId); }
135
136 PerformanceLogger perfLog = new PerformanceLogger(documentId);
137 try {
138 if ( LOG.isInfoEnabled() ) {
139 LOG.info("Processing document for Simulation: " + documentId);
140 }
141 List<RouteNodeInstance> activeNodeInstances = getRouteNodeService().getActiveNodeInstances(document);
142 List<RouteNodeInstance> nodeInstancesToProcess = determineNodeInstancesToProcess(activeNodeInstances, criteria.getDestinationNodeName());
143
144 context.setDocument(document);
145
146 context.setEngineState(new EngineState());
147 ProcessContext processContext = new ProcessContext(true, nodeInstancesToProcess);
148 while (! nodeInstancesToProcess.isEmpty()) {
149 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeInstancesToProcess.remove(0);
150 if ( !nodeInstance.isActive() ) {
151 continue;
152 }
153 NodeJotter.jotNodeInstance(context.getDocument(), nodeInstance);
154 context.setNodeInstance(nodeInstance);
155 processContext = processNodeInstance(context, helper);
156 if (!hasReachedCompletion(processContext, context.getEngineState().getGeneratedRequests(), nodeInstance, criteria)) {
157 if (processContext.isComplete()) {
158 if (!processContext.getNextNodeInstances().isEmpty()) {
159 nodeInstancesToProcess.addAll(processContext.getNextNodeInstances());
160 }
161 context.getActivationContext().getSimulatedActionsTaken().addAll(processPotentialActionsTaken(context, document, nodeInstance, criteria));
162 }
163 } else {
164 context.getActivationContext().getSimulatedActionsTaken().addAll(processPotentialActionsTaken(context, document, nodeInstance, criteria));
165 }
166 }
167 List simulatedActionRequests = context.getEngineState().getGeneratedRequests();
168 Collections.sort(simulatedActionRequests, new Utilities.RouteLogActionRequestSorter());
169 results.setSimulatedActionRequests(simulatedActionRequests);
170 results.setSimulatedActionsTaken(context.getActivationContext().getSimulatedActionsTaken());
171 } catch (InvalidActionTakenException e) {
172 throw e;
173 } catch (Exception e) {
174 String errorMsg = "Error running simulation for document " + ((criteria.isDocumentSimulation()) ? "id " + documentId.toString() : "type " + criteria.getDocumentTypeName());
175 LOG.error(errorMsg,e);
176 throw new DocumentSimulatedRouteException(errorMsg, e);
177 } finally {
178 perfLog.log("Time to run simulation.");
179 RouteContext.clearCurrentRouteContext();
180
181 if (!mdcHadDocId) { MDC.remove("docID"); }
182 }
183 } finally {
184 RouteContext.releaseCurrentRouteContext();
185 }
186 }
187
188
189
190
191
192
193
194 private List<RouteNodeInstance> determineNodeInstancesToProcess(List<RouteNodeInstance> activeNodeInstances, String nodeName) throws InvalidActionTakenException {
195 if (org.apache.commons.lang.StringUtils.isEmpty(nodeName)) {
196 return activeNodeInstances;
197 }
198 List<RouteNodeInstance> nodeInstancesToProcess = new ArrayList<RouteNodeInstance>();
199 for (RouteNodeInstance nodeInstance : activeNodeInstances) {
200 if (nodeName.equals(nodeInstance.getName())) {
201
202 return new ArrayList<RouteNodeInstance>();
203 } else {
204 if (isNodeNameInPath(nodeName, nodeInstance)) {
205 nodeInstancesToProcess.add(nodeInstance);
206 }
207 }
208 }
209 if (nodeInstancesToProcess.size() == 0) {
210 throw new InvalidActionTakenException("Could not locate a node with the given name in the blanket approval path '" + nodeName + "'. " +
211 "The document is probably already passed the specified node or does not contain the node.");
212 }
213 return nodeInstancesToProcess;
214 }
215
216 private boolean isNodeNameInPath(String nodeName, RouteNodeInstance nodeInstance) {
217 boolean isInPath = false;
218 for (Iterator<RouteNode> iterator = nodeInstance.getRouteNode().getNextNodes().iterator(); iterator.hasNext();) {
219 RouteNode nextNode = (RouteNode) iterator.next();
220 isInPath = isInPath || isNodeNameInPath(nodeName, nextNode, new HashSet<String>());
221 }
222 return isInPath;
223 }
224
225 private boolean isNodeNameInPath(String nodeName, RouteNode node, Set<String> inspected) {
226 boolean isInPath = !inspected.contains(node.getRouteNodeId()) && node.getRouteNodeName().equals(nodeName);
227 inspected.add(node.getRouteNodeId());
228 if (helper.isSubProcessNode(node)) {
229 ProcessDefinitionBo subProcess = node.getDocumentType().getNamedProcess(node.getRouteNodeName());
230 RouteNode subNode = subProcess.getInitialRouteNode();
231 if (subNode != null) {
232 isInPath = isInPath || isNodeNameInPath(nodeName, subNode, inspected);
233 }
234 }
235 for (Iterator<RouteNode> iterator = node.getNextNodes().iterator(); iterator.hasNext();) {
236 RouteNode nextNode = (RouteNode) iterator.next();
237 isInPath = isInPath || isNodeNameInPath(nodeName, nextNode, inspected);
238 }
239 return isInPath;
240 }
241
242 private boolean hasReachedCompletion(ProcessContext processContext, List actionRequests, RouteNodeInstance nodeInstance, SimulationCriteria criteria) {
243 if (!criteria.getDestinationRecipients().isEmpty()) {
244 for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
245 ActionRequestValue request = (ActionRequestValue) iterator.next();
246 for (Iterator<Recipient> userIt = criteria.getDestinationRecipients().iterator(); userIt.hasNext();) {
247 Recipient recipient = (Recipient) userIt.next();
248 if (request.isRecipientRoutedRequest(recipient)) {
249 if ( (org.apache.commons.lang.StringUtils.isEmpty(criteria.getDestinationNodeName())) || (criteria.getDestinationNodeName().equals(request.getNodeInstance().getName())) ) {
250 return true;
251 }
252 }
253 }
254 }
255 }
256 return (org.apache.commons.lang.StringUtils.isEmpty(criteria.getDestinationNodeName()) && processContext.isComplete() && processContext.getNextNodeInstances().isEmpty())
257 || nodeInstance.getRouteNode().getRouteNodeName().equals(criteria.getDestinationNodeName());
258 }
259
260 private List<ActionTakenValue> processPotentialActionsTaken(RouteContext routeContext, DocumentRouteHeaderValue routeHeader, RouteNodeInstance justProcessedNode, SimulationCriteria criteria) {
261 List<ActionTakenValue> actionsTaken = new ArrayList<ActionTakenValue>();
262 List requestsToCheck = new ArrayList();
263 requestsToCheck.addAll(routeContext.getEngineState().getGeneratedRequests());
264 requestsToCheck.addAll(routeHeader.getActionRequests());
265 List<ActionRequestValue> pendingActionRequestValues = getCriteriaActionsToDoByNodeName(requestsToCheck, justProcessedNode.getName());
266 List<ActionTakenValue> actionsToTakeForNode = generateActionsToTakeForNode(justProcessedNode.getName(), routeHeader, criteria, pendingActionRequestValues);
267
268 for (ActionTakenValue actionTaken : actionsToTakeForNode)
269 {
270 KEWServiceLocator.getActionRequestService().deactivateRequests(actionTaken, pendingActionRequestValues, routeContext.getActivationContext());
271 actionsTaken.add(actionTaken);
272
273 }
274 return actionsTaken;
275 }
276
277 private List<ActionTakenValue> generateActionsToTakeForNode(String nodeName, DocumentRouteHeaderValue routeHeader, SimulationCriteria criteria, List<ActionRequestValue> pendingActionRequests) {
278 List<ActionTakenValue> actions = new ArrayList<ActionTakenValue>();
279 if ( (criteria.getActionsToTake() != null) && (!criteria.getActionsToTake().isEmpty()) ) {
280 for (SimulationActionToTake simAction : criteria.getActionsToTake()) {
281 if (nodeName.equals(simAction.getNodeName())) {
282 actions.add(createDummyActionTaken(routeHeader, simAction.getUser(), simAction.getActionToPerform(), findDelegatorForActionRequests(pendingActionRequests)));
283 }
284 }
285 }
286 return actions;
287 }
288
289 private List<ActionRequestValue> getCriteriaActionsToDoByNodeName(List generatedRequests, String nodeName) {
290 List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>();
291 for (Iterator iterator = generatedRequests.iterator(); iterator.hasNext();) {
292 ActionRequestValue request = (ActionRequestValue) iterator.next();
293 if ( (request.isPending()) && request.getNodeInstance() != null && nodeName.equals(request.getNodeInstance().getName())) {
294 requests.add(request);
295 }
296 }
297 return requests;
298 }
299
300 private void validateCriteria(SimulationCriteria criteria) {
301 if (criteria.getDocumentId() == null && org.apache.commons.lang.StringUtils.isEmpty(criteria.getDocumentTypeName())) {
302 throw new IllegalArgumentException("No document type name or document id given, cannot simulate a document without a document type name or a document id.");
303 }
304 if (criteria.getXmlContent() == null) {
305 criteria.setXmlContent("");
306 }
307 }
308
309
310
311
312
313
314
315
316 private DocumentRouteHeaderValue createSimulationDocument(String documentId, SimulationCriteria criteria, RouteContext context) {
317 DocumentRouteHeaderValue document = null;
318 if (criteria.isDocumentSimulation()) {
319 document = getDocumentForSimulation(documentId);
320 if (!org.apache.commons.lang.StringUtils.isEmpty(criteria.getXmlContent())) {
321 document.setDocContent(criteria.getXmlContent());
322 }
323 } else if (criteria.isDocumentTypeSimulation()) {
324 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(criteria.getDocumentTypeName());
325 if (documentType == null) {
326 throw new IllegalArgumentException("Specified document type could not be found for name '"+criteria.getDocumentTypeName()+"'");
327 }
328 documentId = context.getEngineState().getNextSimulationId().toString();
329 document = new DocumentRouteHeaderValue();
330 context.setDocument(document);
331 document.setDocumentId(documentId);
332 document.setCreateDate(new Timestamp(System.currentTimeMillis()));
333 document.setDocContent(criteria.getXmlContent());
334 document.setDocRouteLevel(new Integer(0));
335 document.setDocumentTypeId(documentType.getDocumentTypeId());
336 document.setDocRouteStatus(KewApiConstants.ROUTE_HEADER_INITIATED_CD);
337 initializeDocument(document);
338 }
339 if (document == null) {
340 throw new IllegalArgumentException("Workflow simulation engine could not locate document with id "+documentId);
341 }
342 for (ActionRequestValue actionRequest : document.getActionRequests()) {
343 actionRequest = (ActionRequestValue) deepCopy(actionRequest);
344 document.getSimulatedActionRequests().add(actionRequest);
345 for (ActionItem actionItem : actionRequest.getActionItems()) {
346 actionRequest.getSimulatedActionItems().add((ActionItem) deepCopy(actionItem));
347 }
348 }
349 context.setDocument(document);
350 installSimulationNodeInstances(context, criteria);
351 return document;
352 }
353
354 private DocumentRouteHeaderValue getDocumentForSimulation(String documentId) {
355 DocumentRouteHeaderValue document = getRouteHeaderService().getRouteHeader(documentId);
356 return (DocumentRouteHeaderValue)deepCopy(document);
357 }
358
359 private Serializable deepCopy(Serializable src) {
360 Serializable obj = null;
361 if (src != null) {
362 ObjectOutputStream oos = null;
363 ObjectInputStream ois = null;
364 try {
365 ByteArrayOutputStream serializer = new ByteArrayOutputStream();
366 oos = new ObjectOutputStream(serializer);
367 oos.writeObject(src);
368
369 ByteArrayInputStream deserializer = new ByteArrayInputStream(serializer.toByteArray());
370 ois = new ObjectInputStream(deserializer);
371 obj = (Serializable) ois.readObject();
372 }
373 catch (IOException e) {
374 throw new RuntimeException("unable to complete deepCopy from src '" + src.toString() + "'", e);
375 }
376 catch (ClassNotFoundException e) {
377 throw new RuntimeException("unable to complete deepCopy from src '" + src.toString() + "'", e);
378 }
379 finally {
380 try {
381 if (oos != null) {
382 oos.close();
383 }
384 if (ois != null) {
385 ois.close();
386 }
387 }
388 catch (IOException e) {
389
390 }
391 }
392 }
393 return obj;
394 }
395
396 private void routeDocumentIfNecessary(DocumentRouteHeaderValue document, SimulationCriteria criteria, RouteContext routeContext) throws InvalidActionTakenException {
397 if (criteria.getRoutingUser() != null) {
398 ActionTakenValue action = createDummyActionTaken(document, criteria.getRoutingUser(), KewApiConstants.ACTION_TAKEN_ROUTED_CD, null);
399 routeContext.getActivationContext().getSimulatedActionsTaken().add(action);
400 simulateDocumentRoute(action, document, criteria.getRoutingUser(), routeContext);
401 }
402 }
403
404
405
406
407
408
409 private void installSimulationNodeInstances(RouteContext context, SimulationCriteria criteria) {
410 DocumentRouteHeaderValue document = context.getDocument();
411 List<RouteNode> simulationNodes = new ArrayList<RouteNode>();
412 if (!criteria.getNodeNames().isEmpty()) {
413 for (String nodeName : criteria.getNodeNames()) {
414 if ( LOG.isDebugEnabled() ) {
415 LOG.debug("Installing simulation starting node '"+nodeName+"'");
416 }
417 List<RouteNode> nodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(document.getDocumentType(), true);
418 boolean foundNode = false;
419 for (RouteNode node : nodes) {
420 if (node.getRouteNodeName().equals(nodeName)) {
421 simulationNodes.add(node);
422 foundNode = true;
423 break;
424 }
425 }
426 if (!foundNode) {
427 throw new IllegalArgumentException("Could not find node on the document type for the given name '"+nodeName+"'");
428 }
429 }
430 } else if (!criteria.getRuleTemplateNames().isEmpty()) {
431 List<RouteNode> nodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(document.getDocumentType(), true);
432 for (String ruleTemplateName : criteria.getRuleTemplateNames()) {
433 boolean foundNode = false;
434 for (RouteNode node : nodes) {
435 String routeMethodName = node.getRouteMethodName();
436 if (node.isFlexRM() && ruleTemplateName.equals(routeMethodName)) {
437 simulationNodes.add(node);
438 foundNode = true;
439 break;
440 }
441 }
442 if (!foundNode) {
443 throw new IllegalArgumentException("Could not find node on the document type with the given rule template name '"+ruleTemplateName+"'");
444 }
445 }
446 } else if (criteria.isFlattenNodes()) {
447
448 List<RouteNode> nodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(document.getDocumentType(), true);
449 for ( RouteNode node : nodes ) {
450 try {
451 if ( NodeType.fromNode( node ).isTypeOf( SimpleNode.class )
452 && !NodeType.fromNode( node ).isTypeOf( NoOpNode.class ) ) {
453 simulationNodes.add(node);
454 }
455 } catch (ResourceUnavailableException ex) {
456 LOG.warn( "Unable to determine node type in simulator: " + ex.getMessage() );
457 }
458 }
459 } else {
460
461 return;
462 }
463
464
465 Branch defaultBranch = document.getInitialRouteNodeInstances().get(0).getBranch();
466
467 document.getInitialRouteNodeInstances().clear();
468
469 RouteNodeInstance currentNodeInstance = null;
470 for (RouteNode simulationNode : simulationNodes) {
471 RouteNodeInstance nodeInstance = helper.getNodeFactory().createRouteNodeInstance(document.getDocumentId(), simulationNode);
472 nodeInstance.setBranch(defaultBranch);
473 if (currentNodeInstance == null) {
474 document.getInitialRouteNodeInstances().add(nodeInstance);
475 nodeInstance.setActive(true);
476 saveNode(context, nodeInstance);
477 } else {
478 currentNodeInstance.addNextNodeInstance(nodeInstance);
479 saveNode(context, currentNodeInstance);
480 }
481 currentNodeInstance = nodeInstance;
482 }
483 installSimulationTerminationNode(context, document.getDocumentType(), currentNodeInstance);
484 }
485
486 private void installSimulationTerminationNode(RouteContext context, DocumentType documentType, RouteNodeInstance lastNodeInstance) {
487 RouteNode terminationNode = new RouteNode();
488 terminationNode.setDocumentType(documentType);
489 terminationNode.setDocumentTypeId(documentType.getDocumentTypeId());
490 terminationNode.setNodeType(NoOpNode.class.getName());
491 terminationNode.setRouteNodeName("SIMULATION_TERMINATION_NODE");
492 RouteNodeInstance terminationNodeInstance = helper.getNodeFactory().createRouteNodeInstance(lastNodeInstance.getDocumentId(), terminationNode);
493 terminationNodeInstance.setBranch(lastNodeInstance.getBranch());
494 lastNodeInstance.addNextNodeInstance(terminationNodeInstance);
495 saveNode(context, lastNodeInstance);
496 }
497
498
499 private void simulateDocumentRoute(ActionTakenValue actionTaken, DocumentRouteHeaderValue document, Person user, RouteContext routeContext) throws InvalidActionTakenException {
500 if (document.isRouted()) {
501 throw new WorkflowRuntimeException("Document can not simulate a route if it has already been routed");
502 }
503 ActionRequestService actionRequestService = KEWServiceLocator.getActionRequestService();
504
505 List<ActionRequestValue> actionRequests = new ArrayList<ActionRequestValue>();
506 for (Iterator iter = actionRequestService.findPendingByDoc(document.getDocumentId()).iterator(); iter.hasNext();) {
507 ActionRequestValue arv = (ActionRequestValue) deepCopy( (ActionRequestValue) iter.next() );
508 for (ActionItem actionItem : arv.getActionItems()) {
509 arv.getSimulatedActionItems().add((ActionItem) deepCopy(actionItem));
510 }
511 actionRequests.add(arv);
512 }
513
514 LOG.debug("Simulate Deactivating all pending action requests");
515
516 for (Iterator<ActionRequestValue> iter = actionRequests.iterator(); iter.hasNext();) {
517 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
518
519 if ( (user.getPrincipalId().equals(actionRequest.getPrincipalId())) && (actionRequest.isActive()) ) {
520 actionRequestService.deactivateRequest(actionTaken, actionRequest, routeContext.getActivationContext());
521 }
522
523 else if (KewApiConstants.SAVED_REQUEST_RESPONSIBILITY_ID.equals(actionRequest.getResponsibilityId())) {
524 actionRequestService.deactivateRequest(actionTaken, actionRequest, routeContext.getActivationContext());
525 }
526 }
527
528
529 document.markDocumentEnroute();
530
531
532
533 }
534
535 private ActionTakenValue createDummyActionTaken(DocumentRouteHeaderValue routeHeader, Person userToPerformAction, String actionToPerform, Recipient delegator) {
536 ActionTakenValue val = new ActionTakenValue();
537 val.setActionTaken(actionToPerform);
538 if (KewApiConstants.ACTION_TAKEN_ROUTED_CD.equals(actionToPerform)) {
539 val.setActionTaken(KewApiConstants.ACTION_TAKEN_COMPLETED_CD);
540 }
541 val.setAnnotation("");
542 val.setDocVersion(routeHeader.getDocVersion());
543 val.setDocumentId(routeHeader.getDocumentId());
544 val.setPrincipalId(userToPerformAction.getPrincipalId());
545
546 if (delegator != null) {
547 if (delegator instanceof KimPrincipalRecipient) {
548 val.setDelegatorPrincipalId(((KimPrincipalRecipient) delegator).getPrincipalId());
549 } else if (delegator instanceof KimGroupRecipient) {
550 Group group = ((KimGroupRecipient) delegator).getGroup();
551 val.setDelegatorGroupId(group.getId());
552 } else{
553 throw new IllegalArgumentException("Invalid Recipient type received: " + delegator.getClass().getName());
554 }
555 }
556
557
558 val.setCurrentIndicator(Boolean.TRUE);
559 return val;
560 }
561
562
563
564
565
566
567 private Recipient findDelegatorForActionRequests(List<ActionRequestValue> actionRequests) {
568 return KEWServiceLocator.getActionRequestService().findDelegator(actionRequests);
569 }
570
571
572
573
574
575
576
577 @Override
578 protected void saveNode(RouteContext context, RouteNodeInstance nodeInstance) {
579
580
581 if (nodeInstance.getRouteNodeInstanceId() == null) {
582 nodeInstance.setRouteNodeInstanceId(context.getEngineState().getNextSimulationId());
583 }
584
585
586
587 for (Iterator<RouteNodeInstance> iterator = nodeInstance.getNextNodeInstances().iterator(); iterator.hasNext();) {
588 RouteNodeInstance routeNodeInstance = (RouteNodeInstance) iterator.next();
589 if (routeNodeInstance.getRouteNodeInstanceId() == null) {
590 routeNodeInstance.setRouteNodeInstanceId(context.getEngineState().getNextSimulationId());
591 }
592 }
593 if (nodeInstance.getProcess() != null && nodeInstance.getProcess().getRouteNodeInstanceId() == null) {
594 nodeInstance.getProcess().setRouteNodeInstanceId(context.getEngineState().getNextSimulationId());
595 }
596 if (nodeInstance.getBranch() != null && nodeInstance.getBranch().getBranchId() == null) {
597 nodeInstance.getBranch().setBranchId(context.getEngineState().getNextSimulationId());
598 }
599 }
600
601 }