1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.engine;
17
18 import org.apache.log4j.MDC;
19 import org.kuali.rice.core.framework.parameter.ParameterService;
20 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
21 import org.kuali.rice.kew.api.doctype.IllegalDocumentTypeException;
22 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
23 import org.kuali.rice.kew.api.exception.WorkflowException;
24 import org.kuali.rice.kew.engine.node.Branch;
25 import org.kuali.rice.kew.engine.node.BranchState;
26 import org.kuali.rice.kew.engine.node.ProcessDefinitionBo;
27 import org.kuali.rice.kew.engine.node.ProcessResult;
28 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
29 import org.kuali.rice.kew.engine.node.RouteNodeUtils;
30 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
31 import org.kuali.rice.kew.engine.transition.Transition;
32 import org.kuali.rice.kew.engine.transition.TransitionEngine;
33 import org.kuali.rice.kew.engine.transition.TransitionEngineFactory;
34 import org.kuali.rice.kew.exception.RouteManagerException;
35 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
36 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
37 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
38 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
39 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
40 import org.kuali.rice.kew.framework.postprocessor.PostProcessor;
41 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
42 import org.kuali.rice.kew.postprocessor.DefaultPostProcessor;
43 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
44 import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
45 import org.kuali.rice.kew.service.KEWServiceLocator;
46 import org.kuali.rice.kew.api.KewApiConstants;
47 import org.kuali.rice.kew.util.PerformanceLogger;
48 import org.kuali.rice.krad.util.KRADConstants;
49
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.Iterator;
53 import java.util.LinkedList;
54 import java.util.List;
55
56
57
58
59
60
61
62
63
64 public class StandardWorkflowEngine implements WorkflowEngine {
65
66 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(StandardWorkflowEngine.class);
67
68 protected final RouteHelper helper = new RouteHelper();
69 protected RouteNodeService routeNodeService;
70 protected RouteHeaderService routeHeaderService;
71 protected ParameterService parameterService;
72 protected OrchestrationConfig config;
73
74 public StandardWorkflowEngine() {}
75
76 protected StandardWorkflowEngine(RouteNodeService routeNodeService, RouteHeaderService routeHeaderService,
77 ParameterService parameterService, OrchestrationConfig config) {
78 this.routeNodeService = routeNodeService;
79 this.routeHeaderService = routeHeaderService;
80 this.parameterService = parameterService;
81 this.config = config;
82 }
83
84
85
86
87
88 public boolean isRunPostProcessorLogic() {
89 return this.config.isRunPostProcessorLogic();
90 }
91
92 public void process(String documentId, String nodeInstanceId) throws Exception {
93 if (documentId == null) {
94 throw new IllegalArgumentException("Cannot process a null document id.");
95 }
96 MDC.put("docId", documentId);
97 boolean success = true;
98 RouteContext context = RouteContext.createNewRouteContext();
99 try {
100 if ( LOG.isInfoEnabled() ) {
101 LOG.info("Aquiring lock on document " + documentId);
102 }
103 KEWServiceLocator.getRouteHeaderService().lockRouteHeader(documentId, true);
104 if ( LOG.isInfoEnabled() ) {
105 LOG.info("Aquired lock on document " + documentId);
106 }
107
108 DocumentRouteHeaderValue document = getRouteHeaderService().getRouteHeader(documentId);
109 context.setDocument(document);
110 lockAdditionalDocuments(document);
111
112 if ( LOG.isInfoEnabled() ) {
113 LOG.info("Processing document: " + documentId + " : " + nodeInstanceId);
114 }
115
116 try {
117 document = notifyPostProcessorBeforeProcess(document, nodeInstanceId);
118 context.setDocument(document);
119 } catch (Exception e) {
120 LOG.warn("Problems contacting PostProcessor before engine process", e);
121 throw new RouteManagerException("Problems contacting PostProcessor: " + e.getMessage());
122 }
123 if (!document.isRoutable()) {
124 LOG.debug("Document not routable so returning with doing no action");
125 return;
126 }
127 List<RouteNodeInstance> nodeInstancesToProcess = new LinkedList<RouteNodeInstance>();
128 if (nodeInstanceId == null) {
129
130 nodeInstancesToProcess.addAll(RouteNodeUtils.getActiveNodeInstances(document));
131 } else {
132 RouteNodeInstance instanceNode = RouteNodeUtils.findRouteNodeInstanceById(nodeInstanceId,document);
133 if (instanceNode == null) {
134 throw new IllegalArgumentException("Invalid node instance id: " + nodeInstanceId);
135 }
136 nodeInstancesToProcess.add(instanceNode);
137 }
138
139 context.setEngineState(new EngineState());
140 ProcessContext processContext = new ProcessContext(true, nodeInstancesToProcess);
141 try {
142 while (!nodeInstancesToProcess.isEmpty()) {
143 context.setNodeInstance((RouteNodeInstance) nodeInstancesToProcess.remove(0));
144 processContext = processNodeInstance(context, helper);
145 if (processContext.isComplete() && !processContext.getNextNodeInstances().isEmpty()) {
146 nodeInstancesToProcess.addAll(processContext.getNextNodeInstances());
147 }
148 }
149 context.setDocument(nodePostProcess(context));
150 } catch (Exception e) {
151 success = false;
152
153
154 throw new RouteManagerException(e, context);
155 }
156 } finally {
157 if ( LOG.isInfoEnabled() ) {
158 LOG.info((success ? "Successfully processed" : "Failed to process") + " document: " + documentId + " : " + nodeInstanceId);
159 }
160 try {
161 notifyPostProcessorAfterProcess(context.getDocument(), nodeInstanceId, success);
162 } catch (Exception e) {
163 LOG.warn("Problems contacting PostProcessor after engine process", e);
164 throw new RouteManagerException("Problems contacting PostProcessor", e, context);
165 }
166 RouteContext.clearCurrentRouteContext();
167 MDC.remove("docId");
168 }
169 }
170
171 protected ProcessContext processNodeInstance(RouteContext context, RouteHelper helper) throws Exception {
172 RouteNodeInstance nodeInstance = context.getNodeInstance();
173 if ( LOG.isDebugEnabled() ) {
174 LOG.debug("Processing node instance: " + nodeInstance.getRouteNode().getRouteNodeName());
175 }
176 if (checkAssertions(context)) {
177
178 return new ProcessContext();
179 }
180 TransitionEngine transitionEngine = TransitionEngineFactory.createTransitionEngine(nodeInstance);
181 ProcessResult processResult = transitionEngine.isComplete(context);
182 nodeInstance.setInitial(false);
183
184
185
186 if (processResult.isComplete()) {
187 if ( LOG.isDebugEnabled() ) {
188 LOG.debug("Routing node has completed: " + nodeInstance.getRouteNode().getRouteNodeName());
189 }
190
191 context.getEngineState().getCompleteNodeInstances().add(nodeInstance.getRouteNodeInstanceId());
192 List nextNodeCandidates = invokeTransition(context, context.getNodeInstance(), processResult, transitionEngine);
193
194
195
196
197
198
199 List<RouteNodeInstance> nodesToActivate = new ArrayList<RouteNodeInstance>();
200 if (!nextNodeCandidates.isEmpty()) {
201
202
203
204 ArrayList<RouteNodeInstance> nextNodeInstances = new ArrayList<RouteNodeInstance>();
205
206 for (Iterator nextIt = nextNodeCandidates.iterator(); nextIt.hasNext();) {
207 RouteNodeInstance nextNodeInstance = (RouteNodeInstance) nextIt.next();
208 transitionEngine = TransitionEngineFactory.createTransitionEngine(nextNodeInstance);
209 RouteNodeInstance currentNextNodeInstance = nextNodeInstance;
210 nextNodeInstance = transitionEngine.transitionTo(nextNodeInstance, context);
211
212
213 if (!currentNextNodeInstance.equals(nextNodeInstance)) {
214 currentNextNodeInstance.getPreviousNodeInstances().remove(nodeInstance);
215 }
216
217
218
219
220
221
222
223
224
225 nextNodeInstance.getPreviousNodeInstances().remove(nodeInstance);
226 nextNodeInstances.add(nextNodeInstance);
227 handleBackwardCompatibility(context, nextNodeInstance);
228
229 notifyNodeChange(context, nextNodeInstance);
230 nodesToActivate.add(nextNodeInstance);
231
232 }
233
234 for (RouteNodeInstance nextNodeInstance : nextNodeInstances) {
235 nodeInstance.addNextNodeInstance(nextNodeInstance);
236 }
237 }
238
239
240 nodeInstance.setComplete(true);
241 nodeInstance.setActive(false);
242
243 for (RouteNodeInstance nodeToActivate : nodesToActivate) {
244 nodeToActivate.setActive(true);
245 }
246 } else {
247 nodeInstance.setComplete(false);
248 }
249
250 saveNode(context, nodeInstance);
251 return new ProcessContext(nodeInstance.isComplete(), nodeInstance.getNextNodeInstances());
252 }
253
254
255
256
257
258
259
260
261 private boolean checkAssertions(RouteContext context) throws Exception {
262 if (context.getNodeInstance().isComplete()) {
263 if ( LOG.isDebugEnabled() ) {
264 LOG.debug("The node has already been completed: " + context.getNodeInstance().getRouteNode().getRouteNodeName());
265 }
266 return true;
267 }
268 if (isRunawayProcessDetected(context.getEngineState())) {
269
270 throw new WorkflowException("Detected runaway process.");
271 }
272 return false;
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 private List invokeTransition(RouteContext context, RouteNodeInstance nodeInstance, ProcessResult processResult, TransitionEngine transitionEngine) throws Exception {
303 List nextNodeInstances = nodeInstance.getNextNodeInstances();
304 if (nextNodeInstances.isEmpty()) {
305 Transition result = transitionEngine.transitionFrom(context, processResult);
306 nextNodeInstances = result.getNextNodeInstances();
307 if (nextNodeInstances.isEmpty() && nodeInstance.isInProcess()) {
308 transitionEngine = TransitionEngineFactory.createTransitionEngine(nodeInstance.getProcess());
309 context.setNodeInstance(nodeInstance);
310 nextNodeInstances = invokeTransition(context, nodeInstance.getProcess(), processResult, transitionEngine);
311 }
312 }
313 return nextNodeInstances;
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 private void notifyNodeChange(RouteContext context, RouteNodeInstance nextNodeInstance) throws Exception {
332 if (!context.isSimulation()) {
333 RouteNodeInstance nodeInstance = context.getNodeInstance();
334
335 String nextStatus = nodeInstance.getRouteNode().getNextDocStatus();
336 if (nextStatus != null && nextStatus.length() > 0){
337 context.getDocument().updateAppDocStatus(nextStatus);
338 }
339
340 DocumentRouteLevelChange event = new DocumentRouteLevelChange(context.getDocument().getDocumentId(), context.getDocument().getAppDocId(), CompatUtils.getLevelForNode(context.getDocument().getDocumentType(), context.getNodeInstance()
341 .getRouteNode().getRouteNodeName()), CompatUtils.getLevelForNode(context.getDocument().getDocumentType(), nextNodeInstance.getRouteNode().getRouteNodeName()), nodeInstance.getRouteNode().getRouteNodeName(), nextNodeInstance
342 .getRouteNode().getRouteNodeName(), nodeInstance.getRouteNodeInstanceId(), nextNodeInstance.getRouteNodeInstanceId());
343 context.setDocument(notifyPostProcessor(context.getDocument(), nodeInstance, event));
344 }
345 }
346
347 private void handleBackwardCompatibility(RouteContext context, RouteNodeInstance nextNodeInstance) {
348 context.getDocument().setDocRouteLevel(new Integer(context.getDocument().getDocRouteLevel().intValue() + 1));
349
350
351
352
353
354 saveDocument(context);
355 }
356
357 private void saveDocument(RouteContext context) {
358 if (!context.isSimulation()) {
359 getRouteHeaderService().saveRouteHeader(context.getDocument());
360 }
361 }
362
363 private void saveBranch(RouteContext context, Branch branch) {
364 if (!context.isSimulation()) {
365 KEWServiceLocator.getRouteNodeService().save(branch);
366 }
367 }
368
369 protected void saveNode(RouteContext context, RouteNodeInstance nodeInstance) {
370 if (!context.isSimulation()) {
371 getRouteNodeService().save(nodeInstance);
372 } else {
373
374
375 for (Iterator<RouteNodeInstance> iterator = nodeInstance.getNextNodeInstances().iterator(); iterator.hasNext();) {
376 RouteNodeInstance routeNodeInstance = (RouteNodeInstance) iterator.next();
377 if (routeNodeInstance.getRouteNodeInstanceId() == null) {
378 routeNodeInstance.setRouteNodeInstanceId(context.getEngineState().getNextSimulationId());
379 }
380 }
381 if (nodeInstance.getProcess() != null && nodeInstance.getProcess().getRouteNodeInstanceId() == null) {
382 nodeInstance.getProcess().setRouteNodeInstanceId(context.getEngineState().getNextSimulationId());
383 }
384 if (nodeInstance.getBranch() != null && nodeInstance.getBranch().getBranchId() == null) {
385 nodeInstance.getBranch().setBranchId(context.getEngineState().getNextSimulationId());
386 }
387 }
388 }
389
390
391
392 protected DocumentRouteHeaderValue nodePostProcess(RouteContext context) throws InvalidActionTakenException {
393 DocumentRouteHeaderValue document = context.getDocument();
394 Collection<RouteNodeInstance> activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
395 boolean moreNodes = false;
396 for (Iterator<RouteNodeInstance> iterator = activeNodes.iterator(); iterator.hasNext();) {
397 RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
398 moreNodes = moreNodes || !nodeInstance.isComplete();
399 }
400 List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
401 boolean activeApproveRequests = false;
402 boolean activeAckRequests = false;
403 for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) {
404 ActionRequestValue request = (ActionRequestValue) iterator.next();
405 activeApproveRequests = request.isApproveOrCompleteRequest() || activeApproveRequests;
406 activeAckRequests = request.isAcknowledgeRequest() || activeAckRequests;
407 }
408
409 if (!document.isProcessed() && (!moreNodes || !activeApproveRequests)) {
410 if ( LOG.isDebugEnabled() ) {
411 LOG.debug("No more nodes for this document " + document.getDocumentId());
412 }
413
414 checkDefaultApprovalPolicy(document);
415
416 LOG.debug("Marking document processed");
417 DocumentRouteStatusChange event = new DocumentRouteStatusChange(document.getDocumentId(), document.getAppDocId(), document.getDocRouteStatus(), KewApiConstants.ROUTE_HEADER_PROCESSED_CD);
418 document.markDocumentProcessed();
419
420 notifyPostProcessor(context, event);
421 }
422
423
424
425 if (document.isProcessed()) {
426 DocumentRouteStatusChange event = new DocumentRouteStatusChange(document.getDocumentId(), document.getAppDocId(), document.getDocRouteStatus(), KewApiConstants.ROUTE_HEADER_FINAL_CD);
427 List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
428 if (actionRequests.isEmpty()) {
429 document.markDocumentFinalized();
430
431 notifyPostProcessor(context, event);
432 } else {
433 boolean markFinalized = true;
434 for (Iterator iter = actionRequests.iterator(); iter.hasNext();) {
435 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
436 if (KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(actionRequest.getActionRequested())) {
437 markFinalized = false;
438 }
439 }
440 if (markFinalized) {
441 document.markDocumentFinalized();
442
443 this.notifyPostProcessor(context, event);
444 }
445 }
446 }
447 saveDocument(context);
448 return document;
449 }
450
451
452
453
454
455
456
457
458
459 private void checkDefaultApprovalPolicy(DocumentRouteHeaderValue document) throws RouteManagerException {
460 if (!document.getDocumentType().getDefaultApprovePolicy().getPolicyValue().booleanValue()) {
461 LOG.debug("Checking if any requests have been generated for the document");
462 List requests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(document.getDocumentId());
463 boolean approved = false;
464 for (Iterator iter = requests.iterator(); iter.hasNext();) {
465 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
466 if (actionRequest.isApproveOrCompleteRequest() && actionRequest.isDone()) {
467
468
469
470
471
472
473 LOG.debug("Found at least one processed approve request so document can be approved");
474 approved = true;
475 break;
476 }
477 }
478 if (!approved) {
479 LOG.debug("Document requires at least one request and none are present");
480
481 throw new RouteManagerException("Document should have generated at least one approval request.");
482 }
483 }
484 }
485
486 private DocumentRouteHeaderValue notifyPostProcessor(RouteContext context, DocumentRouteStatusChange event) {
487 DocumentRouteHeaderValue document = context.getDocument();
488 if (context.isSimulation()) {
489 return document;
490 }
491 if (hasContactedPostProcessor(context, event)) {
492 return document;
493 }
494 String documentId = event.getDocumentId();
495 PerformanceLogger performanceLogger = new PerformanceLogger(documentId);
496 ProcessDocReport processReport = null;
497 PostProcessor postProc = null;
498 try {
499
500 if (!isRunPostProcessorLogic()) {
501 postProc = new DefaultPostProcessor();
502 } else {
503 postProc = document.getDocumentType().getPostProcessor();
504 }
505 } catch (Exception e) {
506 LOG.error("Error retrieving PostProcessor for document " + document.getDocumentId(), e);
507 throw new RouteManagerException("Error retrieving PostProcessor for document " + document.getDocumentId(), e);
508 }
509 try {
510 processReport = postProc.doRouteStatusChange(event);
511 } catch (Exception e) {
512 LOG.error("Error notifying post processor", e);
513 throw new RouteManagerException(KewApiConstants.POST_PROCESSOR_FAILURE_MESSAGE, e);
514 } finally {
515 performanceLogger.log("Time to notifyPostProcessor of event " + event.getDocumentEventCode() + ".");
516 }
517
518 if (!processReport.isSuccess()) {
519 LOG.warn("PostProcessor failed to process document: " + processReport.getMessage());
520 throw new RouteManagerException(KewApiConstants.POST_PROCESSOR_FAILURE_MESSAGE + processReport.getMessage());
521 }
522 return document;
523 }
524
525
526
527
528
529
530
531
532
533
534
535 private boolean hasContactedPostProcessor(RouteContext context, DocumentRouteStatusChange event) {
536
537
538 Branch rootBranch = context.getDocument().getRootBranch();
539 String key = null;
540 if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(event.getNewRouteStatus())) {
541 key = KewApiConstants.POST_PROCESSOR_PROCESSED_KEY;
542 } else if (KewApiConstants.ROUTE_HEADER_FINAL_CD.equals(event.getNewRouteStatus())) {
543 key = KewApiConstants.POST_PROCESSOR_FINAL_KEY;
544 } else {
545 return false;
546 }
547 BranchState branchState = null;
548 if (rootBranch != null) {
549 branchState = rootBranch.getBranchState(key);
550 } else {
551 return false;
552 }
553 if (branchState == null) {
554 branchState = new BranchState();
555 branchState.setKey(key);
556 branchState.setValue("true");
557 rootBranch.addBranchState(branchState);
558 saveBranch(context, rootBranch);
559 return false;
560 }
561 return "true".equals(branchState.getValue());
562 }
563
564
565
566
567
568
569
570
571 private DocumentRouteHeaderValue notifyPostProcessor(DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance, DocumentRouteLevelChange event) {
572 getRouteHeaderService().saveRouteHeader(document);
573 ProcessDocReport report = null;
574 try {
575 PostProcessor postProcessor = null;
576
577 if (!isRunPostProcessorLogic()) {
578 postProcessor = new DefaultPostProcessor();
579 } else {
580 postProcessor = document.getDocumentType().getPostProcessor();
581 }
582 report = postProcessor.doRouteLevelChange(event);
583 } catch (Exception e) {
584 LOG.warn("Problems contacting PostProcessor", e);
585 throw new RouteManagerException("Problems contacting PostProcessor: " + e.getMessage());
586 }
587 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
588 if (!report.isSuccess()) {
589 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
590 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
591 }
592 return document;
593 }
594
595
596
597
598
599 private DocumentRouteHeaderValue notifyPostProcessorBeforeProcess(DocumentRouteHeaderValue document, String nodeInstanceId) {
600 return notifyPostProcessorBeforeProcess(document, nodeInstanceId, new BeforeProcessEvent(document.getDocumentId(),document.getAppDocId(),nodeInstanceId));
601 }
602
603
604
605
606
607 private DocumentRouteHeaderValue notifyPostProcessorBeforeProcess(DocumentRouteHeaderValue document, String nodeInstanceId, BeforeProcessEvent event) {
608 ProcessDocReport report = null;
609 try {
610 PostProcessor postProcessor = null;
611
612 if (!isRunPostProcessorLogic()) {
613 postProcessor = new DefaultPostProcessor();
614 } else {
615 postProcessor = document.getDocumentType().getPostProcessor();
616 }
617 report = postProcessor.beforeProcess(event);
618 } catch (Exception e) {
619 LOG.warn("Problems contacting PostProcessor", e);
620 throw new RouteManagerException("Problems contacting PostProcessor: " + e.getMessage());
621 }
622 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
623 if (!report.isSuccess()) {
624 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
625 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
626 }
627 return document;
628 }
629
630 protected void lockAdditionalDocuments(DocumentRouteHeaderValue document) throws Exception {
631 DocumentLockingEvent lockingEvent = new DocumentLockingEvent(document.getDocumentId(), document.getAppDocId());
632
633 PostProcessor postProcessor = null;
634
635 if (!isRunPostProcessorLogic()) {
636 postProcessor = new DefaultPostProcessor();
637 } else {
638 postProcessor = document.getDocumentType().getPostProcessor();
639 }
640 List<String> documentIdsToLock = postProcessor.getDocumentIdsToLock(lockingEvent);
641 if (documentIdsToLock != null && !documentIdsToLock.isEmpty()) {
642 for (String documentId : documentIdsToLock) {
643 if ( LOG.isInfoEnabled() ) {
644 LOG.info("Aquiring additional lock on document " + documentId);
645 }
646 getRouteHeaderService().lockRouteHeader(documentId, true);
647 if ( LOG.isInfoEnabled() ) {
648 LOG.info("Aquired lock on document " + documentId);
649 }
650 }
651 }
652 }
653
654
655
656
657
658 private DocumentRouteHeaderValue notifyPostProcessorAfterProcess(DocumentRouteHeaderValue document, String nodeInstanceId, boolean successfullyProcessed) {
659 if (document == null) {
660
661 return null;
662 }
663 return notifyPostProcessorAfterProcess(document, nodeInstanceId, new AfterProcessEvent(document.getDocumentId(),document.getAppDocId(),nodeInstanceId,successfullyProcessed));
664 }
665
666
667
668
669
670 private DocumentRouteHeaderValue notifyPostProcessorAfterProcess(DocumentRouteHeaderValue document, String nodeInstanceId, AfterProcessEvent event) {
671 ProcessDocReport report = null;
672 try {
673 PostProcessor postProcessor = null;
674
675 if (!isRunPostProcessorLogic()) {
676 postProcessor = new DefaultPostProcessor();
677 } else {
678 postProcessor = document.getDocumentType().getPostProcessor();
679 }
680 report = postProcessor.afterProcess(event);
681 } catch (Exception e) {
682 throw new RouteManagerException("Problems contacting PostProcessor.",e);
683 }
684 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
685 if (!report.isSuccess()) {
686 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
687 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
688 }
689 return document;
690 }
691
692
693
694
695
696 public void initializeDocument(DocumentRouteHeaderValue document) {
697
698
699
700
701
702
703 RouteContext context = new RouteContext();
704 context.setDocument(document);
705 if (context.getEngineState() == null) {
706 context.setEngineState(new EngineState());
707 }
708 ProcessDefinitionBo process = document.getDocumentType().getPrimaryProcess();
709 if (process == null || process.getInitialRouteNode() == null) {
710 if (process == null) {
711 throw new IllegalDocumentTypeException("DocumentType '" + document.getDocumentType().getName() + "' has no primary process configured!");
712 }
713 return;
714 }
715 RouteNodeInstance nodeInstance = helper.getNodeFactory().createRouteNodeInstance(document.getDocumentId(), process.getInitialRouteNode());
716 nodeInstance.setActive(true);
717 helper.getNodeFactory().createBranch(KewApiConstants.PRIMARY_BRANCH_NAME, null, nodeInstance);
718 document.getInitialRouteNodeInstances().add(nodeInstance);
719 saveNode(context, nodeInstance);
720 }
721
722 private boolean isRunawayProcessDetected(EngineState engineState) throws NumberFormatException {
723 String maxNodesConstant = getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ALL_DETAIL_TYPE, KewApiConstants.MAX_NODES_BEFORE_RUNAWAY_PROCESS);
724 int maxNodes = (org.apache.commons.lang.StringUtils.isEmpty(maxNodesConstant)) ? 50 : Integer.valueOf(maxNodesConstant);
725 return engineState.getCompleteNodeInstances().size() > maxNodes;
726 }
727
728 protected RouteNodeService getRouteNodeService() {
729 return routeNodeService;
730 }
731
732 protected RouteHeaderService getRouteHeaderService() {
733 return routeHeaderService;
734 }
735
736 protected ParameterService getParameterService() {
737 return parameterService;
738 }
739
740 public void setRouteNodeService(RouteNodeService routeNodeService) {
741 this.routeNodeService = routeNodeService;
742 }
743
744 public void setRouteHeaderService(RouteHeaderService routeHeaderService) {
745 this.routeHeaderService = routeHeaderService;
746 }
747
748 public void setParameterService(ParameterService parameterService) {
749 this.parameterService = parameterService;
750 }
751 }