View Javadoc

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