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.superuser.web;
17  
18  import java.util.Collection;
19  import java.util.Collections;
20  import java.util.Comparator;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  import javax.xml.namespace.QName;
27  
28  import org.apache.commons.lang.ArrayUtils;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.struts.action.ActionForm;
31  import org.apache.struts.action.ActionForward;
32  import org.apache.struts.action.ActionMapping;
33  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
34  import org.kuali.rice.kew.api.KewApiConstants;
35  import org.kuali.rice.kew.api.KewApiServiceLocator;
36  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
37  import org.kuali.rice.kew.api.action.ActionRequestType;
38  import org.kuali.rice.kew.api.action.AdHocRevoke;
39  import org.kuali.rice.kew.api.action.DocumentActionParameters;
40  import org.kuali.rice.kew.api.action.ReturnPoint;
41  import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
42  import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
43  import org.kuali.rice.kew.api.document.WorkflowDocumentService;
44  import org.kuali.rice.kew.api.exception.WorkflowException;
45  import org.kuali.rice.kew.doctype.bo.DocumentType;
46  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
47  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
48  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
49  import org.kuali.rice.kew.service.KEWServiceLocator;
50  import org.kuali.rice.kew.api.KewApiConstants;
51  import org.kuali.rice.kew.web.AppSpecificRouteRecipient;
52  import org.kuali.rice.kew.web.KewKualiAction;
53  import org.kuali.rice.kim.api.group.GroupService;
54  import org.kuali.rice.kim.api.identity.principal.Principal;
55  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
56  import org.kuali.rice.krad.UserSession;
57  import org.kuali.rice.krad.exception.ValidationException;
58  import org.kuali.rice.krad.util.GlobalVariables;
59  import org.kuali.rice.krad.util.KRADConstants;
60  import org.kuali.rice.krad.util.ObjectUtils;
61  import org.kuali.rice.ksb.api.KsbApiServiceLocator;
62  
63  /**
64   * A Struts Action which provides super user functionality.
65   * 
66   * @author Kuali Rice Team (rice.collab@kuali.org)
67   */
68  public class SuperUserAction extends KewKualiAction {
69      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SuperUserAction.class);
70      public static final String UNAUTHORIZED = "authorizationFailure";
71  
72      //public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
73      //	defaultDispatch(mapping, form, request, response);
74      //}
75  
76      @Override
77      public ActionForward execute(ActionMapping mapping, ActionForm form,
78              HttpServletRequest request, HttpServletResponse response)
79              throws Exception {
80          initForm(request, form);
81          return super.execute(mapping, form, request, response);
82      }
83  
84      @Override
85      public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request,
86              HttpServletResponse response) throws Exception {
87          ((SuperUserForm) form).getActionRequests().clear();
88          initForm(request, form);
89          return defaultDispatch(mapping, form, request, response);
90      }
91  
92      public ActionForward displaySuperUserDocument(ActionMapping mapping, ActionForm form, HttpServletRequest request,
93              HttpServletResponse response) throws Exception {
94          SuperUserForm superUserForm = (SuperUserForm) form;
95          superUserForm.setDocHandlerUrl(KewApiConstants.DOC_HANDLER_REDIRECT_PAGE + "?docId="
96                  + superUserForm.getDocumentId() + "&" + KewApiConstants.COMMAND_PARAMETER + "="
97                  + KewApiConstants.SUPERUSER_COMMAND);
98          return defaultDispatch(mapping, form, request, response);
99      }
100 
101     public ActionForward routeLevelApprove(ActionMapping mapping, ActionForm form, HttpServletRequest request,
102             HttpServletResponse response) throws Exception {
103         LOG.info("entering routeLevelApprove()...");
104         SuperUserForm superUserForm = (SuperUserForm) form;
105         String documentId = superUserForm.getRouteHeader().getDocumentId();
106         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
107         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
108                 .getPrincipalId(), superUserForm.getAnnotation());
109 
110         documentActions.superUserNodeApprove(parameters, superUserForm.isRunPostProcessorLogic(),
111                 superUserForm.getDestNodeName());
112         saveDocumentMessage("general.routing.superuser.routeLevelApproved", request, superUserForm.getDocumentId(),
113                 null);
114         LOG.info("exiting routeLevelApprove()...");
115         superUserForm.getActionRequests().clear();
116         initForm(request, form);
117         return defaultDispatch(mapping, form, request, response);
118     }
119 
120     public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request,
121             HttpServletResponse response) throws Exception {
122         LOG.info("entering approve() ...");
123         SuperUserForm superUserForm = (SuperUserForm) form;
124         String documentId = superUserForm.getRouteHeader().getDocumentId();
125         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
126         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
127                 .getPrincipalId(), superUserForm.getAnnotation());
128         documentActions.superUserBlanketApprove(parameters, superUserForm.isRunPostProcessorLogic());
129         saveDocumentMessage("general.routing.superuser.approved", request, superUserForm.getDocumentId(), null);
130         LOG.info("exiting approve() ...");
131         superUserForm.getActionRequests().clear();
132         initForm(request, form);
133         return defaultDispatch(mapping, form, request, response);
134     }
135 
136     public ActionForward disapprove(ActionMapping mapping, ActionForm form, HttpServletRequest request,
137             HttpServletResponse response) throws Exception {
138         LOG.info("entering disapprove() ...");
139         SuperUserForm superUserForm = (SuperUserForm) form;
140         String documentId = superUserForm.getRouteHeader().getDocumentId();
141         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
142         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
143                 .getPrincipalId(), superUserForm.getAnnotation());
144         documentActions.superUserDisapprove(parameters, superUserForm.isRunPostProcessorLogic());
145         saveDocumentMessage("general.routing.superuser.disapproved", request, superUserForm.getDocumentId(), null);
146         LOG.info("exiting disapprove() ...");
147         superUserForm.getActionRequests().clear();
148         initForm(request, form);
149         return defaultDispatch(mapping, form, request, response);
150     }
151 
152     public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request,
153             HttpServletResponse response) throws Exception {
154         LOG.info("entering cancel() ...");
155         SuperUserForm superUserForm = (SuperUserForm) form;
156         String documentId = superUserForm.getRouteHeader().getDocumentId();
157         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
158         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
159                 .getPrincipalId(), superUserForm.getAnnotation());
160         documentActions.superUserCancel(parameters, superUserForm.isRunPostProcessorLogic());
161         saveDocumentMessage("general.routing.superuser.canceled", request, superUserForm.getDocumentId(), null);
162         LOG.info("exiting cancel() ...");
163         superUserForm.getActionRequests().clear();
164         initForm(request, form);
165         return defaultDispatch(mapping, form, request, response);
166     }
167 
168     public ActionForward returnToPreviousNode(ActionMapping mapping, ActionForm form, HttpServletRequest request,
169             HttpServletResponse response) throws Exception {
170         LOG.info("entering returnToPreviousNode() ...");
171         SuperUserForm superUserForm = (SuperUserForm) form;
172         String documentId = superUserForm.getRouteHeader().getDocumentId();
173         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
174         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
175                 .getPrincipalId(), superUserForm.getAnnotation());
176         documentActions.superUserReturnToPreviousNode(parameters, superUserForm.isRunPostProcessorLogic(),
177                 ReturnPoint.create(superUserForm.getReturnDestNodeName()));
178         saveDocumentMessage("general.routing.returnedToPreviousNode", request, "document", superUserForm
179                 .getReturnDestNodeName().toString());
180         LOG.info("exiting returnToPreviousRouteLevel() ...");
181         superUserForm.getActionRequests().clear();
182         initForm(request, form);
183         return defaultDispatch(mapping, form, request, response);
184     }
185 
186     public ActionForward actionRequestApprove(ActionMapping mapping, ActionForm form, HttpServletRequest request,
187             HttpServletResponse response) throws Exception {
188         LOG.info("entering actionRequestApprove() ...");
189         SuperUserForm superUserForm = (SuperUserForm) form;
190 
191         // Retrieve the relevant arguments from the "methodToCall" parameter.
192         String methodToCallAttr = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
193         superUserForm.setActionTakenRecipientCode(StringUtils.substringBetween(methodToCallAttr,
194                 KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL));
195         superUserForm.setActionTakenNetworkId(StringUtils.substringBetween(methodToCallAttr,
196                 KRADConstants.METHOD_TO_CALL_PARM2_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM2_RIGHT_DEL));
197         superUserForm.setActionTakenWorkGroupId(StringUtils.substringBetween(methodToCallAttr,
198                 KRADConstants.METHOD_TO_CALL_PARM4_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM4_RIGHT_DEL));
199         superUserForm.setActionTakenActionRequestId(StringUtils.substringBetween(methodToCallAttr,
200                 KRADConstants.METHOD_TO_CALL_PARM5_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM5_RIGHT_DEL));
201 
202         LOG.debug("Routing super user action request approve action");
203         boolean runPostProcessorLogic = ArrayUtils.contains(superUserForm.getActionRequestRunPostProcessorCheck(),
204                 superUserForm.getActionTakenActionRequestId());
205         String documentId = superUserForm.getRouteHeader().getDocumentId();
206         WorkflowDocumentActionsService documentActions = getWorkflowDocumentActionsService(documentId);
207         DocumentActionParameters parameters = DocumentActionParameters.create(documentId, getUserSession(request)
208                 .getPrincipalId(), superUserForm.getAnnotation());
209         documentActions.superUserTakeRequestedAction(parameters, runPostProcessorLogic,
210                 superUserForm.getActionTakenActionRequestId());
211         String messageString;
212         String actionReqest = StringUtils.substringBetween(methodToCallAttr,
213                 KRADConstants.METHOD_TO_CALL_PARM6_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM6_RIGHT_DEL);
214         if (actionReqest.equalsIgnoreCase("acknowledge")) {
215             messageString = "general.routing.superuser.actionRequestAcknowledged";
216         } else if (actionReqest.equalsIgnoreCase("FYI")) {
217             messageString = "general.routing.superuser.actionRequestFYI";
218         } else if (actionReqest.equalsIgnoreCase("complete")) {
219             messageString = "general.routing.superuser.actionRequestCompleted";
220         } else if (actionReqest.equalsIgnoreCase("approved")) {
221             messageString = "general.routing.superuser.actionRequestApproved";
222         } else {
223             messageString = "general.routing.superuser.actionRequestApproved";
224         }
225         saveDocumentMessage(messageString, request, superUserForm.getDocumentId(),
226                 superUserForm.getActionTakenActionRequestId());
227         LOG.info("exiting actionRequestApprove() ...");
228         superUserForm.getActionRequests().clear();
229         initForm(request, form);
230 
231         // If the action request was also an app specific request, remove it from the app specific route recipient list.
232         int removalIndex = findAppSpecificRecipientIndex(superUserForm, superUserForm.getActionTakenActionRequestId());
233 
234         if (removalIndex >= 0) {
235             superUserForm.getAppSpecificRouteList().remove(removalIndex);
236         }
237 
238         return defaultDispatch(mapping, form, request, response);
239     }
240 
241     /**
242      * Finds the index in the app specific route recipient list of the recipient whose routing was
243      * handled by the given action request.
244      * 
245      * @param superUserForm The SuperUserForm currently being processed.
246      * @param actionRequestId The ID of the action request that handled the routing of the app
247      *        specific recipient that is being removed.
248      * @return The index of the app specific route recipient that was handled by the given action
249      *         request, or -1 if no such recipient was found.
250      */
251     private int findAppSpecificRecipientIndex(SuperUserForm superUserForm, String actionRequestId) {
252     	int tempIndex = 0;
253     	for (Iterator<?> appRouteIter = superUserForm.getAppSpecificRouteList().iterator(); appRouteIter.hasNext();) {
254     		String tempActnReqId = ((AppSpecificRouteRecipient) appRouteIter.next()).getActionRequestId();
255     		if (StringUtils.equals(tempActnReqId, actionRequestId)) {
256     			return tempIndex;
257     		}
258     		tempIndex++;
259     	}
260     	return -1;
261     }
262 
263     public ActionForward initForm(HttpServletRequest request, ActionForm form) throws Exception {
264         request.setAttribute("Constants", getServlet().getServletContext().getAttribute("KewApiConstants"));
265         SuperUserForm superUserForm = (SuperUserForm) form;
266         DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(
267                 superUserForm.getDocumentId());
268         if(ObjectUtils.isNull(routeHeader)) {
269             throw new ValidationException("No route header ID found.  Try searching for the document again using the super user document search.");
270         }
271         superUserForm.setRouteHeader(routeHeader);
272         String principalId = getUserSession(request).getPrincipalId();
273         boolean isAuthorized = KEWServiceLocator.getDocumentTypePermissionService().canAdministerRouting(principalId,
274                 routeHeader.getDocumentType());
275         superUserForm.setAuthorized(isAuthorized);
276         if (!isAuthorized) {
277             saveDocumentMessage("general.routing.superuser.notAuthorized", request, superUserForm.getDocumentId(), null);
278             return null;
279         }
280 
281         superUserForm.setFutureNodeNames(KEWServiceLocator.getRouteNodeService().findFutureNodeNames(
282                 routeHeader.getDocumentId()));
283 
284         Collection actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(
285                 routeHeader.getDocumentId());
286         Iterator requestIterator = actionRequests.iterator();
287         while (requestIterator.hasNext()) {
288             ActionRequestValue req = (ActionRequestValue) requestIterator.next();
289             // if (KewApiConstants.ACTION_REQUEST_APPROVE_REQ.equalsIgnoreCase(req.getActionRequested())) {
290             superUserForm.getActionRequests().add(req);
291             // }
292         }
293 
294         superUserForm.setDocId(superUserForm.getDocumentId());
295         if (superUserForm.getDocId() != null) {
296             superUserForm.setWorkflowDocument(WorkflowDocumentFactory.loadDocument(getUserSession(request)
297                     .getPrincipalId(), superUserForm.getDocId()));
298             superUserForm.establishVisibleActionRequestCds();
299         }
300 
301         return null;
302     }
303 
304     private void saveDocumentMessage(String messageKey, HttpServletRequest request, String subVariable1,
305             String subVariable2) {
306         if (subVariable2 == null) {
307             GlobalVariables.getMessageMap().putInfo("document", messageKey, subVariable1);
308         } else {
309             GlobalVariables.getMessageMap().putInfo("document", messageKey, subVariable1, subVariable2);
310         }
311     }
312 
313     public ActionForward routeToAppSpecificRecipient(ActionMapping mapping, ActionForm form,
314             HttpServletRequest request, HttpServletResponse response) throws Exception {
315         SuperUserForm superUserForm = (SuperUserForm) form;
316 
317         //super.routeToAppSpecificRecipient(mapping, form, request, response);
318         //WorkflowRoutingForm routingForm = (WorkflowRoutingForm) form;
319         String routeType = StringUtils.substringBetween(
320                 (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE),
321                 KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL);
322         AppSpecificRouteRecipient recipient = null;
323         if (KewApiConstants.PERSON.equals(routeType)) {
324             recipient = superUserForm.getAppSpecificRouteRecipient();
325             recipient.setActionRequested(superUserForm.getAppSpecificRouteActionRequestCd());
326             superUserForm.setAppSpecificPersonId(recipient.getId());
327         } else {
328             recipient = superUserForm.getAppSpecificRouteRecipient2();
329             recipient.setActionRequested(superUserForm.getAppSpecificRouteActionRequestCd2());
330             superUserForm.setAppSpecificWorkgroupId(recipient.getId());
331         }
332 
333         validateAppSpecificRoute(recipient);
334 
335         // Make sure that the requested action is still available.
336         superUserForm.establishVisibleActionRequestCds();
337         if (superUserForm.getAppSpecificRouteActionRequestCds().get(recipient.getActionRequested()) == null) {
338             GlobalVariables.getMessageMap().putError("appSpecificRouteRecipient" +
339                     ((KewApiConstants.WORKGROUP.equals(recipient.getType())) ? "2" : "") + ".id",
340                     "appspecificroute.actionrequested.invalid");
341 
342             throw new ValidationException("The requested action of '" + recipient.getActionRequested()
343                     + "' is no longer available for this document");
344         }
345 
346         try {
347             String routeNodeName = getAdHocRouteNodeName(superUserForm.getWorkflowDocument().getDocumentId());
348             //if (KewApiConstants.PERSON.equals(recipient.getType())) {
349             if (KewApiConstants.PERSON.equals(routeType)) {
350                 String recipientPrincipalId = KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(
351                         recipient.getId());
352                 superUserForm.getWorkflowDocument().adHocToPrincipal(
353                         ActionRequestType.fromCode(recipient.getActionRequested()), routeNodeName,
354                         superUserForm.getAnnotation(), recipientPrincipalId, "", true);
355             } else {
356                 String recipientGroupId = KEWServiceLocator.getIdentityHelperService().getIdForGroupName(
357                         recipient.getNamespaceCode(), recipient.getId());
358                 superUserForm.getWorkflowDocument().adHocToGroup(
359                         ActionRequestType.fromCode(recipient.getActionRequested()), routeNodeName,
360                         superUserForm.getAnnotation(), recipientGroupId, "", true);
361             }
362         } catch (Exception e) {
363             LOG.error("Error generating app specific route request", e);
364             throw new WorkflowServiceErrorException("AppSpecific Route Error", new WorkflowServiceErrorImpl(
365                     "AppSpecific Route Error", "appspecificroute.systemerror"));
366         }
367 
368         superUserForm.getActionRequests().clear();
369         initForm(request, form);
370 
371         // Retrieve the ID of the latest action request and store it with the app specific route recipient.
372         ActionRequestValue latestActnReq = getLatestActionRequest(superUserForm);
373         if (latestActnReq != null) {
374             recipient.setActionRequestId(latestActnReq.getActionRequestId());
375         }
376         // Add the recipient to the list.
377         superUserForm.getAppSpecificRouteList().add(recipient);
378         superUserForm.resetAppSpecificRoute();
379 
380         return start(mapping, form, request, response);
381     }
382 
383     /**
384      * Searches the current action requests list for the most recent request, which is the one with
385      * the highest ID.
386      * @param superUserForm The SuperUserForm currently being processed.
387      * @return The action request on the form with the highest ID, or null if no action requests
388      *         exist in the list.
389      */
390     private ActionRequestValue getLatestActionRequest(SuperUserForm superUserForm) {
391     	ActionRequestValue latestActnReq = null;
392 //    	long latestId = -1;
393     	
394     	// FIXME: KULRICE-5201 required the following refactor since action request ids are no longer numeric (and in any case the assumption that
395     	// they are strictly ordinal by time of creation may be false)
396     	List<ActionRequestValue> actionRequests = superUserForm.getActionRequests();
397     	
398     	if (actionRequests != null && actionRequests.size() > 0) {
399 	    	Collections.sort(actionRequests, new Comparator<ActionRequestValue>() {
400 	
401 				@Override
402 				// Should should by date in descending order
403 				public int compare(ActionRequestValue o1, ActionRequestValue o2) {
404 					if (o1 == null && o2 == null)
405 						return 0;
406 					if (o1 == null)
407 						return -1;
408 					if (o2 == null)
409 						return 1;
410 					
411 					if (o1.getCreateDate() == null && o2.getCreateDate() == null)
412 						return 0;
413 					if (o1.getCreateDate() == null)
414 						return -1;
415 					if (o2.getCreateDate() == null)
416 						return 1;
417 	
418 					return o2.getCreateDate().compareTo(o1.getCreateDate());
419 				}
420 	    	
421 	    	});
422 
423 	    	// If the list above is sorted in descending order then the first item should be the most recent
424 	    	latestActnReq = actionRequests.get(0);
425     	}
426     	
427     	// TODO: As part of KULRICE-5329 this change above needs to be verified and compared with code below
428 //    	// Search the list for the action request with the highest action request value.
429 //    	for (Iterator<?> actnReqIter = superUserForm.getActionRequests().iterator(); actnReqIter.hasNext();) {
430 //    		ActionRequestValue tmpActnReq = (ActionRequestValue) actnReqIter.next();
431 //    		if (tmpActnReq.getActionRequestId().longValue() > latestId) {
432 //    			latestActnReq = tmpActnReq;
433 //    			latestId = tmpActnReq.getActionRequestId().longValue();
434 //    		}
435 //    	}
436     	return latestActnReq;
437     }
438 
439     /**
440      * Removes an existing AppSpecificRouteRecipient from the list.
441      */
442     public ActionForward removeAppSpecificRecipient(ActionMapping mapping, ActionForm form, HttpServletRequest request,
443             HttpServletResponse response) throws Exception {
444         SuperUserForm superUserForm = (SuperUserForm) form;
445         // Make sure a valid route recipient index was specified in the "methodToCall" attribute.
446         String strIndex = StringUtils.substringBetween(
447                 (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE),
448                 KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL);
449         if (StringUtils.isBlank(strIndex)) {
450             throw new WorkflowException("No adhoc route recipient index specified");
451         }
452         int removeIndex = Integer.parseInt(strIndex);
453         if (removeIndex < 0 || removeIndex >= superUserForm.getAppSpecificRouteList().size()) {
454             throw new WorkflowException("Invalid adhoc route recipient index specified");
455         }
456         // Remove the specified recipient from the routing, based on the recipient's ID and the ID of the action request that handled the recipient.
457         AppSpecificRouteRecipient removedRec = (AppSpecificRouteRecipient) superUserForm.getAppSpecificRouteList().get(
458                 removeIndex);
459         if (removedRec.getActionRequestId() != null) {
460             superUserForm.getWorkflowDocument().revokeAdHocRequestById(removedRec.getActionRequestId().toString(), "");
461         } else {
462             AdHocRevoke adHocRevoke = null;
463             // Set the ID according to whether the recipient is a person or a group.
464             if (KewApiConstants.PERSON.equals(removedRec.getType())) {
465                 adHocRevoke = AdHocRevoke.createRevokeFromPrincipal(KEWServiceLocator.getIdentityHelperService()
466                         .getIdForPrincipalName(removedRec.getId()));
467             } else {
468                 adHocRevoke = AdHocRevoke.createRevokeFromGroup(KEWServiceLocator.getIdentityHelperService()
469                         .getIdForGroupName(removedRec.getNamespaceCode(), removedRec.getId()));
470             }
471             superUserForm.getWorkflowDocument().revokeAdHocRequests(adHocRevoke, "");
472         }
473         superUserForm.getAppSpecificRouteList().remove(removeIndex);
474 
475         superUserForm.getActionRequests().clear();
476         initForm(request, form);
477         return start(mapping, form, request, response);
478     }
479 
480     private WorkflowDocumentActionsService getWorkflowDocumentActionsService(String documentId) {
481         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByDocumentId(documentId);
482         String applicationId = documentType.getApplicationId();
483         QName serviceName = new QName(KewApiConstants.Namespaces.KEW_NAMESPACE_2_0,
484                 KewApiConstants.ServiceNames.WORKFLOW_DOCUMENT_ACTIONS_SERVICE_SOAP);
485         WorkflowDocumentActionsService service = (WorkflowDocumentActionsService) KsbApiServiceLocator.getServiceBus()
486                 .getService(serviceName, applicationId);
487         if (service == null) {
488             service = KewApiServiceLocator.getWorkflowDocumentActionsService();
489         }
490         return service;
491     }
492 
493     protected void validateAppSpecificRoute(AppSpecificRouteRecipient recipient) {
494         if (recipient.getId() == null || recipient.getId().trim().equals("")) {
495             GlobalVariables.getMessageMap().putError("appSpecificRouteRecipient" +
496                     ((KewApiConstants.WORKGROUP.equals(recipient.getType())) ? "2" : "") + ".id",
497                     "appspecificroute.recipient.required");
498         } else {
499             if (KewApiConstants.PERSON.equals(recipient.getType())) {
500                 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(
501                         recipient.getId());
502                 if (principal == null) {
503                     LOG.error("App Specific user recipient not found");
504                     GlobalVariables.getMessageMap().putError("appSpecificRouteRecipient.id",
505                             "appspecificroute.user.invalid");
506                 }
507             } else if (KewApiConstants.WORKGROUP.equals(recipient.getType())) {
508                 //if (getIdentityManagementService().getGroup(recipient.getId()) == null) {
509                 if (getGroupService().getGroupByNamespaceCodeAndName(recipient.getNamespaceCode(), recipient.getId()) == null) {
510                     GlobalVariables.getMessageMap().putError("appSpecificRouteRecipient2.id",
511                             "appspecificroute.workgroup.invalid");
512                 }
513             }
514         }
515         if (GlobalVariables.getMessageMap().hasErrors()) {
516             throw new ValidationException("AppSpecific Route validation Errors");
517         }
518 
519     }
520 
521     protected String getAdHocRouteNodeName(String documentId) throws WorkflowException {
522         WorkflowDocumentService workflowDocumentService = KewApiServiceLocator.getWorkflowDocumentService();
523         List<RouteNodeInstance> nodeInstances = workflowDocumentService.getActiveRouteNodeInstances(documentId);
524         if (nodeInstances == null || nodeInstances.isEmpty()) {
525             nodeInstances = workflowDocumentService.getTerminalRouteNodeInstances(documentId);
526         }
527         if (nodeInstances == null || nodeInstances.isEmpty()) {
528             throw new WorkflowException("Could not locate a node on the document to send the ad hoc request to.");
529         }
530         return nodeInstances.get(0).getName();
531     }
532 
533     private GroupService getGroupService() {
534         return KimApiServiceLocator.getGroupService();
535     }
536 
537     public static UserSession getUserSession(HttpServletRequest request) {
538         return GlobalVariables.getUserSession();
539     }
540 
541 }