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