1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.engine.node;
17
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
27 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
28 import org.kuali.rice.kew.engine.RouteContext;
29 import org.kuali.rice.kew.engine.RouteHelper;
30 import org.kuali.rice.kew.exception.RouteManagerException;
31 import org.kuali.rice.kew.exception.WorkflowException;
32 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
33 import org.kuali.rice.kew.rule.FlexRM;
34 import org.kuali.rice.kew.rule.KRAMetaRuleEngine;
35 import org.kuali.rice.kew.rule.RuleExpressionResult;
36 import org.kuali.rice.kew.service.KEWServiceLocator;
37 import org.kuali.rice.kew.util.Utilities;
38
39
40
41
42
43
44
45 public class KRAMetaRuleNode extends IteratedRequestActivationNode {
46 private static String SUPPRESS_POLICY_ERRORS_KEY = "_suppressPolicyErrorsRequestActivationNode";
47
48 protected List<ActionRequestValue> generateUninitializedRequests(ActionRequestFactory arFactory, RouteContext context, RuleExpressionResult result) throws WorkflowException {
49 FlexRM flexRM = new FlexRM();
50 flexRM.makeActionRequests(arFactory, result.getResponsibilities(), context, result.getRule().getDefinition(), context.getDocument(), null, null);
51 return new ArrayList<ActionRequestValue>(arFactory.getRequestGraphs());
52 }
53
54 protected List<ActionRequestValue> initializeRequests(List<ActionRequestValue> requests, RouteContext context) {
55
56 List<ActionRequestValue> newRequests = new ArrayList<ActionRequestValue>();
57 for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
58 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
59 actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, context.getDocument(), context.getNodeInstance());
60 saveActionRequest(context, actionRequest);
61 newRequests.add(actionRequest);
62 }
63 return newRequests;
64 }
65
66 @Override
67 protected boolean generateNewRequests(boolean initial, RouteContext context, RouteHelper routeHelper)
68 throws WorkflowException, Exception {
69 RouteNodeInstance nodeInstance = context.getNodeInstance();
70 RouteNode nodeDef = nodeInstance.getRouteNode();
71
72
73 Map<String, String> cfg = Utilities.getKeyValueCollectionAsMap(nodeDef.getConfigParams());
74 String expression = cfg.get("expression");
75 if (StringUtils.isEmpty(expression)) {
76 throw new WorkflowException("No meta-rule expression supplied in node " + nodeDef);
77 }
78 KRAMetaRuleEngine engine = new KRAMetaRuleEngine(expression);
79
80
81 int curStatement = getCurStatement(nodeInstance);
82
83 engine.setCurStatement(curStatement);
84
85 if (engine.isDone()) {
86 return false;
87 }
88
89
90 RuleExpressionResult result = engine.processSingleStatement(context);
91 if (!result.isSuccess()) {
92 return false;
93 }
94
95 boolean suppressPolicyErrors = isSupressingPolicyErrors(context);
96 boolean pastFinalApprover = isPastFinalApprover(context.getDocument(), nodeInstance);
97
98
99
100 ActionRequestFactory arFactory = new ActionRequestFactory(context.getDocument(), context.getNodeInstance());
101 List<ActionRequestValue> requests = generateUninitializedRequests(arFactory, context, result);
102 requests = initializeRequests(requests, context);
103
104 if ((requests.isEmpty()) && nodeDef.getMandatoryRouteInd().booleanValue() && ! suppressPolicyErrors) {
105 LOG.warn("no requests generated for mandatory route - " + nodeDef.getRouteNodeName());
106 throw new RouteManagerException("No requests generated for mandatory route " + nodeDef.getRouteNodeName() + ":" + nodeDef.getRouteMethodName(), context);
107 }
108
109 boolean hasApproveRequest = false;
110 for (Iterator iter = requests.iterator(); iter.hasNext();) {
111 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
112 hasApproveRequest = actionRequest.isApproveOrCompleteRequest() || hasApproveRequest;
113 }
114
115 if (nodeDef.getFinalApprovalInd().booleanValue()) {
116
117 if (!hasApproveRequest && ! suppressPolicyErrors) {
118 throw new RuntimeException("No Approve Request generated after final approver");
119 }
120 } else if (pastFinalApprover) {
121
122 if (hasApproveRequest && ! suppressPolicyErrors) {
123 throw new RuntimeException("Approve Request generated after final approver");
124 }
125 }
126
127
128 nodeInstance.getNodeState("stmt").setValue(String.valueOf(curStatement + 1));
129 return !requests.isEmpty();
130 }
131
132
133
134
135
136 protected static int getCurStatement(RouteNodeInstance nodeInstance) {
137 int statement = 0;
138 NodeState nodeState = nodeInstance.getNodeState("stmt");
139 if (nodeState == null) {
140 nodeState = new NodeState();
141 nodeState.setKey("stmt");
142 nodeState.setNodeInstance(nodeInstance);
143 nodeInstance.addNodeState(nodeState);
144 }
145 if (StringUtils.isEmpty(nodeState.getValue())) {
146 nodeState.setValue("0");
147 } else {
148 statement = Integer.parseInt(nodeState.getValue());
149 }
150 return statement;
151 }
152
153 @Override
154 protected RequestFulfillmentCriteria getRequestFulfillmentCriteria(RouteContext routeContext) {
155 return super.getRequestFulfillmentCriteria(routeContext);
156 }
157
158
159
160
161
162
163
164 private Object getKey(RouteNodeInstance nodeInstance) {
165 String id = nodeInstance.getRouteNodeInstanceId();
166 return (id != null ? (Object) id : (Object) nodeInstance);
167 }
168
169
170
171
172
173 private boolean isPastFinalApprover(DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance) {
174 FinalApproverContext context = new FinalApproverContext();
175 List revokedNodeInstances = KEWServiceLocator.getRouteNodeService().getRevokedNodeInstances(document);
176 Set revokedNodeInstanceIds = new HashSet();
177 for (Iterator iterator = revokedNodeInstances.iterator(); iterator.hasNext(); ) {
178 RouteNodeInstance revokedNodeInstance = (RouteNodeInstance) iterator.next();
179 revokedNodeInstanceIds.add(revokedNodeInstance.getRouteNodeInstanceId());
180 }
181 isPastFinalApprover(nodeInstance.getPreviousNodeInstances(), context, revokedNodeInstanceIds);
182 return context.isPast;
183 }
184
185 private void isPastFinalApprover(List previousNodeInstances, FinalApproverContext context, Set revokedNodeInstanceIds) {
186 if (previousNodeInstances != null && !previousNodeInstances.isEmpty()) {
187 for (Iterator iterator = previousNodeInstances.iterator(); iterator.hasNext();) {
188 if (context.isPast) {
189 return;
190 }
191 RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
192 if (context.inspected.contains(getKey(nodeInstance))) {
193 continue;
194 } else {
195 context.inspected.add(getKey(nodeInstance));
196 }
197 if (Boolean.TRUE.equals(nodeInstance.getRouteNode().getFinalApprovalInd())) {
198
199
200
201 if (!revokedNodeInstanceIds.contains(nodeInstance.getRouteNodeInstanceId())) {
202 context.isPast = true;
203 }
204 return;
205 }
206 isPastFinalApprover(nodeInstance.getPreviousNodeInstances(), context, revokedNodeInstanceIds);
207 }
208 }
209 }
210 public static boolean isSupressingPolicyErrors(RouteContext routeContext) {
211 Boolean suppressPolicyErrors = (Boolean)routeContext.getParameters().get(SUPPRESS_POLICY_ERRORS_KEY);
212 if (suppressPolicyErrors == null || ! suppressPolicyErrors) {
213 return false;
214 }
215 return true;
216 }
217
218 private class FinalApproverContext {
219 public Set inspected = new HashSet();
220 public boolean isPast = false;
221 }
222
223 }