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 org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.MDC;
20 import org.kuali.rice.core.api.criteria.Predicate;
21 import org.kuali.rice.core.api.criteria.QueryByCriteria;
22 import org.kuali.rice.kew.actionitem.ActionItem;
23 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24 import org.kuali.rice.kew.api.action.ActionRequestStatus;
25 import org.kuali.rice.kew.doctype.bo.DocumentType;
26 import org.kuali.rice.kew.engine.RouteContext;
27 import org.kuali.rice.kew.engine.RouteHelper;
28 import org.kuali.rice.kew.exception.ResourceUnavailableException;
29 import org.kuali.rice.kew.exception.RouteManagerException;
30 import org.kuali.rice.kew.exception.WorkflowException;
31 import org.kuali.rice.kew.role.RoleRouteModule;
32 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
33 import org.kuali.rice.kew.routemodule.RouteModule;
34 import org.kuali.rice.kew.service.KEWServiceLocator;
35 import org.kuali.rice.kew.util.ClassDumper;
36 import org.kuali.rice.kew.util.KEWConstants;
37 import org.kuali.rice.kew.util.PerformanceLogger;
38 import org.kuali.rice.kim.api.KimConstants;
39 import org.kuali.rice.kim.api.responsibility.Responsibility;
40 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
41 import org.kuali.rice.krad.util.KRADConstants;
42
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.Comparator;
46 import java.util.List;
47
48 import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
49 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
50
51
52
53
54
55
56
57
58
59 public class RoleNode extends RequestsNode {
60
61 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
62 .getLogger( RoleNode.class );
63
64 @Override
65 protected RouteModule getRouteModule(RouteContext context) throws Exception {
66 return new RoleRouteModule();
67 }
68
69
70
71
72 @Override
73 protected boolean processCustom(RouteContext routeContext, RouteHelper routeHelper) throws Exception {
74 DocumentRouteHeaderValue document = routeContext.getDocument();
75 RouteNodeInstance nodeInstance = routeContext.getNodeInstance();
76 RouteNode node = nodeInstance.getRouteNode();
77
78
79 if ( nodeInstance.isInitial() ) {
80 if ( LOG.isDebugEnabled() ) {
81 LOG.debug( "RouteHeader info inside routing loop\n"
82 + ClassDumper.dumpFields( routeContext.getDocument() ) );
83 LOG.debug( "Looking for new actionRequests - routeLevel: "
84 + node.getRouteNodeName() );
85 }
86 boolean suppressPolicyErrors = isSupressingPolicyErrors( routeContext );
87 List<ActionRequestValue> requests = getNewActionRequests( routeContext );
88
89
90
91
92
93
94 if ( requests.isEmpty() && !suppressPolicyErrors) {
95 Responsibility resp = getFirstResponsibilityWithMandatoryRouteFlag( document, node );
96 if ( resp != null ) {
97 throw new RouteManagerException( "No requests generated for KIM Responsibility-based mandatory route.\n" +
98 "Document Id: " + document.getDocumentId() + "\n" +
99 "DocumentType: " + document.getDocumentType().getName() + "\n" +
100 "Route Node: " + node.getRouteNodeName() + "\n" +
101 "Responsibility: " + resp,
102 routeContext );
103 }
104 }
105
106
107 if ( !suppressPolicyErrors ) {
108 verifyFinalApprovalRequest( document, requests, nodeInstance, routeContext );
109 }
110 }
111 return true;
112 }
113
114
115
116
117
118
119 protected Responsibility getFirstResponsibilityWithMandatoryRouteFlag( DocumentRouteHeaderValue document, RouteNode node ) {
120
121
122 DocumentType docType = document.getDocumentType();
123 while ( docType != null ) {
124 QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
125 Predicate p = and(
126 equal("template.namespaceCode", KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE),
127 equal("template.name", KEWConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME),
128 equal("active", "Y"),
129 equal("attributes[documentTypeName]", docType.getName()),
130 equal("attributes[routeNodeName]", node.getRouteNodeName())
131 );
132 builder.setPredicates(p);
133
134 List<Responsibility> responsibilities = KimApiServiceLocator.getResponsibilityService().findResponsibilities(builder.build()).getResults();
135
136
137 if ( !responsibilities.isEmpty() ) {
138
139 for ( Responsibility resp : responsibilities ) {
140 if ( Boolean.parseBoolean( resp.getAttributes().get( KimConstants.AttributeConstants.REQUIRED ) ) ) {
141 return resp;
142 }
143 }
144 return null;
145 }
146 docType = docType.getParentDocType();
147 }
148
149 return null;
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 @SuppressWarnings("unchecked")
171 public boolean activateRequests(RouteContext context, DocumentRouteHeaderValue document,
172 RouteNodeInstance nodeInstance) throws WorkflowException {
173 MDC.put( "docId", document.getDocumentId() );
174 PerformanceLogger performanceLogger = new PerformanceLogger( document.getDocumentId() );
175 List<ActionItem> generatedActionItems = new ArrayList<ActionItem>();
176 List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>();
177 if ( context.isSimulation() ) {
178 for ( ActionRequestValue ar : context.getDocument().getActionRequests() ) {
179
180
181
182 if ( ar.getCurrentIndicator()
183 && (ActionRequestStatus.INITIALIZED.getCode().equals( ar.getStatus() ) || ActionRequestStatus.ACTIVATED.getCode()
184 .equals( ar.getStatus() ))
185 && ar.getNodeInstance().getRouteNodeInstanceId().equals(
186 nodeInstance.getRouteNodeInstanceId() )
187 && ar.getParentActionRequest() == null ) {
188 requests.add( ar );
189 }
190 }
191 requests.addAll( context.getEngineState().getGeneratedRequests() );
192 } else {
193 requests = KEWServiceLocator.getActionRequestService()
194 .findPendingRootRequestsByDocIdAtRouteNode( document.getDocumentId(),
195 nodeInstance.getRouteNodeInstanceId() );
196 }
197 if ( LOG.isDebugEnabled() ) {
198 LOG.debug( "Pending Root Requests " + requests.size() );
199 }
200 boolean requestActivated = activateRequestsCustom( context, requests, generatedActionItems,
201 document, nodeInstance );
202
203
204
205
206 notify(context, generatedActionItems, nodeInstance);
207
208 performanceLogger.log( "Time to activate requests." );
209 return requestActivated;
210 }
211
212 protected static class RoleRequestSorter implements Comparator<ActionRequestValue> {
213 public int compare(ActionRequestValue ar1, ActionRequestValue ar2) {
214 int result = 0;
215
216 if ( ar1.getResponsibilityDesc() != null && ar2.getResponsibilityDesc() != null ) {
217 result = ar1.getResponsibilityDesc().compareTo( ar2.getResponsibilityDesc() );
218 }
219 if ( result != 0 ) return result;
220
221 result = ar1.getPriority().compareTo(ar2.getPriority());
222 if ( result != 0 ) return result;
223
224 result = ActionRequestValue.compareActionCode(ar1.getActionRequested(), ar2.getActionRequested(), true);
225 if ( result != 0 ) return result;
226
227 if ( (ar1.getActionRequestId() != null) && (ar2.getActionRequestId() != null) ) {
228 result = ar1.getActionRequestId().compareTo(ar2.getActionRequestId());
229 } else {
230
231 result = 0;
232 }
233 return result;
234 }
235 }
236 protected static final Comparator<ActionRequestValue> ROLE_REQUEST_SORTER = new RoleRequestSorter();
237
238
239 protected boolean activateRequestsCustom(RouteContext context,
240 List<ActionRequestValue> requests, List<ActionItem> generatedActionItems,
241 DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance)
242 throws WorkflowException {
243 Collections.sort( requests, ROLE_REQUEST_SORTER );
244 String activationType = nodeInstance.getRouteNode().getActivationType();
245 boolean isParallel = KEWConstants.ROUTE_LEVEL_PARALLEL.equals( activationType );
246 boolean requestActivated = false;
247 String groupToActivate = null;
248 Integer priorityToActivate = null;
249 for ( ActionRequestValue request : requests ) {
250
251
252 if ( requestActivated
253 && !isParallel
254 && (!context.isSimulation() || !context.getActivationContext()
255 .isActivateRequests()) ) {
256 break;
257 }
258 if ( request.getParentActionRequest() != null || request.getNodeInstance() == null ) {
259
260
261
262 continue;
263 }
264 if ( request.isApproveOrCompleteRequest() ) {
265 boolean thisRequestActivated = false;
266
267
268 if ( priorityToActivate == null ) {
269 priorityToActivate = request.getPriority();
270 }
271 if ( groupToActivate == null ) {
272 groupToActivate = request.getResponsibilityDesc();
273 }
274
275
276 if ( StringUtils.equals( groupToActivate, request.getResponsibilityDesc() )
277 && (
278 (priorityToActivate != null && request.getPriority() != null && priorityToActivate.equals(request.getPriority()))
279 || (priorityToActivate == null && request.getPriority() == null)
280 )
281 ) {
282
283
284 if ( request.isActive() ) {
285 requestActivated = true;
286 continue;
287 }
288 logProcessingMessage( request );
289 if ( LOG.isDebugEnabled() ) {
290 LOG.debug( "Activating request: " + request );
291 }
292
293 thisRequestActivated = activateRequest( context, request, nodeInstance,
294 generatedActionItems );
295 requestActivated |= thisRequestActivated;
296 }
297
298
299
300
301
302 if ( !thisRequestActivated && !requestActivated ) {
303 priorityToActivate = null;
304 groupToActivate = null;
305 }
306 } else {
307 logProcessingMessage( request );
308 if ( LOG.isDebugEnabled() ) {
309 LOG.debug( "Activating request: " + request );
310 }
311 requestActivated = activateRequest( context, request, nodeInstance,
312 generatedActionItems )
313 || requestActivated;
314 }
315 }
316 return requestActivated;
317 }
318 }