View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.actionrequest.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.commons.lang.ObjectUtils;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.log4j.Logger;
31  import org.kuali.rice.core.api.config.CoreConfigHelper;
32  import org.kuali.rice.core.api.exception.RiceRuntimeException;
33  import org.kuali.rice.core.api.config.property.ConfigContext;
34  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
35  import org.kuali.rice.kew.actionitem.ActionItem;
36  import org.kuali.rice.kew.actionlist.service.ActionListService;
37  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
38  import org.kuali.rice.kew.actionrequest.Recipient;
39  import org.kuali.rice.kew.actionrequest.dao.ActionRequestDAO;
40  import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
41  import org.kuali.rice.kew.api.KewApiServiceLocator;
42  import org.kuali.rice.kew.api.document.DocumentRefreshQueue;
43  import org.kuali.rice.kew.actiontaken.ActionTakenValue;
44  import org.kuali.rice.kew.actiontaken.service.ActionTakenService;
45  import org.kuali.rice.kew.api.action.ActionRequestPolicy;
46  import org.kuali.rice.kew.api.action.ActionRequestStatus;
47  import org.kuali.rice.kew.api.action.RecipientType;
48  import org.kuali.rice.kew.doctype.bo.DocumentType;
49  import org.kuali.rice.kew.engine.ActivationContext;
50  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
51  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
52  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
53  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
54  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
55  import org.kuali.rice.kew.routemodule.RouteModule;
56  import org.kuali.rice.kew.service.KEWServiceLocator;
57  import org.kuali.rice.kew.util.FutureRequestDocumentStateManager;
58  import org.kuali.rice.kew.api.KewApiConstants;
59  import org.kuali.rice.kew.util.PerformanceLogger;
60  import org.kuali.rice.kew.util.ResponsibleParty;
61  import org.kuali.rice.kim.api.group.Group;
62  import org.kuali.rice.kim.api.identity.principal.Principal;
63  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
64  import org.kuali.rice.krad.util.KRADConstants;
65  
66  
67  /**
68   * Default implementation of the {@link ActionRequestService}.
69   *
70   * @author Kuali Rice Team (rice.collab@kuali.org)
71   */
72  public class ActionRequestServiceImpl implements ActionRequestService {
73      private static final Logger LOG = Logger.getLogger(ActionRequestServiceImpl.class);
74  
75      private ActionRequestDAO actionRequestDAO;
76  
77      public ActionRequestValue findByActionRequestId(String actionRequestId) {
78          return getActionRequestDAO().getActionRequestByActionRequestId(actionRequestId);
79      }
80  
81      public Map<String, String> getActionsRequested(DocumentRouteHeaderValue routeHeader, String principalId, boolean completeAndApproveTheSame) {
82      	return getActionsRequested(principalId, routeHeader.getActionRequests(), completeAndApproveTheSame);
83      }
84      
85      /**
86       * Returns a Map of actions that are requested for the given principalId in the given list of action requests.
87       * @param principalId
88       * @param actionRequests
89       * @param completeAndApproveTheSame
90       * @return
91       */
92      protected Map<String, String> getActionsRequested(String principalId, List<ActionRequestValue> actionRequests, boolean completeAndApproveTheSame) {
93      	Map<String, String> actionsRequested = new HashMap<String, String>();
94          actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false");
95          actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false");
96          actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "false");
97          actionsRequested.put(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, "false");
98      	String topActionRequested = KewApiConstants.ACTION_REQUEST_FYI_REQ;
99          for (ActionRequestValue actionRequest : actionRequests) {
100             // we are getting the full list of requests here, so no need to look at role requests, if we did this then
101             // we could get a "false positive" for "all approve" roles where only part of the request graph is marked
102             // as "done"
103             if (!RecipientType.ROLE.getCode().equals(actionRequest.getRecipientTypeCd()) &&
104                     actionRequest.isRecipientRoutedRequest(principalId) && actionRequest.isActive()) {
105                 int actionRequestComparison = ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), topActionRequested, completeAndApproveTheSame);
106                 if (actionRequest.isFYIRequest() && actionRequestComparison >= 0) {
107                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "true");
108                 } else if (actionRequest.isAcknowledgeRequest() && actionRequestComparison >= 0) {
109                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "true");
110                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false");
111                     topActionRequested = actionRequest.getActionRequested();
112                 } else if (actionRequest.isApproveRequest() && actionRequestComparison >= 0) {
113                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "true");
114                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false");
115                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false");
116                     topActionRequested = actionRequest.getActionRequested();
117                 } else if (actionRequest.isCompleteRequst() && actionRequestComparison >= 0) {
118                 	actionsRequested.put(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, "true");
119                 	actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "false");
120                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false");
121                     actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false");
122                 	if (completeAndApproveTheSame) {
123                 		actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "true");
124                 	}
125                     topActionRequested = actionRequest.getActionRequested();
126                 }
127             }
128         }
129         return actionsRequested;
130     }
131 
132     public ActionRequestValue initializeActionRequestGraph(ActionRequestValue actionRequest,
133             DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance) {
134         if (actionRequest.getParentActionRequest() != null) {
135             LOG.warn("-->A non parent action request from doc " + document.getDocumentId());
136             actionRequest = KEWServiceLocator.getActionRequestService().getRoot(actionRequest);
137         }
138         propagatePropertiesToRequestGraph(actionRequest, document, nodeInstance);
139         return actionRequest;
140     }
141 
142     private void propagatePropertiesToRequestGraph(ActionRequestValue actionRequest, DocumentRouteHeaderValue document,
143             RouteNodeInstance nodeInstance) {
144         setPropertiesToRequest(actionRequest, document, nodeInstance);
145         for (ActionRequestValue actionRequestValue : actionRequest.getChildrenRequests())
146         {
147             propagatePropertiesToRequestGraph(actionRequestValue, document, nodeInstance);
148         }
149     }
150 
151     private void setPropertiesToRequest(ActionRequestValue actionRequest, DocumentRouteHeaderValue document,
152             RouteNodeInstance nodeInstance) {
153         actionRequest.setDocumentId(document.getDocumentId());
154         actionRequest.setDocVersion(document.getDocVersion());
155         actionRequest.setRouteLevel(document.getDocRouteLevel());
156         actionRequest.setNodeInstance(nodeInstance);
157         actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode());
158     }
159 
160 
161 
162     public void activateRequests(Collection actionRequests) {
163         activateRequests(actionRequests, new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION));
164     }
165 
166     public void activateRequests(Collection actionRequests, boolean simulate) {
167         activateRequests(actionRequests, new ActivationContext(simulate));
168     }
169 
170     public void activateRequests(Collection actionRequests, ActivationContext activationContext) {
171         if (actionRequests == null) {
172             return;
173         }
174         PerformanceLogger performanceLogger = null;
175         if ( LOG.isInfoEnabled() ) {
176         	performanceLogger = new PerformanceLogger();
177         }
178         activationContext.setGeneratedActionItems(new ArrayList<ActionItem>());
179         activateRequestsInternal(actionRequests, activationContext);
180         if (!activationContext.isSimulation()) {
181             KEWServiceLocator.getNotificationService().notify(ActionItem.to(activationContext.getGeneratedActionItems()));
182         }
183         if ( LOG.isInfoEnabled() ) {
184         	performanceLogger.log("Time to " + (activationContext.isSimulation() ? "simulate activation of " : "activate ")
185         			+ actionRequests.size() + " action requests.");
186         }
187         if ( LOG.isDebugEnabled() ) {
188         	LOG.debug("Generated " + activationContext.getGeneratedActionItems().size() + " action items.");
189         }
190     }
191 
192     public void activateRequest(ActionRequestValue actionRequest) {
193         activateRequests(Collections.singletonList(actionRequest), new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION));
194     }
195 
196     public void activateRequest(ActionRequestValue actionRequest, boolean simulate) {
197         activateRequests(Collections.singletonList(actionRequest), new ActivationContext(simulate));
198     }
199 
200     public void activateRequest(ActionRequestValue actionRequest, ActivationContext activationContext) {
201         activateRequests(Collections.singletonList(actionRequest), activationContext);
202     }
203 
204     public List activateRequestNoNotification(ActionRequestValue actionRequest, boolean simulate) {
205         return activateRequestNoNotification(actionRequest, new ActivationContext(simulate));
206     }
207 
208     public List activateRequestNoNotification(ActionRequestValue actionRequest, ActivationContext activationContext) {
209         activationContext.setGeneratedActionItems(new ArrayList<ActionItem>());
210         activateRequestInternal(actionRequest, activationContext);
211         return activationContext.getGeneratedActionItems();
212     }
213 
214     /**
215      * Internal helper method for activating a Collection of action requests and their children. Maintains an accumulator
216      * for generated action items.
217      * @param actionRequests
218      * @param activationContext
219      */
220     private void activateRequestsInternal(Collection actionRequests, ActivationContext activationContext) {
221         if (actionRequests == null) {
222             return;
223         }
224         List<?> actionRequestList = new ArrayList<Object>(actionRequests);
225         for (int i = 0; i < actionRequestList.size(); i++) {
226         	activateRequestInternal((ActionRequestValue) actionRequestList.get(i), activationContext);
227         }
228     }
229 
230     /**
231      * Internal helper method for activating a single action requests and it's children. Maintains an accumulator for
232      * generated action items.
233      */
234     private void activateRequestInternal(ActionRequestValue actionRequest, ActivationContext activationContext) {
235         PerformanceLogger performanceLogger = null;
236         if ( LOG.isInfoEnabled() ) {
237         	performanceLogger = new PerformanceLogger();
238         }
239         if (actionRequest == null || actionRequest.isActive() || actionRequest.isDeactivated()) {
240             return;
241         }
242         processResponsibilityId(actionRequest);
243         if (deactivateOnActionAlreadyTaken(actionRequest, activationContext)) {
244             return;
245         }
246         if (deactivateOnInactiveGroup(actionRequest, activationContext)) {
247             return;
248         }
249         if (deactivateOnEmptyGroup(actionRequest, activationContext)) {
250         	return;
251         }
252         actionRequest.setStatus(ActionRequestStatus.ACTIVATED.getCode());
253         if (!activationContext.isSimulation()) {
254             saveActionRequest(actionRequest);
255             activationContext.getGeneratedActionItems().addAll(generateActionItems(actionRequest, activationContext));
256         }
257         activateRequestsInternal(actionRequest.getChildrenRequests(), activationContext);
258         activateRequestInternal(actionRequest.getParentActionRequest(), activationContext);
259         if ( LOG.isInfoEnabled() ) {
260         	if (activationContext.isSimulation()) {
261                 performanceLogger.log("Time to simulate activation of request.");
262 	        } else {
263 	            performanceLogger.log("Time to activate action request with id " + actionRequest.getActionRequestId());
264 	        }
265         }
266     }
267 
268     /**
269      * Generates ActionItems for the given ActionRequest and returns the List of generated Action Items.
270      *
271      * @param actionRequest
272      * @param activationContext
273      * @return the List of generated ActionItems
274      */
275     private List<ActionItem> generateActionItems(ActionRequestValue actionRequest, ActivationContext activationContext) {
276     	if ( LOG.isDebugEnabled() ) {
277     		LOG.debug("generating the action items for request " + actionRequest.getActionRequestId());
278     	}
279         List<ActionItem> actionItems = new ArrayList<ActionItem>();
280         if (!actionRequest.isPrimaryDelegator()) {
281             if (actionRequest.isGroupRequest()) {
282                 List<String> principalIds =  KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId());
283                 actionItems.addAll(createActionItemsForPrincipals(actionRequest, principalIds));
284             } else if (actionRequest.isUserRequest()) {
285                 ActionItem actionItem = getActionListService().createActionItemForActionRequest(actionRequest);
286                 actionItems.add(actionItem);
287             }
288         }
289         if (!activationContext.isSimulation()) {
290             for (ActionItem actionItem: actionItems) {
291             	if ( LOG.isDebugEnabled() ) {
292             		LOG.debug("Saving action item: " + actionItems);
293             	}
294                 getActionListService().saveActionItem(actionItem);
295             }
296         } else {
297         	actionRequest.getSimulatedActionItems().addAll(actionItems);
298         }
299         return actionItems;
300     }
301 
302     private List<ActionItem> createActionItemsForPrincipals(ActionRequestValue actionRequest, List<String> principalIds) {
303         List<ActionItem> actionItems = new ArrayList<ActionItem>();
304         for (String principalId: principalIds) {
305 
306             ActionItem actionItem = getActionListService().createActionItemForActionRequest(actionRequest);
307             actionItem.setPrincipalId(principalId);
308             actionItem.setRoleName(actionRequest.getQualifiedRoleName());
309 
310             //KULRICE-3307 Prevent workflow from attempting to activate requests for null principals
311             String ignoreUnknownPrincipalIdsValue = ConfigContext.getCurrentContextConfig().getProperty(KewApiConstants.WORKFLOW_ACTION_IGNORE_UNKOWN_PRINCIPAL_IDS);
312             boolean ignoreUnknownPrincipalIds = Boolean.parseBoolean(ignoreUnknownPrincipalIdsValue);
313 
314             if(principalId==null && ignoreUnknownPrincipalIds)
315             {
316                 LOG.warn("Ignoring action item with actionRequestID of " + actionRequest.getActionRequestId()  + " due to null principalId.");
317             }
318             else
319             {
320                 if(principalId==null)
321                 {
322                     IllegalArgumentException e = new IllegalArgumentException("Exception thrown when trying to add action item with null principalId");
323                     LOG.error(e);
324                     throw e;
325                 }
326                 else
327                 {
328                     actionItems.add(actionItem);
329                 }
330             }
331         }
332         return actionItems;
333     }
334 
335     private void processResponsibilityId(ActionRequestValue actionRequest) {
336     	if (actionRequest.getResolveResponsibility()) {
337 	        String responsibilityId = actionRequest.getResponsibilityId();
338 	        try {
339 	            RouteModule routeModule = KEWServiceLocator.getRouteModuleService().findRouteModule(actionRequest);
340 	            if (responsibilityId != null && actionRequest.isRouteModuleRequest()) {
341 	            	if ( LOG.isDebugEnabled() ) {
342 	            		LOG.debug("Resolving responsibility id for action request id=" + actionRequest.getActionRequestId()
343 	                        + " and responsibility id=" + actionRequest.getResponsibilityId());
344 	            	}
345 	                ResponsibleParty responsibleParty = routeModule.resolveResponsibilityId(actionRequest.getResponsibilityId());
346 	                if (responsibleParty == null) {
347 	                    return;
348 	                }
349 	                if (responsibleParty.getPrincipalId() != null) {
350 	                    Principal user = KimApiServiceLocator.getIdentityService()
351 	                            .getPrincipal(responsibleParty.getPrincipalId());
352 	                    actionRequest.setPrincipalId(user.getPrincipalId());
353 	                } else if (responsibleParty.getGroupId() != null) {
354 	                	actionRequest.setGroupId(responsibleParty.getGroupId());
355 	                } else if (responsibleParty.getRoleName() != null) {
356 	                    actionRequest.setRoleName(responsibleParty.getRoleName());
357 	                }
358 	            }
359 	        } catch (Exception e) {
360 	            LOG.error("Exception thrown when trying to resolve responsibility id " + responsibilityId, e);
361 	            throw new RuntimeException(e);
362 	        }
363     	}
364     }
365 
366     protected boolean deactivateOnActionAlreadyTaken(ActionRequestValue actionRequestToActivate,
367             ActivationContext activationContext) {
368 
369         FutureRequestDocumentStateManager futureRequestStateMngr = null;
370 
371         if (actionRequestToActivate.isGroupRequest()) {
372             futureRequestStateMngr = new FutureRequestDocumentStateManager(actionRequestToActivate.getRouteHeader(), actionRequestToActivate.getGroup());
373         } else if (actionRequestToActivate.isUserRequest()) {
374             futureRequestStateMngr = new FutureRequestDocumentStateManager(actionRequestToActivate.getRouteHeader(), actionRequestToActivate.getPrincipalId());
375         } else {
376             return false;
377         }
378 
379         if (futureRequestStateMngr.isReceiveFutureRequests()) {
380             return false;
381         }
382         if (!actionRequestToActivate.getForceAction() || futureRequestStateMngr.isDoNotReceiveFutureRequests()) {
383             ActionTakenValue previousActionTaken = null;
384             if (!activationContext.isSimulation()) {
385                 previousActionTaken = getActionTakenService().getPreviousAction(actionRequestToActivate);
386             } else {
387                 previousActionTaken = getActionTakenService().getPreviousAction(actionRequestToActivate,
388                         activationContext.getSimulatedActionsTaken());
389             }
390             if (previousActionTaken != null) {
391                 if ( LOG.isDebugEnabled() ) {
392                 	LOG.debug("found a satisfying action taken so setting this request done.  Action Request Id "
393                             + actionRequestToActivate.getActionRequestId());
394                 }
395                 // set up the delegation for an action taken if this is a delegate request and the delegate has
396                 // already taken action.
397                 if (!previousActionTaken.isForDelegator() && actionRequestToActivate.getParentActionRequest() != null) {
398                     previousActionTaken.setDelegator(actionRequestToActivate.getParentActionRequest().getRecipient());
399                     if (!activationContext.isSimulation()) {
400                         getActionTakenService().saveActionTaken(previousActionTaken);
401                     }
402                 }
403                 deactivateRequest(previousActionTaken, actionRequestToActivate, null, activationContext);
404                 return true;
405             }
406         }
407         if ( LOG.isDebugEnabled() ) {
408         	LOG.debug("Forcing action for action request " + actionRequestToActivate.getActionRequestId());
409         }
410         return false;
411     }
412     
413     /**
414      * Checks if the action request which is being activated has a group with no members.  If this is the case then it will immediately
415      * initiate de-activation on the request since a group with no members will result in no action items being generated so should be
416      * effectively skipped.
417      */
418     protected boolean deactivateOnEmptyGroup(ActionRequestValue actionRequestToActivate, ActivationContext activationContext) {
419     	if (actionRequestToActivate.isGroupRequest()) {
420     		 if (KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequestToActivate.getGroup().getId()).isEmpty()) {
421     			 deactivateRequest(null, actionRequestToActivate, null, activationContext);
422     			 return true;
423          	}
424     	}
425     	return false;
426     }
427 
428     /**
429      * Checks if the action request which is being activated is being assigned to an inactive group.  If this is the case and if the FailOnInactiveGroup 
430      * policy is set to false then it will immediately initiate de-activation on the request
431      */
432     protected boolean deactivateOnInactiveGroup(ActionRequestValue actionRequestToActivate, ActivationContext activationContext) {
433         if (actionRequestToActivate.isGroupRequest()) {
434             if (!actionRequestToActivate.getGroup().isActive() && !actionRequestToActivate.getRouteHeader().getDocumentType().getFailOnInactiveGroup().getPolicyValue()) {
435                 deactivateRequest(null, actionRequestToActivate, null, activationContext);
436                 return true;
437             }
438         }
439         return false;
440     }
441     
442     public void deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest) {
443         deactivateRequest(actionTaken, actionRequest, null, new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION));
444     }
445 
446     public void deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest, boolean simulate) {
447         deactivateRequest(actionTaken, actionRequest, null, new ActivationContext(simulate));
448     }
449 
450     public void deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest,
451             ActivationContext activationContext) {
452         deactivateRequest(actionTaken, actionRequest, null, activationContext);
453     }
454 
455     public void deactivateRequests(ActionTakenValue actionTaken, List actionRequests) {
456         deactivateRequests(actionTaken, actionRequests, null,
457                 new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION));
458     }
459 
460     public void deactivateRequests(ActionTakenValue actionTaken, List actionRequests, boolean simulate) {
461         deactivateRequests(actionTaken, actionRequests, null, new ActivationContext(simulate));
462     }
463 
464     public void deactivateRequests(ActionTakenValue actionTaken, List actionRequests, ActivationContext activationContext) {
465         deactivateRequests(actionTaken, actionRequests, null, activationContext);
466     }
467 
468     private void deactivateRequests(ActionTakenValue actionTaken, Collection actionRequests,
469             ActionRequestValue deactivationRequester, ActivationContext activationContext) {
470         if (actionRequests == null) {
471             return;
472         }
473         for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
474             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
475             deactivateRequest(actionTaken, actionRequest, deactivationRequester, activationContext);
476         }
477     }
478 
479     private void deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest,
480             ActionRequestValue deactivationRequester, ActivationContext activationContext) {
481         if (actionRequest == null || actionRequest.isDeactivated()
482                 || haltForAllApprove(actionRequest, deactivationRequester)) {
483             return;
484         }
485         actionRequest.setStatus(ActionRequestStatus.DONE.getCode());
486         actionRequest.setActionTaken(actionTaken);
487         if (actionTaken != null) {
488             actionTaken.getActionRequests().add(actionRequest);
489         }
490         if (!activationContext.isSimulation()) {
491             getActionRequestDAO().saveActionRequest(actionRequest);
492             deleteActionItems(actionRequest);
493         }
494         deactivateRequests(actionTaken, actionRequest.getChildrenRequests(), actionRequest, activationContext);
495         deactivateRequest(actionTaken, actionRequest.getParentActionRequest(), actionRequest, activationContext);
496     }
497 
498     /**
499      * Returns true if we are dealing with an 'All Approve' request, the requester of the deactivation is a child of the
500      * 'All Approve' request, and all of the children have not been deactivated. If all of the children are already
501      * deactivated or a non-child request initiated deactivation, then this method returns false. false otherwise.
502      * @param actionRequest
503      * @param deactivationRequester
504      * @return
505      */
506     private boolean haltForAllApprove(ActionRequestValue actionRequest, ActionRequestValue deactivationRequester) {
507         if (ActionRequestPolicy.ALL.getCode().equals(actionRequest.getApprovePolicy())
508                 && actionRequest.hasChild(deactivationRequester)) {
509             boolean allDeactivated = true;
510             for (ActionRequestValue childRequest : actionRequest.getChildrenRequests())
511             {
512                 if (!(allDeactivated = childRequest.isDeactivated()))
513                 {
514                     return true;
515                 }
516             }
517         }
518         return false;
519     }
520 
521     public List<ActionRequestValue> getRootRequests(Collection<ActionRequestValue> actionRequests) {
522     	Set<ActionRequestValue> unsavedRequests = new HashSet<ActionRequestValue>();
523     	Map<String, ActionRequestValue> requestMap = new HashMap<String, ActionRequestValue>();
524     	for (ActionRequestValue actionRequest1 : actionRequests)
525     	{
526     		ActionRequestValue actionRequest = (ActionRequestValue) actionRequest1;
527     		ActionRequestValue rootRequest = getRoot(actionRequest);
528     		if (rootRequest.getActionRequestId() != null)
529     		{
530     			requestMap.put(rootRequest.getActionRequestId(), rootRequest);
531     		} else
532     		{
533     			unsavedRequests.add(rootRequest);
534     		}
535     	}
536     	List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>();
537     	requests.addAll(requestMap.values());
538     	requests.addAll(unsavedRequests);
539     	return requests;
540     }
541 
542     public ActionRequestValue getRoot(ActionRequestValue actionRequest) {
543         if (actionRequest == null) {
544             return null;
545         }
546         if (actionRequest.getParentActionRequest() != null) {
547             return getRoot(actionRequest.getParentActionRequest());
548         }
549         return actionRequest;
550     }
551     
552     /**
553      * Returns all pending requests for a given routing identity
554      * @param documentId the id of the document header being routed
555      * @return a List of all pending ActionRequestValues for the document
556      */
557     public List<ActionRequestValue> findAllPendingRequests(String documentId) {
558     	ActionRequestDAO arDAO = getActionRequestDAO();
559         List<ActionRequestValue> pendingArs = arDAO.findByStatusAndDocId(ActionRequestStatus.ACTIVATED.getCode(), documentId);
560         return pendingArs;
561     }
562 
563     public List findAllValidRequests(String principalId, String documentId, String requestCode) {
564         ActionRequestDAO arDAO = getActionRequestDAO();
565         Collection pendingArs = arDAO.findByStatusAndDocId(ActionRequestStatus.ACTIVATED.getCode(), documentId);
566         return findAllValidRequests(principalId, pendingArs, requestCode);
567     }
568 
569     public List findAllValidRequests(String principalId, Collection actionRequests, String requestCode) {
570         List matchedArs = new ArrayList();
571         List<String> arGroups = KimApiServiceLocator.getGroupService().getGroupIdsByPrincipalId(principalId);
572         return filterActionRequestsByCode((List<ActionRequestValue>)actionRequests, principalId, arGroups, requestCode);
573     }
574     
575     /**
576 	 * Filters action requests based on if they occur after the given requestCode, and if they relate to 
577 	 * the given principal
578 	 * @param actionRequests the List of ActionRequestValues to filter
579 	 * @param principalId the id of the principal to find active requests for
580 	 * @param principalGroupIds List of group ids that the principal belongs to
581 	 * @param requestCode the request code for all ActionRequestValues to be after
582 	 * @return the filtered List of ActionRequestValues
583 	 */
584 	public List<ActionRequestValue> filterActionRequestsByCode(List<ActionRequestValue> actionRequests, String principalId, List<String> principalGroupIds, String requestCode) {
585 		List<ActionRequestValue> filteredActionRequests = new ArrayList<ActionRequestValue>();
586 		
587 		List<String> arGroups = null;
588         for (ActionRequestValue ar : actionRequests) {
589             if (ActionRequestValue.compareActionCode(ar.getActionRequested(), requestCode, true) > 0) {
590                 continue;
591             }
592             if (ar.isUserRequest() && principalId.equals(ar.getPrincipalId())) {
593             	filteredActionRequests.add(ar);
594             } else if (ar.isGroupRequest() && principalGroupIds != null && !principalGroupIds.isEmpty()) {
595             	for (String groupId : principalGroupIds) {
596             		if (groupId.equals(ar.getGroupId())) {
597             			filteredActionRequests.add(ar);
598             		}
599             	}
600             }
601         }
602 		
603 		return filteredActionRequests;
604 	}
605 
606     public void updateActionRequestsForResponsibilityChange(Set<String> responsibilityIds) {
607     	PerformanceLogger performanceLogger = null;
608     	if ( LOG.isInfoEnabled() ) {
609     		performanceLogger = new PerformanceLogger();
610     	}
611         Collection documentsAffected = getRouteHeaderService().findPendingByResponsibilityIds(responsibilityIds);
612         String cacheWaitValue = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.RULE_DETAIL_TYPE, KewApiConstants.RULE_CACHE_REQUEUE_DELAY);
613         Long cacheWait = KewApiConstants.DEFAULT_CACHE_REQUEUE_WAIT_TIME;
614         if (!org.apache.commons.lang.StringUtils.isEmpty(cacheWaitValue)) {
615             try {
616                 cacheWait = Long.valueOf(cacheWaitValue);
617             } catch (NumberFormatException e) {
618                 LOG.warn("Cache wait time is not a valid number: " + cacheWaitValue);
619             }
620         }
621         if ( LOG.isInfoEnabled() ) {
622         	LOG.info("Scheduling requeue of " + documentsAffected.size() + " documents, affected by " + responsibilityIds.size()
623                     + " responsibility changes.  Installing a processing wait time of " + cacheWait
624                     + " milliseconds to avoid stale rule cache.");
625         }
626         for (Object aDocumentsAffected : documentsAffected)
627         {
628             String documentId = (String) aDocumentsAffected;
629 
630              String applicationId = null;
631              DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByDocumentId(documentId);
632                     
633              if (documentType != null) {
634                 applicationId = documentType.getApplicationId();
635              }
636 
637             if (applicationId == null)
638             {
639                 applicationId = CoreConfigHelper.getApplicationId();
640             }
641             if(documentType.getRegenerateActionRequestsOnChange().getPolicyValue()) {
642                 DocumentRefreshQueue documentRequeuer = KewApiServiceLocator.getDocumentRequeuerService(applicationId,
643                         documentId, cacheWait);
644                 documentRequeuer.refreshDocument(documentId);
645             }
646         }
647         if ( LOG.isInfoEnabled() ) {
648         	performanceLogger.log("Time to updateActionRequestsForResponsibilityChange");
649         }
650     }
651 
652     /**
653      * Deletes an action request and all of its action items following the graph down through the action request's
654      * children. This method should be invoked on a top-level action request.
655      */
656     public void deleteActionRequestGraph(ActionRequestValue actionRequest) {
657         deleteActionItems(actionRequest);
658         if (actionRequest.getActionTakenId() != null) {
659             ActionTakenValue actionTaken = getActionTakenService().findByActionTakenId(actionRequest.getActionTakenId());
660 
661             if(actionTaken != null){//iu patch
662             getActionTakenService().delete(actionTaken);
663             }//iu patch
664            
665         }
666         getActionRequestDAO().delete(actionRequest.getActionRequestId());
667         for (ActionRequestValue child: actionRequest.getChildrenRequests()) {
668             deleteActionRequestGraph(child);
669         }
670     }
671 
672     /**
673      * Deletes the action items for the action request
674      * @param actionRequest the action request whose action items to delete
675      */
676     private void deleteActionItems(ActionRequestValue actionRequest) {
677     	List<ActionItem> actionItems = actionRequest.getActionItems();
678     	if ( LOG.isDebugEnabled() ) {
679     		LOG.debug("deleting " + actionItems.size() + " action items for action request: " + actionRequest);
680     	}
681         for (ActionItem actionItem: actionItems) {
682         	if ( LOG.isDebugEnabled() ) {
683         		LOG.debug("deleting action item: " + actionItem);
684         	}
685             getActionListService().deleteActionItem(actionItem);
686         }
687     }
688 
689 
690     public List<ActionRequestValue> findByDocumentIdIgnoreCurrentInd(String documentId) {
691         return getActionRequestDAO().findByDocumentIdIgnoreCurrentInd(documentId);
692     }
693 
694     public List<ActionRequestValue> findAllActionRequestsByDocumentId(String documentId) {
695         return getActionRequestDAO().findAllByDocId(documentId);
696     }
697 
698     public List<ActionRequestValue> findAllRootActionRequestsByDocumentId(String documentId) {
699         return getActionRequestDAO().findAllRootByDocId(documentId);
700     }
701 
702     public List<ActionRequestValue> findPendingByActionRequestedAndDocId(String actionRequestedCd, String documentId) {
703         return getActionRequestDAO().findPendingByActionRequestedAndDocId(actionRequestedCd, documentId);
704     }
705 
706     /**
707      * @see org.kuali.rice.kew.actionrequest.service.ActionRequestService#getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(java.lang.String, java.lang.String)
708      */
709     public List<String> getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(String actionRequestedCd, String documentId) {
710     	List<String> principalIds = new ArrayList<String>();
711     	List<ActionRequestValue> actionRequests = findPendingByActionRequestedAndDocId(actionRequestedCd, documentId);
712 		for(ActionRequestValue actionRequest: actionRequests){
713 			if(actionRequest.isUserRequest()){
714 				principalIds.add(actionRequest.getPrincipalId());
715 			} else if(actionRequest.isGroupRequest()){
716 				principalIds.addAll(
717 						KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId()));
718 			}
719 		}
720     	return principalIds;
721     }
722 
723     public List<ActionRequestValue> findPendingByDocIdAtOrBelowRouteLevel(String documentId, Integer routeLevel) {
724         return getActionRequestDAO().findPendingByDocIdAtOrBelowRouteLevel(documentId, routeLevel);
725     }
726 
727     public List<ActionRequestValue> findPendingRootRequestsByDocId(String documentId) {
728         return getRootRequests(findPendingByDoc(documentId));
729     }
730 
731     public List<ActionRequestValue> findPendingRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) {
732         return getActionRequestDAO().findPendingRootRequestsByDocIdAtRouteNode(documentId, nodeInstanceId);
733     }
734 
735     public List<ActionRequestValue> findRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) {
736         return getActionRequestDAO().findRootRequestsByDocIdAtRouteNode(documentId, nodeInstanceId);
737     }
738 
739     public List<ActionRequestValue> findPendingRootRequestsByDocIdAtOrBelowRouteLevel(String documentId, Integer routeLevel) {
740         return getActionRequestDAO().findPendingRootRequestsByDocIdAtOrBelowRouteLevel(documentId, routeLevel);
741     }
742 
743     public List<ActionRequestValue> findPendingRootRequestsByDocIdAtRouteLevel(String documentId, Integer routeLevel) {
744         return getActionRequestDAO().findPendingRootRequestsByDocIdAtRouteLevel(documentId, routeLevel);
745     }
746 
747     public List<ActionRequestValue> findPendingRootRequestsByDocumentType(String documentTypeId) {
748         return getActionRequestDAO().findPendingRootRequestsByDocumentType(documentTypeId);
749     }
750 
751     public void saveActionRequest(ActionRequestValue actionRequest) {
752         if (actionRequest.isGroupRequest()) {
753              Group group = actionRequest.getGroup();
754              if (group == null)  {
755                  throw new RiceRuntimeException("Attempted to save an action request with a non-existent group.");
756              }
757              if (!group.isActive() && actionRequest.getRouteHeader().getDocumentType().getFailOnInactiveGroup().getPolicyValue()) {
758         		throw new RiceRuntimeException("Attempted to save an action request with an inactive group.");
759         	}
760         }
761         getActionRequestDAO().saveActionRequest(actionRequest);
762     }
763 
764     public List<ActionRequestValue> findPendingByDoc(String documentId) {
765         return getActionRequestDAO().findAllPendingByDocId(documentId);
766     }
767 
768     public List<ActionRequestValue> findPendingByDocRequestCdRouteLevel(String documentId, String requestCode, Integer routeLevel) {
769         List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>();
770         for (Object object : getActionRequestDAO().findAllPendingByDocId(documentId))
771         {
772             ActionRequestValue actionRequest = (ActionRequestValue) object;
773             if (ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), requestCode, true) > 0)
774             {
775                 continue;
776             }
777             if (actionRequest.getRouteLevel().intValue() == routeLevel.intValue())
778             {
779                 requests.add(actionRequest);
780             }
781         }
782         return requests;
783     }
784 
785     public List<ActionRequestValue> findPendingByDocRequestCdNodeName(String documentId, String requestCode, String nodeName) {
786         List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>();
787         for (Object object : getActionRequestDAO().findAllPendingByDocId(documentId))
788         {
789             ActionRequestValue actionRequest = (ActionRequestValue) object;
790             if (ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), requestCode, true) > 0)
791             {
792                 continue;
793             }
794             if (actionRequest.getNodeInstance() != null && actionRequest.getNodeInstance().getName().equals(nodeName))
795             {
796                 requests.add(actionRequest);
797             }
798         }
799         return requests;
800     }
801 
802     public List findActivatedByGroup(String groupId) {
803         return getActionRequestDAO().findActivatedByGroup(groupId);
804     }
805 
806     private ActionListService getActionListService() {
807         return (ActionListService) KEWServiceLocator.getActionListService();
808     }
809 
810     private ActionTakenService getActionTakenService() {
811         return (ActionTakenService) KEWServiceLocator.getActionTakenService();
812     }
813 
814     public ActionRequestDAO getActionRequestDAO() {
815         return actionRequestDAO;
816     }
817 
818     public void setActionRequestDAO(ActionRequestDAO actionRequestDAO) {
819         this.actionRequestDAO = actionRequestDAO;
820     }
821 
822     private RouteHeaderService getRouteHeaderService() {
823         return (RouteHeaderService) KEWServiceLocator.getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV);
824     }
825 
826     public List<ActionRequestValue> findByStatusAndDocId(String statusCd, String documentId) {
827         return getActionRequestDAO().findByStatusAndDocId(statusCd, documentId);
828     }
829 
830     public void alterActionRequested(List actionRequests, String actionRequestCd) {
831         for (Object actionRequest1 : actionRequests)
832         {
833             ActionRequestValue actionRequest = (ActionRequestValue) actionRequest1;
834 
835             actionRequest.setActionRequested(actionRequestCd);
836             for (ActionItem item : actionRequest.getActionItems())
837             {
838                 item.setActionRequestCd(actionRequestCd);
839             }
840 
841             saveActionRequest(actionRequest);
842         }
843     }
844 
845     // TODO this still won't work in certain cases when checking from the root
846     public boolean isDuplicateRequest(ActionRequestValue actionRequest) {
847         List<ActionRequestValue> requests = findAllRootActionRequestsByDocumentId(actionRequest.getDocumentId());
848         for (ActionRequestValue existingRequest : requests) {
849             if (existingRequest.getStatus().equals(ActionRequestStatus.DONE.getCode())
850                     && existingRequest.getRouteLevel().equals(actionRequest.getRouteLevel())
851                     && ObjectUtils.equals(existingRequest.getPrincipalId(), actionRequest.getPrincipalId())
852                     && ObjectUtils.equals(existingRequest.getGroupId(), actionRequest.getGroupId())
853                     && ObjectUtils.equals(existingRequest.getRoleName(), actionRequest.getRoleName())
854                     && ObjectUtils.equals(existingRequest.getQualifiedRoleName(), actionRequest.getQualifiedRoleName())
855                     && existingRequest.getActionRequested().equals(actionRequest.getActionRequested())) {
856                 return true;
857             }
858         }
859         return false;
860     }
861 
862     public Recipient findDelegator(List actionRequests) {
863         Recipient delegator = null;
864         String requestCode = KewApiConstants.ACTION_REQUEST_FYI_REQ;
865         for (Object actionRequest1 : actionRequests)
866         {
867             ActionRequestValue actionRequest = (ActionRequestValue) actionRequest1;
868             ActionRequestValue delegatorRequest = findDelegatorRequest(actionRequest);
869             if (delegatorRequest != null)
870             {
871                 if (ActionRequestValue.compareActionCode(delegatorRequest.getActionRequested(), requestCode, true) >= 0)
872                 {
873                     delegator = delegatorRequest.getRecipient();
874                     requestCode = delegatorRequest.getActionRequested();
875                 }
876             }
877         }
878         return delegator;
879     }
880 
881     public Recipient findDelegator(ActionRequestValue actionRequest) {
882         ActionRequestValue delegatorRequest = findDelegatorRequest(actionRequest);
883         Recipient delegator = null;
884         if (delegatorRequest != null) {
885             delegator = delegatorRequest.getRecipient();
886         }
887         return delegator;
888     }
889 
890     public ActionRequestValue findDelegatorRequest(ActionRequestValue actionRequest) {
891         ActionRequestValue parentRequest = actionRequest.getParentActionRequest();
892         if (parentRequest != null && !(parentRequest.isUserRequest() || parentRequest.isGroupRequest())) {
893             parentRequest = findDelegatorRequest(parentRequest);
894         }
895         return parentRequest;
896     }
897 
898     public void deleteByDocumentId(String documentId) {
899         actionRequestDAO.deleteByDocumentId(documentId);
900     }
901 
902     public void deleteByActionRequestId(String actionRequestId) {
903         actionRequestDAO.delete(actionRequestId);
904     }
905 
906     public void validateActionRequest(ActionRequestValue actionRequest) {
907         LOG.debug("Enter validateActionRequest(..)");
908         List<WorkflowServiceErrorImpl> errors = new ArrayList<WorkflowServiceErrorImpl>();
909 
910         String actionRequestCd = actionRequest.getActionRequested();
911         if (actionRequestCd == null || actionRequestCd.trim().equals("")) {
912             errors.add(new WorkflowServiceErrorImpl("ActionRequest cd null.", "actionrequest.actionrequestcd.empty",
913                     actionRequest.getActionRequestId().toString()));
914         } else if (!KewApiConstants.ACTION_REQUEST_CD.containsKey(actionRequestCd)) {
915             errors.add(new WorkflowServiceErrorImpl("ActionRequest cd invalid.", "actionrequest.actionrequestcd.invalid",
916                     actionRequest.getActionRequestId().toString()));
917         }
918 
919         String documentId = actionRequest.getDocumentId();
920         if (documentId == null || StringUtils.isEmpty(documentId)) {
921         	errors.add(new WorkflowServiceErrorImpl("ActionRequest Document id empty.", "actionrequest.documentid.empty",
922                     actionRequest.getActionRequestId().toString()));
923         } else if (getRouteHeaderService().getRouteHeader(documentId) == null) {
924             errors.add(new WorkflowServiceErrorImpl("ActionRequest Document id invalid.",
925                     "actionrequest.documentid.invalid", actionRequest.getActionRequestId().toString()));
926         }
927 
928         String actionRequestStatus = actionRequest.getStatus();
929         if (actionRequestStatus == null || actionRequestStatus.trim().equals("")) {
930             errors.add(new WorkflowServiceErrorImpl("ActionRequest status null.", "actionrequest.actionrequeststatus.empty",
931                     actionRequest.getActionRequestId().toString()));
932         } else if (ActionRequestStatus.fromCode(actionRequestStatus) == null) {
933             errors.add(new WorkflowServiceErrorImpl("ActionRequest status invalid.",
934                     "actionrequest.actionrequeststatus.invalid", actionRequest.getActionRequestId().toString()));
935         }
936 
937         if (actionRequest.getResponsibilityId() == null) {
938             errors.add(new WorkflowServiceErrorImpl("ActionRequest responsibility id null.",
939                     "actionrequest.responsibilityid.empty", actionRequest.getActionRequestId().toString()));
940         }
941 
942         Integer priority = actionRequest.getPriority();
943         if (priority == null) {
944             errors.add(new WorkflowServiceErrorImpl("ActionRequest priority null.", "actionrequest.priority.empty",
945                     actionRequest.getActionRequestId().toString()));
946         }
947 
948         // if(actionRequest.getRouteMethodName() == null || actionRequest.getRouteMethodName().trim().equals("")){
949         // errors.add(new WorkflowServiceErrorImpl("ActionRequest route method name null.",
950         // "actionrequest.routemethodname.empty", actionRequest.getActionRequestId().toString()));
951         // }
952 
953         Integer routeLevel = actionRequest.getRouteLevel();
954         if (routeLevel == null) {
955             errors.add(new WorkflowServiceErrorImpl("ActionRequest route level null.", "actionrequest.routelevel.empty",
956                     actionRequest.getActionRequestId().toString()));
957         } else if (routeLevel < -1) {
958             errors.add(new WorkflowServiceErrorImpl("ActionRequest route level invalid.",
959                     "actionrequest.routelevel.invalid", actionRequest.getActionRequestId().toString()));
960         }
961 
962         Integer version = actionRequest.getDocVersion();
963         if (version == null) {
964             errors.add(new WorkflowServiceErrorImpl("ActionRequest doc version null.", "actionrequest.docversion.empty",
965                     actionRequest.getActionRequestId().toString()));
966         }
967 
968         if (actionRequest.getCreateDate() == null) {
969             errors.add(new WorkflowServiceErrorImpl("ActionRequest create date null.", "actionrequest.createdate.empty",
970                     actionRequest.getActionRequestId().toString()));
971         }
972 
973         String recipientType = actionRequest.getRecipientTypeCd();
974         if (recipientType != null && !recipientType.trim().equals("")) {
975             if (recipientType.equals(KewApiConstants.WORKGROUP)) {
976                 String workgroupId = actionRequest.getGroupId();
977                 if (workgroupId == null) {
978                     errors.add(new WorkflowServiceErrorImpl("ActionRequest workgroup null.",
979                             "actionrequest.workgroup.empty", actionRequest.getActionRequestId().toString()));
980                 } else if (KimApiServiceLocator.getGroupService().getGroup(workgroupId) == null) {
981                     errors.add(new WorkflowServiceErrorImpl("ActionRequest workgroup invalid.",
982                             "actionrequest.workgroup.invalid", actionRequest.getActionRequestId().toString()));
983                 }
984 
985             }
986             if (recipientType.equals(KewApiConstants.PERSON)) {
987                 String principalId = actionRequest.getPrincipalId();
988                 if (principalId == null || principalId.trim().equals("")) {
989                     errors.add(new WorkflowServiceErrorImpl("ActionRequest person id null.", "actionrequest.persosn.empty",
990                             actionRequest.getActionRequestId().toString()));
991                 } else {
992                 	Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
993                 	if (principal == null) {
994                 		errors.add(new WorkflowServiceErrorImpl("ActionRequest person id invalid.",
995                 				"actionrequest.personid.invalid", actionRequest.getActionRequestId().toString()));
996                 	}
997                 }
998 
999                 if (recipientType.equals(KewApiConstants.ROLE)
1000                         && (actionRequest.getRoleName() == null || actionRequest.getRoleName().trim().equals(""))) {
1001                     errors.add(new WorkflowServiceErrorImpl("ActionRequest role name null.", "actionrequest.rolename.null",
1002                             actionRequest.getActionRequestId().toString()));
1003                 }
1004             }
1005             LOG.debug("Exit validateActionRequest(..) ");
1006             if (!errors.isEmpty()) {
1007                 throw new WorkflowServiceErrorException("ActionRequest Validation Error", errors);
1008             }
1009         }
1010     }
1011 
1012     public List getDelegateRequests(ActionRequestValue actionRequest) {
1013         List<ActionRequestValue> delegateRequests = new ArrayList<ActionRequestValue>();
1014         List requests = getTopLevelRequests(actionRequest);
1015         for (Object request : requests)
1016         {
1017             ActionRequestValue parentActionRequest = (ActionRequestValue) request;
1018             delegateRequests.addAll(parentActionRequest.getChildrenRequests());
1019         }
1020         return delegateRequests;
1021     }
1022 
1023     public List getTopLevelRequests(ActionRequestValue actionRequest) {
1024         List<ActionRequestValue> topLevelRequests = new ArrayList<ActionRequestValue>();
1025         if (actionRequest.isRoleRequest()) {
1026             topLevelRequests.addAll(actionRequest.getChildrenRequests());
1027         } else {
1028             topLevelRequests.add(actionRequest);
1029         }
1030         return topLevelRequests;
1031     }
1032 
1033     public boolean isValidActionRequestCode(String actionRequestCode) {
1034         return actionRequestCode != null && KewApiConstants.ACTION_REQUEST_CODES.containsKey(actionRequestCode);
1035     }
1036 
1037     public boolean doesPrincipalHaveRequest(String principalId, String documentId) {
1038         if (getActionRequestDAO().doesDocumentHaveUserRequest(principalId, documentId)) {
1039             return true;
1040         }
1041         // TODO since we only store the workgroup id for workgroup requests, if the user is in a workgroup that has a request
1042         // than we need get all the requests with workgroup ids and see if our user is in that group
1043         List<String> groupIds = getActionRequestDAO().getRequestGroupIds(documentId);
1044         for (String groupId : groupIds) {
1045             if (KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, groupId)) {
1046                 return true;
1047             }
1048         }
1049         return false;
1050     }
1051 
1052     @Override
1053     public ActionRequestValue getActionRequestForRole(String actionTakenId) {
1054         return getActionRequestDAO().getRoleActionRequestByActionTakenId(actionTakenId);
1055     }
1056 
1057 }