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