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