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