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