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