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