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(
444 document.getDocumentId());
445 boolean approved = false;
446 for (Iterator iter = requests.iterator(); iter.hasNext();) {
447 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
448 if (actionRequest.isApproveOrCompleteRequest() && actionRequest.isDone() &&
449 !document.getInitiatorWorkflowId().equals(actionRequest.getPrincipalId())) {
450 LOG.debug("Found at least one processed approve or completion request for someone other than"
451 + " the initiator so document can be approved");
452 approved = true;
453 break;
454 }
455 }
456 if (!approved) {
457 LOG.debug("Document requires at least one request and none are present");
458
459 throw new RouteManagerException("Document should have generated at least one approval or completion"
460 + " request for someone other than the initiator.");
461 }
462 }
463 }
464
465 private DocumentRouteHeaderValue notifyPostProcessor(RouteContext context, DocumentRouteStatusChange event) {
466 DocumentRouteHeaderValue document = context.getDocument();
467 if (context.isSimulation()) {
468 return document;
469 }
470 if (hasContactedPostProcessor(context, event)) {
471 return document;
472 }
473 String documentId = event.getDocumentId();
474 PerformanceLogger performanceLogger = new PerformanceLogger(documentId);
475 ProcessDocReport processReport = null;
476 PostProcessor postProc = null;
477 try {
478
479 if (!isRunPostProcessorLogic()) {
480 postProc = new DefaultPostProcessor();
481 } else {
482 postProc = document.getDocumentType().getPostProcessor();
483 }
484 } catch (Exception e) {
485 LOG.error("Error retrieving PostProcessor for document " + document.getDocumentId(), e);
486 throw new RouteManagerException("Error retrieving PostProcessor for document " + document.getDocumentId(), e);
487 }
488 try {
489 processReport = postProc.doRouteStatusChange(event);
490 } catch (Exception e) {
491 LOG.error("Error notifying post processor", e);
492 throw new RouteManagerException(KewApiConstants.POST_PROCESSOR_FAILURE_MESSAGE, e);
493 } finally {
494 performanceLogger.log("Time to notifyPostProcessor of event " + event.getDocumentEventCode() + ".");
495 }
496
497 if (!processReport.isSuccess()) {
498 LOG.warn("PostProcessor failed to process document: " + processReport.getMessage());
499 throw new RouteManagerException(KewApiConstants.POST_PROCESSOR_FAILURE_MESSAGE + processReport.getMessage());
500 }
501 return document;
502 }
503
504
505
506
507
508
509
510
511
512
513
514 private boolean hasContactedPostProcessor(RouteContext context, DocumentRouteStatusChange event) {
515
516
517 Branch rootBranch = context.getDocument().getRootBranch();
518 String key = null;
519 if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(event.getNewRouteStatus())) {
520 key = KewApiConstants.POST_PROCESSOR_PROCESSED_KEY;
521 } else if (KewApiConstants.ROUTE_HEADER_FINAL_CD.equals(event.getNewRouteStatus())) {
522 key = KewApiConstants.POST_PROCESSOR_FINAL_KEY;
523 } else {
524 return false;
525 }
526 BranchState branchState = null;
527 if (rootBranch != null) {
528 branchState = rootBranch.getBranchState(key);
529 } else {
530 return false;
531 }
532 if (branchState == null) {
533 branchState = new BranchState();
534 branchState.setKey(key);
535 branchState.setValue("true");
536 rootBranch.addBranchState(branchState);
537 saveBranch(context, rootBranch);
538 return false;
539 }
540 return "true".equals(branchState.getValue());
541 }
542
543
544
545
546
547
548
549
550 private DocumentRouteHeaderValue notifyPostProcessor(DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance, DocumentRouteLevelChange event) {
551 document = getRouteHeaderService().saveRouteHeader(document);
552 ProcessDocReport report = null;
553 try {
554 PostProcessor postProcessor = null;
555
556 if (!isRunPostProcessorLogic()) {
557 postProcessor = new DefaultPostProcessor();
558 } else {
559 postProcessor = document.getDocumentType().getPostProcessor();
560 }
561 report = postProcessor.doRouteLevelChange(event);
562 } catch (Exception e) {
563 LOG.warn("Problems contacting PostProcessor", e);
564 throw new RouteManagerException("Problems contacting PostProcessor: " + e.getMessage());
565 }
566 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
567 if (!report.isSuccess()) {
568 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
569 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
570 }
571 return document;
572 }
573
574
575
576
577
578 private DocumentRouteHeaderValue notifyPostProcessorBeforeProcess(DocumentRouteHeaderValue document, String nodeInstanceId) {
579 return notifyPostProcessorBeforeProcess(document, nodeInstanceId, new BeforeProcessEvent(document.getDocumentId(),document.getAppDocId(),nodeInstanceId));
580 }
581
582
583
584
585
586 private DocumentRouteHeaderValue notifyPostProcessorBeforeProcess(DocumentRouteHeaderValue document, String nodeInstanceId, BeforeProcessEvent event) {
587 ProcessDocReport report = null;
588 try {
589 PostProcessor postProcessor = null;
590
591 if (!isRunPostProcessorLogic()) {
592 postProcessor = new DefaultPostProcessor();
593 } else {
594 postProcessor = document.getDocumentType().getPostProcessor();
595 }
596 report = postProcessor.beforeProcess(event);
597 } catch (Exception e) {
598 LOG.warn("Problems contacting PostProcessor", e);
599 throw new RouteManagerException("Problems contacting PostProcessor: " + e.getMessage());
600 }
601 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
602 if (!report.isSuccess()) {
603 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
604 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
605 }
606 return document;
607 }
608
609 protected void lockAdditionalDocuments(DocumentRouteHeaderValue document) throws Exception {
610 DocumentLockingEvent lockingEvent = new DocumentLockingEvent(document.getDocumentId(), document.getAppDocId());
611
612 PostProcessor postProcessor = null;
613
614 if (!isRunPostProcessorLogic()) {
615 postProcessor = new DefaultPostProcessor();
616 } else {
617 postProcessor = document.getDocumentType().getPostProcessor();
618 }
619 List<String> documentIdsToLock = postProcessor.getDocumentIdsToLock(lockingEvent);
620 if (documentIdsToLock != null && !documentIdsToLock.isEmpty()) {
621 for (String documentId : documentIdsToLock) {
622 if ( LOG.isInfoEnabled() ) {
623 LOG.info("Aquiring additional lock on document " + documentId);
624 }
625 getRouteHeaderService().lockRouteHeader(documentId);
626 if ( LOG.isInfoEnabled() ) {
627 LOG.info("Aquired lock on document " + documentId);
628 }
629 }
630 }
631 }
632
633
634
635
636
637 private DocumentRouteHeaderValue notifyPostProcessorAfterProcess(DocumentRouteHeaderValue document, String nodeInstanceId, boolean successfullyProcessed) {
638 if (document == null) {
639
640 return null;
641 }
642 return notifyPostProcessorAfterProcess(document, nodeInstanceId, new AfterProcessEvent(document.getDocumentId(),document.getAppDocId(),nodeInstanceId,successfullyProcessed));
643 }
644
645
646
647
648
649 private DocumentRouteHeaderValue notifyPostProcessorAfterProcess(DocumentRouteHeaderValue document, String nodeInstanceId, AfterProcessEvent event) {
650 ProcessDocReport report = null;
651 try {
652 PostProcessor postProcessor = null;
653
654 if (!isRunPostProcessorLogic()) {
655 postProcessor = new DefaultPostProcessor();
656 } else {
657 postProcessor = document.getDocumentType().getPostProcessor();
658 }
659 report = postProcessor.afterProcess(event);
660 } catch (Exception e) {
661 throw new RouteManagerException("Problems contacting PostProcessor.",e);
662 }
663 document = getRouteHeaderService().getRouteHeader(document.getDocumentId());
664 if (!report.isSuccess()) {
665 LOG.error("PostProcessor rejected route level change::" + report.getMessage(), report.getProcessException());
666 throw new RouteManagerException("Route Level change failed in post processor::" + report.getMessage());
667 }
668 return document;
669 }
670
671
672
673
674
675 public void initializeDocument(DocumentRouteHeaderValue document) {
676
677
678
679
680
681
682 RouteContext context = new RouteContext();
683 context.setDocument(document);
684
685 if (context.getEngineState() == null) {
686 context.setEngineState(new EngineState());
687 }
688
689 ProcessDefinitionBo process = document.getDocumentType().getPrimaryProcess();
690
691 if (process == null) {
692 throw new IllegalDocumentTypeException("DocumentType '" + document.getDocumentType().getName() + "' has no primary process configured!");
693 }
694
695 if (process.getInitialRouteNode() != null) {
696 RouteNodeInstance nodeInstance = helper.getNodeFactory().createRouteNodeInstance(document.getDocumentId(), process.getInitialRouteNode());
697 nodeInstance.setActive(true);
698 helper.getNodeFactory().createBranch(KewApiConstants.PRIMARY_BRANCH_NAME, null, nodeInstance);
699 nodeInstance = saveNode(context, nodeInstance);
700 document.getInitialRouteNodeInstances().add(nodeInstance);
701 }
702 }
703
704 private boolean isRunawayProcessDetected(EngineState engineState) throws NumberFormatException {
705 String maxNodesConstant = getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ALL_DETAIL_TYPE, KewApiConstants.MAX_NODES_BEFORE_RUNAWAY_PROCESS);
706 int maxNodes = StringUtils.isEmpty(maxNodesConstant) ? 50 : Integer.valueOf(maxNodesConstant);
707 return engineState.getCompleteNodeInstances().size() > maxNodes;
708 }
709
710 protected RouteNodeService getRouteNodeService() {
711 return routeNodeService;
712 }
713
714 protected RouteHeaderService getRouteHeaderService() {
715 return routeHeaderService;
716 }
717
718 protected ParameterService getParameterService() {
719 if (parameterService == null) {
720 parameterService = CoreFrameworkServiceLocator.getParameterService();
721 }
722 return parameterService;
723 }
724
725 public void setRouteNodeService(RouteNodeService routeNodeService) {
726 this.routeNodeService = routeNodeService;
727 }
728
729 public void setRouteHeaderService(RouteHeaderService routeHeaderService) {
730 this.routeHeaderService = routeHeaderService;
731 }
732
733 public void setParameterService(ParameterService parameterService) {
734 this.parameterService = parameterService;
735 }
736 }