Coverage Report - org.kuali.rice.kew.routelog.web.RouteLogAction
 
Classes in this File Line Coverage Branch Coverage Complexity
RouteLogAction
0%
0/130
0%
0/62
3.895
RouteLogAction$RouteNodeInstanceFabricator
0%
0/80
0%
0/32
3.895
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.routelog.web;
 17  
 
 18  
 import org.apache.struts.action.ActionForm;
 19  
 import org.apache.struts.action.ActionForward;
 20  
 import org.apache.struts.action.ActionMapping;
 21  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 22  
 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
 23  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 24  
 import org.kuali.rice.kew.api.KewApiServiceLocator;
 25  
 import org.kuali.rice.kew.api.WorkflowRuntimeException;
 26  
 import org.kuali.rice.kew.api.action.ActionRequest;
 27  
 import org.kuali.rice.kew.api.action.ActionRequestStatus;
 28  
 import org.kuali.rice.kew.api.action.RoutingReportCriteria;
 29  
 import org.kuali.rice.kew.api.document.DocumentDetail;
 30  
 import org.kuali.rice.kew.api.document.node.RouteNodeInstanceState;
 31  
 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
 32  
 import org.kuali.rice.kew.doctype.SecuritySession;
 33  
 import org.kuali.rice.kew.doctype.service.DocumentSecurityService;
 34  
 import org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader;
 35  
 import org.kuali.rice.kew.engine.node.Branch;
 36  
 import org.kuali.rice.kew.engine.node.NodeState;
 37  
 import org.kuali.rice.kew.engine.node.RouteNode;
 38  
 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
 39  
 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
 40  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 41  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 42  
 import org.kuali.rice.kew.util.Utilities;
 43  
 import org.kuali.rice.kew.web.KewKualiAction;
 44  
 import org.kuali.rice.krad.UserSession;
 45  
 import org.kuali.rice.krad.util.GlobalVariables;
 46  
 
 47  
 import javax.servlet.http.HttpServletRequest;
 48  
 import javax.servlet.http.HttpServletResponse;
 49  
 import java.util.ArrayList;
 50  
 import java.util.Collection;
 51  
 import java.util.Collections;
 52  
 import java.util.Comparator;
 53  
 import java.util.HashMap;
 54  
 import java.util.HashSet;
 55  
 import java.util.List;
 56  
 import java.util.Map;
 57  
 import java.util.Set;
 58  
 
 59  
 
 60  
 /**
 61  
  * A Struts Action used to display the routelog.
 62  
  *
 63  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 64  
  */
 65  0
 public class RouteLogAction extends KewKualiAction {
 66  
 
 67  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RouteLogAction.class);
 68  0
     private static Comparator<ActionRequestValue> ROUTE_LOG_ACTION_REQUEST_SORTER = new Utilities.RouteLogActionRequestSorter();
 69  
     
 70  
     @Override
 71  
         public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 72  
 
 73  0
         RouteLogForm rlForm = (RouteLogForm) form;
 74  0
         String documentId = null;
 75  0
         if (! org.apache.commons.lang.StringUtils.isEmpty(rlForm.getDocumentId())) {
 76  0
                 documentId = rlForm.getDocumentId();
 77  0
         } else if (! org.apache.commons.lang.StringUtils.isEmpty(rlForm.getDocId())) {
 78  0
                 documentId =rlForm.getDocId();
 79  
         } else {
 80  0
                 throw new WorkflowRuntimeException("No paramater provided to fetch document");
 81  
         }
 82  
 
 83  0
         DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
 84  
 
 85  0
         DocumentSecurityService security = KEWServiceLocator.getDocumentSecurityService();
 86  0
         if (!security.routeLogAuthorized(getUserSession().getPrincipalId(), routeHeader, new SecuritySession(GlobalVariables.getUserSession().getPrincipalId()))) {
 87  0
           return mapping.findForward("NotAuthorized");
 88  
         }
 89  
         
 90  0
         fixActionRequestsPositions(routeHeader);
 91  0
         populateRouteLogFormActionRequests(rlForm, routeHeader);
 92  
 
 93  0
         rlForm.setLookFuture(routeHeader.getDocumentType().getLookIntoFuturePolicy().getPolicyValue().booleanValue());
 94  
 
 95  0
         if (rlForm.isShowFuture()) {
 96  
             try {
 97  0
                 populateRouteLogFutureRequests(rlForm, routeHeader);
 98  0
             } catch (Exception e) {
 99  0
                 String errorMsg = "Unable to determine Future Action Requests";
 100  0
                 LOG.info(errorMsg,e);
 101  0
                 rlForm.setShowFutureError(errorMsg);
 102  0
             }
 103  
         }
 104  0
         request.setAttribute("routeHeader", routeHeader);
 105  
         
 106  
                 // check whether action message logging should be enabled, user must
 107  
                 // have KIM permission for doc type 
 108  0
         boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
 109  
                                 .canAddRouteLogMessage(GlobalVariables.getUserSession().getPrincipalId(), routeHeader);
 110  0
                 if (isAuthorizedToAddRouteLogMessage) {
 111  0
                         rlForm.setEnableLogAction(true);
 112  
                 } else {
 113  0
                         rlForm.setEnableLogAction(false);
 114  
                 }
 115  
         
 116  0
         return super.execute(mapping, rlForm, request, response);
 117  
     }
 118  
 
 119  
     @SuppressWarnings("unchecked")
 120  
         public void populateRouteLogFormActionRequests(RouteLogForm rlForm, DocumentRouteHeaderValue routeHeader) {
 121  0
         List<ActionRequestValue> rootRequests = getActionRequestService().getRootRequests(routeHeader.getActionRequests());
 122  0
         Collections.sort(rootRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
 123  0
         rootRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(rootRequests);
 124  0
         int arCount = 0;
 125  0
         for ( ActionRequestValue actionRequest : rootRequests ) {
 126  0
             if (actionRequest.isPending()) {
 127  0
                 arCount++;
 128  
 
 129  0
                 if (ActionRequestStatus.INITIALIZED.getCode().equals(actionRequest.getStatus())) {
 130  0
                     actionRequest.setDisplayStatus("PENDING");
 131  0
                 } else if (ActionRequestStatus.ACTIVATED.getCode().equals(actionRequest.getStatus())) {
 132  0
                     actionRequest.setDisplayStatus("IN ACTION LIST");
 133  
                 }
 134  
             }
 135  
         }
 136  0
         rlForm.setRootRequests(rootRequests);
 137  0
         rlForm.setPendingActionRequestCount(arCount);
 138  0
     }
 139  
 
 140  
     @SuppressWarnings("unchecked")
 141  
         private ActionRequestValue switchActionRequestPositionIfPrimaryDelegatePresent( ActionRequestValue actionRequest ) {
 142  
             
 143  
             /**
 144  
              * KULRICE-4756 - The main goal here is to fix the regression of what happened in Rice 1.0.2 with the display
 145  
              * of primary delegate requests.  The delegate is displayed at the top-most level correctly on action requests
 146  
              * that are "rooted" at a "role" request.
 147  
              * 
 148  
              * If they are rooted at a principal or group request, then the display of the primary delegator at the top-most
 149  
              * level does not happen (instead it shows the delegator and you have to expand the request to see the primary
 150  
              * delegate).
 151  
              * 
 152  
              * Ultimately, the KAI group and Rice BA need to come up with a specification for how the Route Log should
 153  
              * display delegate information.  For now, will fix this so that in the non "role" case, it will put the
 154  
              * primary delegate as the outermost request *except* in the case where there is more than one primary delegate.
 155  
              */
 156  
             
 157  0
             if (!actionRequest.isRoleRequest()) {
 158  0
                     List<ActionRequestValue> primaryDelegateRequests = actionRequest.getPrimaryDelegateRequests();
 159  
                     // only display primary delegate request at top if there is only *one* primary delegate request
 160  0
                     if ( primaryDelegateRequests.size() != 1) {
 161  0
                             return actionRequest;
 162  
                     }
 163  0
                     ActionRequestValue primaryDelegateRequest = primaryDelegateRequests.get(0);
 164  0
                     actionRequest.getChildrenRequests().remove(primaryDelegateRequest);
 165  0
                     primaryDelegateRequest.setChildrenRequests(actionRequest.getChildrenRequests());
 166  0
                     primaryDelegateRequest.setParentActionRequest(actionRequest.getParentActionRequest());
 167  0
                     primaryDelegateRequest.setParentActionRequestId(actionRequest.getParentActionRequestId());
 168  
                     
 169  0
                     actionRequest.setChildrenRequests( new ArrayList<ActionRequestValue>(0) );
 170  0
                     actionRequest.setParentActionRequest(primaryDelegateRequest);
 171  0
                     actionRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
 172  
                     
 173  0
                     primaryDelegateRequest.getChildrenRequests().add(0, actionRequest);
 174  
                     
 175  0
                     for (ActionRequestValue delegateRequest : primaryDelegateRequest.getChildrenRequests()) {
 176  0
                             delegateRequest.setParentActionRequest(primaryDelegateRequest);
 177  0
                             delegateRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
 178  
                     }
 179  
                     
 180  0
                     return primaryDelegateRequest;
 181  
             }
 182  
             
 183  0
             return actionRequest;
 184  
     }
 185  
 
 186  
     private List<ActionRequestValue> switchActionRequestPositionsIfPrimaryDelegatesPresent( Collection<ActionRequestValue> actionRequests ) {
 187  0
             List<ActionRequestValue> results = new ArrayList<ActionRequestValue>( actionRequests.size() );
 188  0
             for ( ActionRequestValue actionRequest : actionRequests ) {
 189  0
                         results.add( switchActionRequestPositionIfPrimaryDelegatePresent(actionRequest) );
 190  
             }
 191  0
             return results;
 192  
     }
 193  
     
 194  
     @SuppressWarnings("unchecked")
 195  
     private void fixActionRequestsPositions(DocumentRouteHeaderValue routeHeader) {
 196  0
         for (ActionTakenValue actionTaken : routeHeader.getActionsTaken()) {
 197  0
             Collections.sort((List<ActionRequestValue>) actionTaken.getActionRequests(), ROUTE_LOG_ACTION_REQUEST_SORTER);
 198  0
             actionTaken.setActionRequests( actionTaken.getActionRequests() );
 199  
         }
 200  0
     }
 201  
     
 202  
     /**
 203  
      * executes a simulation of the future routing, and sets the futureRootRequests and futureActionRequestCount
 204  
      * properties on the provided RouteLogForm.
 205  
      * 
 206  
      * @param rlForm the RouteLogForm --used in a write-only fashion.
 207  
      * @param document the DocumentRouteHeaderValue for the document whose future routing is being simulated.
 208  
      * @throws Exception
 209  
      */
 210  
     public void populateRouteLogFutureRequests(RouteLogForm rlForm, DocumentRouteHeaderValue document) throws Exception {
 211  
 
 212  0
         RoutingReportCriteria reportCriteria = RoutingReportCriteria.Builder.createByDocumentId(document.getDocumentId()).build();
 213  0
         String applicationId = document.getDocumentType().getApplicationId();
 214  
 
 215  
         // gather the IDs for action requests that predate the simulation
 216  0
                 Set<String> preexistingActionRequestIds = getActionRequestIds(document);
 217  
         
 218  
                 // run the simulation
 219  0
         DocumentDetail documentDetail = KewApiServiceLocator.getWorkflowDocumentActionsService().executeSimulation(
 220  
                 reportCriteria);
 221  
 
 222  
         // fabricate our ActionRequestValueS from the results
 223  0
         List<ActionRequestValue> futureActionRequests = 
 224  
                 reconstituteActionRequestValues(documentDetail, preexistingActionRequestIds);
 225  
 
 226  0
         Collections.sort(futureActionRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
 227  
         
 228  0
         futureActionRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(futureActionRequests);
 229  
         
 230  0
         int pendingActionRequestCount = 0;
 231  0
         for (ActionRequestValue actionRequest: futureActionRequests) {
 232  0
             if (actionRequest.isPending()) {
 233  0
                 pendingActionRequestCount++;
 234  
 
 235  0
                 if (ActionRequestStatus.INITIALIZED.getCode().equals(actionRequest.getStatus())) {
 236  0
                     actionRequest.setDisplayStatus("PENDING");
 237  0
                 } else if (ActionRequestStatus.ACTIVATED.getCode().equals(actionRequest.getStatus())) {
 238  0
                     actionRequest.setDisplayStatus("IN ACTION LIST");
 239  
                 }
 240  
             }
 241  
         }
 242  
 
 243  0
         rlForm.setFutureRootRequests(futureActionRequests);
 244  0
         rlForm.setFutureActionRequestCount(pendingActionRequestCount);
 245  0
     }
 246  
 
 247  
 
 248  
         /**
 249  
          * This utility method returns a Set of LongS containing the IDs for the ActionRequestValueS associated with 
 250  
          * this DocumentRouteHeaderValue. 
 251  
          */
 252  
         @SuppressWarnings("unchecked")
 253  
         private Set<String> getActionRequestIds(DocumentRouteHeaderValue document) {
 254  0
                 Set<String> actionRequestIds = new HashSet<String>();
 255  
 
 256  0
                 List<ActionRequestValue> actionRequests = 
 257  
                         KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(document.getDocumentId());
 258  
                 
 259  0
                 if (actionRequests != null) {
 260  0
                         for (ActionRequestValue actionRequest : actionRequests) {
 261  0
                                 if (actionRequest.getActionRequestId() != null) {
 262  0
                                         actionRequestIds.add(actionRequest.getActionRequestId());
 263  
                                 }
 264  
                         }
 265  
                 }
 266  0
                 return actionRequestIds;
 267  
         }
 268  
 
 269  
         /**
 270  
          * This method creates ActionRequestValue objects from the DocumentDetailDTO output from
 271  
          * 
 272  
          * @param documentDetail contains the DTOs from which the ActionRequestValues are reconstituted
 273  
          * @param preexistingActionRequestIds this is a Set of ActionRequest IDs that will not be reconstituted
 274  
          * @return the ActionRequestValueS that have been created
 275  
          */
 276  
         private List<ActionRequestValue> reconstituteActionRequestValues(DocumentDetail documentDetail,
 277  
                         Set<String> preexistingActionRequestIds) {
 278  
 
 279  0
         RouteNodeInstanceFabricator routeNodeInstanceFabricator = 
 280  
                     new RouteNodeInstanceFabricator(KEWServiceLocator.getRouteNodeService());
 281  
 
 282  0
         if (documentDetail.getRouteNodeInstances() != null && !documentDetail.getRouteNodeInstances().isEmpty()) {
 283  0
                 for (org.kuali.rice.kew.api.document.node.RouteNodeInstance routeNodeInstanceVO : documentDetail.getRouteNodeInstances()) {
 284  0
                         routeNodeInstanceFabricator.importRouteNodeInstanceDTO(routeNodeInstanceVO);
 285  
                 }
 286  
                 }
 287  
         
 288  0
         List<ActionRequest> actionRequestVOs = documentDetail.getActionRequests();
 289  0
         List<ActionRequestValue> futureActionRequests = new ArrayList<ActionRequestValue>();
 290  0
         if (actionRequestVOs != null) {
 291  0
                         for (ActionRequest actionRequestVO : actionRequestVOs) {
 292  0
                                 if (actionRequestVO != null) {
 293  0
                                         if (!preexistingActionRequestIds.contains(actionRequestVO.getId())) {
 294  0
                                                 ActionRequestValue converted = ActionRequestValue.from(actionRequestVO,
 295  
                                 routeNodeInstanceFabricator);
 296  0
                                                 futureActionRequests.add(converted);
 297  0
                                         }
 298  
                                 }
 299  
                         }
 300  
                 }
 301  0
                 return futureActionRequests;
 302  
         }
 303  
     
 304  
     private ActionRequestService getActionRequestService() {
 305  0
         return (ActionRequestService) KEWServiceLocator.getService(KEWServiceLocator.ACTION_REQUEST_SRV);
 306  
     }
 307  
     
 308  
     private UserSession getUserSession() {
 309  0
         return GlobalVariables.getUserSession();
 310  
     }
 311  
     
 312  
     /**
 313  
      * Creates dummy RouteNodeInstances based on imported data from RouteNodeInstanceDTOs.
 314  
      * It is then able to vend those RouteNodeInstanceS back by their IDs.
 315  
      * 
 316  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 317  
      *
 318  
      */
 319  0
     private static class RouteNodeInstanceFabricator implements RouteNodeInstanceLoader {
 320  
 
 321  0
             private Map<String,Branch> branches = new HashMap<String, Branch>();
 322  0
             private Map<String, RouteNodeInstance> routeNodeInstances =
 323  
                 new HashMap<String, RouteNodeInstance>();
 324  0
             private Map<String,RouteNode> routeNodes = new HashMap<String, RouteNode>();
 325  0
             private Map<String,NodeState> nodeStates = new HashMap<String, NodeState>();
 326  
 
 327  
             private RouteNodeService routeNodeService;
 328  
             
 329  
             /**
 330  
                  * This constructs a FutureRouteNodeInstanceFabricator, which will generate bogus
 331  
                  * RouteNodeInstances for SimulationEngine results
 332  
                  * 
 333  
                  */
 334  0
                 public RouteNodeInstanceFabricator(RouteNodeService routeNodeService) {
 335  0
                         this.routeNodeService = routeNodeService;
 336  0
                 }
 337  
 
 338  
                 /**
 339  
                  * 
 340  
                  * This method looks at the given RouteNodeInstanceDTO and imports it (and all it's ancestors)
 341  
                  * as dummy RouteNodeInstanceS
 342  
                  * 
 343  
                  * @param nodeInstanceDTO
 344  
                  */
 345  
                 public void importRouteNodeInstanceDTO(org.kuali.rice.kew.api.document.node.RouteNodeInstance nodeInstanceDTO) {
 346  0
                         _importRouteNodeInstanceDTO(nodeInstanceDTO);
 347  0
                 }
 348  
                 
 349  
                 /**
 350  
                  * helper method for {@link #importRouteNodeInstanceDTO(org.kuali.rice.kew.api.document.node.RouteNodeInstance)} which does all
 351  
                  * the work.  The public method just wraps this one but hides the returned RouteNodeInstance,
 352  
                  * which is used for the recursive call to populate the nextNodeInstanceS inside our 
 353  
                  * RouteNodeInstanceS.
 354  
                  * 
 355  
                  * @param nodeInstanceDTO
 356  
                  * @return
 357  
                  */
 358  
             private RouteNodeInstance _importRouteNodeInstanceDTO(org.kuali.rice.kew.api.document.node.RouteNodeInstance nodeInstanceDTO) {
 359  0
                     if (nodeInstanceDTO == null) {
 360  0
                             return null;
 361  
                     }
 362  0
                     RouteNodeInstance nodeInstance = new RouteNodeInstance();
 363  0
                     nodeInstance.setActive(nodeInstanceDTO.isActive());
 364  
 
 365  0
                     nodeInstance.setComplete(nodeInstanceDTO.isComplete());
 366  0
                     nodeInstance.setDocumentId(nodeInstanceDTO.getDocumentId());
 367  0
                     nodeInstance.setInitial(nodeInstanceDTO.isInitial());
 368  
 
 369  0
                     Branch branch = getBranch(nodeInstanceDTO.getBranchId());
 370  0
                     nodeInstance.setBranch(branch);
 371  
 
 372  0
                     if (nodeInstanceDTO.getRouteNodeId() != null) {
 373  0
                             RouteNode routeNode = routeNodeService.findRouteNodeById(nodeInstanceDTO.getRouteNodeId());
 374  
 
 375  0
                             if (routeNode == null) {
 376  0
                                     routeNode = getRouteNode(nodeInstanceDTO.getRouteNodeId());
 377  0
                                     routeNode.setNodeType(nodeInstanceDTO.getName());
 378  
                             }
 379  
 
 380  0
                             nodeInstance.setRouteNode(routeNode);
 381  
 
 382  0
                             if (routeNode.getBranch() != null) {
 383  0
                                 branch.setName(routeNode.getBranch().getName());
 384  
                         } 
 385  
                     }
 386  
 
 387  0
                     RouteNodeInstance process = getRouteNodeInstance(nodeInstanceDTO.getProcessId());
 388  0
                     nodeInstance.setProcess(process);
 389  
 
 390  0
                     nodeInstance.setRouteNodeInstanceId(nodeInstanceDTO.getId());
 391  
 
 392  0
                     List<NodeState> nodeState = new ArrayList<NodeState>();
 393  0
                     if (nodeInstanceDTO.getState() != null) {
 394  0
                                 for (RouteNodeInstanceState stateDTO : nodeInstanceDTO.getState()) {
 395  0
                                         NodeState state = getNodeState(stateDTO.getId());
 396  0
                                         if (state != null) {
 397  0
                                                 state.setKey(stateDTO.getKey());
 398  0
                                                 state.setValue(stateDTO.getValue());
 399  0
                                                 state.setStateId(stateDTO.getId());
 400  0
                                                 state.setNodeInstance(nodeInstance);
 401  0
                                                 nodeState.add(state);
 402  
                                         }
 403  0
                                 }
 404  
                         }
 405  0
                     nodeInstance.setState(nodeState);
 406  
 
 407  0
                     List<RouteNodeInstance> nextNodeInstances = new ArrayList<RouteNodeInstance>();
 408  
 
 409  
 
 410  0
                     for (org.kuali.rice.kew.api.document.node.RouteNodeInstance nextNodeInstanceVO : nodeInstanceDTO.getNextNodeInstances()) {
 411  
                             // recurse to populate nextNodeInstances
 412  0
                             nextNodeInstances.add(_importRouteNodeInstanceDTO(nextNodeInstanceVO));
 413  
                     }
 414  0
             nodeInstance.setNextNodeInstances(nextNodeInstances);
 415  
 
 416  0
                     routeNodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
 417  0
                     return nodeInstance;
 418  
             }
 419  
             
 420  
                 /**
 421  
                  * This method returns a dummy RouteNodeInstance for the given ID, or null if it hasn't
 422  
                  * imported from a RouteNodeInstanceDTO with that ID
 423  
                  * 
 424  
                  * @see org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader#load(String)
 425  
                  */
 426  
                 @Override
 427  
                 public RouteNodeInstance load(String routeNodeInstanceID) {
 428  0
                         return routeNodeInstances.get(routeNodeInstanceID);
 429  
                 }
 430  
 
 431  
 
 432  
             /**
 433  
              * This method creates bogus BranchES as needed
 434  
              * 
 435  
              * @param branchId
 436  
              * @return
 437  
              */
 438  
             private Branch getBranch(String branchId) {
 439  0
                     Branch result = null;
 440  
 
 441  0
                     if (branchId != null) {
 442  
                             // if branch doesn't exist, create it
 443  0
                             if (!branches.containsKey(branchId)) {
 444  0
                                     result = new Branch();
 445  0
                                     result.setBranchId(branchId);
 446  0
                                     branches.put(branchId, result);
 447  
                             } else {
 448  0
                                     result = branches.get(branchId);
 449  
                             }
 450  
                     }
 451  0
                     return result;
 452  
             }
 453  
 
 454  
             /**
 455  
              * This method creates bogus RouteNodeS as needed
 456  
              * 
 457  
              * @param routeNodeId
 458  
              * @return
 459  
              */
 460  
             private RouteNode getRouteNode(String routeNodeId) {
 461  0
                     RouteNode result = null;
 462  
 
 463  0
                     if (routeNodeId != null) {
 464  
                             // if RouteNode doesn't exist, create it
 465  0
                             if (!routeNodes.containsKey(routeNodeId)) {
 466  0
                                     result = new RouteNode();
 467  0
                                     result.setRouteNodeId(routeNodeId);
 468  0
                                     routeNodes.put(routeNodeId, result);
 469  
                             } else {
 470  0
                                     result = routeNodes.get(routeNodeId);
 471  
                             }
 472  
                     }
 473  0
                     return result;
 474  
             }
 475  
 
 476  
             /**
 477  
              * This method creates bogus RouteNodeInstanceS as needed
 478  
              * 
 479  
              * @param routeNodeInstanceId
 480  
              * @return
 481  
              */
 482  
             public RouteNodeInstance getRouteNodeInstance(String routeNodeInstanceId) {
 483  0
                     RouteNodeInstance result = null;
 484  
 
 485  0
                     if (routeNodeInstanceId != null) {
 486  
                             // if RouteNodeInstance doesn't exist, create it
 487  0
                             if (!routeNodeInstances.containsKey(routeNodeInstanceId)) {
 488  0
                     result = new RouteNodeInstance();
 489  0
                                     result.setRouteNodeInstanceId(routeNodeInstanceId);
 490  0
                                     routeNodeInstances.put(routeNodeInstanceId, result);
 491  
                             } else {
 492  0
                                     result = routeNodeInstances.get(routeNodeInstanceId);
 493  
                             }
 494  
                     }
 495  0
                     return result;
 496  
             }
 497  
 
 498  
             /**
 499  
              * This method creates bogus NodeStateS as needed
 500  
              * 
 501  
              * @param nodeStateId
 502  
              * @return
 503  
              */
 504  
             private NodeState getNodeState(String nodeStateId) {
 505  0
                     NodeState result = null;
 506  
 
 507  0
                     if (nodeStateId != null) {
 508  
                             // if NodeState doesn't exist, create it
 509  0
                             if (!nodeStates.containsKey(nodeStateId)) {
 510  0
                                     result = new NodeState();
 511  0
                                     result.setNodeStateId(nodeStateId);
 512  0
                                     nodeStates.put(nodeStateId, result);
 513  
                             } else {
 514  0
                                     result = nodeStates.get(nodeStateId);
 515  
                             }
 516  
                     }
 517  0
                     return result;
 518  
             }
 519  
 
 520  
     } // end inner class FutureRouteNodeInstanceFabricator
 521  
 
 522  
     /**
 523  
      * Logs a new message to the route log for the current document, then refreshes the action taken list to display
 524  
      * back the new message in the route log tab. User must have permission to log a message for the doc type and the
 525  
      * request must be coming from the route log tab display (not the route log page).
 526  
      */
 527  
         public ActionForward logActionMessageInRouteLog(ActionMapping mapping, ActionForm form, HttpServletRequest request,
 528  
                         HttpServletResponse response) throws Exception {
 529  0
                 RouteLogForm routeLogForm = (RouteLogForm) form;
 530  
 
 531  0
                 String documentId = null;
 532  0
                 if (!org.apache.commons.lang.StringUtils.isEmpty(routeLogForm.getDocumentId())) {
 533  0
                         documentId = routeLogForm.getDocumentId();
 534  0
                 } else if (!org.apache.commons.lang.StringUtils.isEmpty(routeLogForm.getDocId())) {
 535  0
                         documentId = routeLogForm.getDocId();
 536  
                 } else {
 537  0
                         throw new WorkflowRuntimeException("No paramater provided to fetch document");
 538  
                 }
 539  
                 
 540  0
                 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
 541  
                 
 542  
                 // check user has permission to add a route log message
 543  0
                 boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
 544  
                                 .canAddRouteLogMessage(GlobalVariables.getUserSession().getPrincipalId(), routeHeader);
 545  
 
 546  0
                 if (!isAuthorizedToAddRouteLogMessage) {
 547  0
                         throw new InvalidActionTakenException("Principal with name '"
 548  
                                         + GlobalVariables.getUserSession().getPrincipalName()
 549  
                                         + "' is not authorized to add route log messages for documents of type '"
 550  
                                         + routeHeader.getDocumentType().getName());
 551  
                 }
 552  
 
 553  0
                 LOG.info("Logging new action message for user " + GlobalVariables.getUserSession().getPrincipalName()
 554  
                                 + ", route header " + routeHeader);
 555  0
                 KEWServiceLocator.getWorkflowDocumentService().logDocumentAction(
 556  
                                 GlobalVariables.getUserSession().getPrincipalId(), routeHeader,
 557  
                                 routeLogForm.getNewRouteLogActionMessage());
 558  
 
 559  0
                 routeLogForm.setNewRouteLogActionMessage("");
 560  
 
 561  
                 // retrieve routeHeader again to pull new action taken
 562  0
                 routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, true);
 563  0
                 fixActionRequestsPositions(routeHeader);
 564  0
                 request.setAttribute("routeHeader", routeHeader);
 565  
 
 566  0
                 return mapping.findForward(getDefaultMapping());
 567  
         }
 568  
     
 569  
 }