001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.superuser.web;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.Comparator;
021import java.util.Iterator;
022import java.util.List;
023
024import javax.servlet.http.HttpServletRequest;
025import javax.servlet.http.HttpServletResponse;
026import javax.xml.namespace.QName;
027
028import org.apache.commons.lang.ArrayUtils;
029import org.apache.commons.lang.StringUtils;
030import org.apache.struts.action.ActionForm;
031import org.apache.struts.action.ActionForward;
032import org.apache.struts.action.ActionMapping;
033import org.kuali.rice.kew.actionrequest.ActionRequestValue;
034import org.kuali.rice.kew.api.KewApiConstants;
035import org.kuali.rice.kew.api.KewApiServiceLocator;
036import org.kuali.rice.kew.api.WorkflowDocumentFactory;
037import org.kuali.rice.kew.api.action.ActionRequestType;
038import org.kuali.rice.kew.api.action.AdHocRevoke;
039import org.kuali.rice.kew.api.action.DocumentActionParameters;
040import org.kuali.rice.kew.api.action.ReturnPoint;
041import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
042import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
043import org.kuali.rice.kew.api.document.WorkflowDocumentService;
044import org.kuali.rice.kew.api.exception.WorkflowException;
045import org.kuali.rice.kew.doctype.bo.DocumentType;
046import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
047import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
048import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
049import org.kuali.rice.kew.service.KEWServiceLocator;
050import org.kuali.rice.kew.api.KewApiConstants;
051import org.kuali.rice.kew.web.AppSpecificRouteRecipient;
052import org.kuali.rice.kew.web.KewKualiAction;
053import org.kuali.rice.kim.api.group.GroupService;
054import org.kuali.rice.kim.api.identity.principal.Principal;
055import org.kuali.rice.kim.api.services.KimApiServiceLocator;
056import org.kuali.rice.krad.UserSession;
057import org.kuali.rice.krad.exception.ValidationException;
058import org.kuali.rice.krad.util.GlobalVariables;
059import org.kuali.rice.krad.util.KRADConstants;
060import org.kuali.rice.krad.util.ObjectUtils;
061import org.kuali.rice.ksb.api.KsbApiServiceLocator;
062
063/**
064 * A Struts Action which provides super user functionality.
065 * 
066 * @author Kuali Rice Team (rice.collab@kuali.org)
067 */
068public class SuperUserAction extends KewKualiAction {
069    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SuperUserAction.class);
070    public static final String UNAUTHORIZED = "authorizationFailure";
071
072    //public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
073    //  defaultDispatch(mapping, form, request, response);
074    //}
075
076    @Override
077    public ActionForward execute(ActionMapping mapping, ActionForm form,
078            HttpServletRequest request, HttpServletResponse response)
079            throws Exception {
080        initForm(request, form);
081        return super.execute(mapping, form, request, response);
082    }
083
084    @Override
085    public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request,
086            HttpServletResponse response) throws Exception {
087        ((SuperUserForm) form).getActionRequests().clear();
088        initForm(request, form);
089        return defaultDispatch(mapping, form, request, response);
090    }
091
092    public ActionForward displaySuperUserDocument(ActionMapping mapping, ActionForm form, HttpServletRequest request,
093            HttpServletResponse response) throws Exception {
094        SuperUserForm superUserForm = (SuperUserForm) form;
095        superUserForm.setDocHandlerUrl(KewApiConstants.DOC_HANDLER_REDIRECT_PAGE + "?docId="
096                + superUserForm.getDocumentId() + "&" + KewApiConstants.COMMAND_PARAMETER + "="
097                + KewApiConstants.SUPERUSER_COMMAND);
098        return defaultDispatch(mapping, form, request, response);
099    }
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}