Coverage Report - org.kuali.rice.kew.routelog.web.RouteLogAction
 
Classes in this File Line Coverage Branch Coverage Complexity
RouteLogAction
0%
0/127
0%
0/62
3.895
RouteLogAction$RouteNodeInstanceFabricator
0%
0/79
0%
0/32
3.895
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  *
 4  
  *
 5  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.opensource.org/licenses/ecl2.php
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.kuali.rice.kew.routelog.web;
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.Collections;
 22  
 import java.util.Comparator;
 23  
 import java.util.HashMap;
 24  
 import java.util.HashSet;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 import java.util.Set;
 28  
 
 29  
 import javax.servlet.http.HttpServletRequest;
 30  
 import javax.servlet.http.HttpServletResponse;
 31  
 import javax.xml.namespace.QName;
 32  
 
 33  
 import org.apache.struts.action.ActionForm;
 34  
 import org.apache.struts.action.ActionForward;
 35  
 import org.apache.struts.action.ActionMapping;
 36  
 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
 37  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 38  
 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
 39  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 40  
 import org.kuali.rice.kew.doctype.SecuritySession;
 41  
 import org.kuali.rice.kew.doctype.service.DocumentSecurityService;
 42  
 import org.kuali.rice.kew.dto.ActionRequestDTO;
 43  
 import org.kuali.rice.kew.dto.DTOConverter;
 44  
 import org.kuali.rice.kew.dto.DocumentDetailDTO;
 45  
 import org.kuali.rice.kew.dto.ReportCriteriaDTO;
 46  
 import org.kuali.rice.kew.dto.RouteNodeInstanceDTO;
 47  
 import org.kuali.rice.kew.dto.StateDTO;
 48  
 import org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader;
 49  
 import org.kuali.rice.kew.engine.node.Branch;
 50  
 import org.kuali.rice.kew.engine.node.NodeState;
 51  
 import org.kuali.rice.kew.engine.node.RouteNode;
 52  
 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
 53  
 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
 54  
 import org.kuali.rice.kew.exception.InvalidActionTakenException;
 55  
 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
 56  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 57  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 58  
 import org.kuali.rice.kew.service.WorkflowUtility;
 59  
 import org.kuali.rice.kew.util.KEWConstants;
 60  
 import org.kuali.rice.kew.util.Utilities;
 61  
 import org.kuali.rice.kew.web.KewKualiAction;
 62  
 import org.kuali.rice.kew.web.session.UserSession;
 63  
 import org.kuali.rice.kim.bo.impl.KimAttributes;
 64  
 import org.kuali.rice.kim.bo.types.dto.AttributeSet;
 65  
 import org.kuali.rice.kim.service.KIMServiceLocator;
 66  
 import org.kuali.rice.kim.util.KimConstants;
 67  
 import org.kuali.rice.kns.exception.AuthorizationException;
 68  
 
 69  
 
 70  
 /**
 71  
  * A Struts Action used to display the routelog.
 72  
  *
 73  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 74  
  */
 75  0
 public class RouteLogAction extends KewKualiAction {
 76  
 
 77  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RouteLogAction.class);
 78  0
     private static Comparator<ActionRequestValue> ROUTE_LOG_ACTION_REQUEST_SORTER = new Utilities.RouteLogActionRequestSorter();
 79  
     
 80  
     public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
 81  
 
 82  0
         RouteLogForm rlForm = (RouteLogForm) form;
 83  0
         Long routeHeaderId = null;
 84  0
         if (! Utilities.isEmpty(rlForm.getRouteHeaderId())) {
 85  0
             routeHeaderId = new Long(rlForm.getRouteHeaderId());
 86  0
         } else if (! Utilities.isEmpty(rlForm.getDocId())) {
 87  0
             routeHeaderId = new Long(rlForm.getDocId());
 88  
         } else {
 89  0
                 throw new WorkflowRuntimeException("No paramater provided to fetch document");
 90  
         }
 91  
 
 92  0
         DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(routeHeaderId);
 93  
 
 94  0
         DocumentSecurityService security = KEWServiceLocator.getDocumentSecurityService();
 95  0
         if (!security.routeLogAuthorized(getUserSession(request), routeHeader, new SecuritySession(UserSession.getAuthenticatedUser()))) {
 96  0
           return mapping.findForward("NotAuthorized");
 97  
         }
 98  
         
 99  0
         fixActionRequestsPositions(routeHeader);
 100  0
         populateRouteLogFormActionRequests(rlForm, routeHeader);
 101  
 
 102  0
         rlForm.setLookFuture(routeHeader.getDocumentType().getLookIntoFuturePolicy().getPolicyValue().booleanValue());
 103  
 
 104  0
         if (rlForm.isShowFuture()) {
 105  
             try {
 106  0
                 populateRouteLogFutureRequests(rlForm, routeHeader);
 107  0
             } catch (Exception e) {
 108  0
                 String errorMsg = "Unable to determine Future Action Requests";
 109  0
                 LOG.info(errorMsg,e);
 110  0
                 rlForm.setShowFutureError(errorMsg);
 111  0
             }
 112  
         }
 113  0
         request.setAttribute("routeHeader", routeHeader);
 114  
         
 115  
                 // check whether action message logging should be enabled, user must
 116  
                 // have KIM permission for doc type 
 117  0
         boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
 118  
                                 .canAddRouteLogMessage(UserSession.getAuthenticatedUser().getPrincipalId(), routeHeader);
 119  0
                 if (isAuthorizedToAddRouteLogMessage) {
 120  0
                         rlForm.setEnableLogAction(true);
 121  
                 } else {
 122  0
                         rlForm.setEnableLogAction(false);
 123  
                 }
 124  
         
 125  0
         return super.execute(mapping, rlForm, request, response);
 126  
     }
 127  
 
 128  
     @SuppressWarnings("unchecked")
 129  
         public void populateRouteLogFormActionRequests(RouteLogForm rlForm, DocumentRouteHeaderValue routeHeader) {
 130  0
         List<ActionRequestValue> rootRequests = getActionRequestService().getRootRequests(routeHeader.getActionRequests());
 131  0
         Collections.sort(rootRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
 132  0
         rootRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(rootRequests);
 133  0
         int arCount = 0;
 134  0
         for ( ActionRequestValue actionRequest : rootRequests ) {
 135  0
             if (actionRequest.isPending()) {
 136  0
                 arCount++;
 137  
 
 138  0
                 if (KEWConstants.ACTION_REQUEST_INITIALIZED.equals(actionRequest.getStatus())) {
 139  0
                     actionRequest.setDisplayStatus("PENDING");
 140  0
                 } else if (KEWConstants.ACTION_REQUEST_ACTIVATED.equals(actionRequest.getStatus())) {
 141  0
                     actionRequest.setDisplayStatus("IN ACTION LIST");
 142  
                 }
 143  
             }
 144  
         }
 145  0
         rlForm.setRootRequests(rootRequests);
 146  0
         rlForm.setPendingActionRequestCount(arCount);
 147  0
     }
 148  
 
 149  
     @SuppressWarnings("unchecked")
 150  
         private ActionRequestValue switchActionRequestPositionIfPrimaryDelegatePresent( ActionRequestValue actionRequest ) {
 151  
             
 152  
             /**
 153  
              * KULRICE-4756 - The main goal here is to fix the regression of what happened in Rice 1.0.2 with the display
 154  
              * of primary delegate requests.  The delegate is displayed at the top-most level correctly on action requests
 155  
              * that are "rooted" at a "role" request.
 156  
              * 
 157  
              * If they are rooted at a principal or group request, then the display of the primary delegator at the top-most
 158  
              * level does not happen (instead it shows the delegator and you have to expand the request to see the primary
 159  
              * delegate).
 160  
              * 
 161  
              * Ultimately, the KAI group and Rice BA need to come up with a specification for how the Route Log should
 162  
              * display delegate information.  For now, will fix this so that in the non "role" case, it will put the
 163  
              * primary delegate as the outermost request *except* in the case where there is more than one primary delegate.
 164  
              */
 165  
             
 166  0
             if (!actionRequest.isRoleRequest()) {
 167  0
                     List<ActionRequestValue> primaryDelegateRequests = actionRequest.getPrimaryDelegateRequests();
 168  
                     // only display primary delegate request at top if there is only *one* primary delegate request
 169  0
                     if ( primaryDelegateRequests.size() != 1) {
 170  0
                             return actionRequest;
 171  
                     }
 172  0
                     ActionRequestValue primaryDelegateRequest = primaryDelegateRequests.get(0);
 173  0
                     actionRequest.getChildrenRequests().remove(primaryDelegateRequest);
 174  0
                     primaryDelegateRequest.setChildrenRequests(actionRequest.getChildrenRequests());
 175  0
                     primaryDelegateRequest.setParentActionRequest(actionRequest.getParentActionRequest());
 176  0
                     primaryDelegateRequest.setParentActionRequestId(actionRequest.getParentActionRequestId());
 177  
                     
 178  0
                     actionRequest.setChildrenRequests( new ArrayList<ActionRequestValue>(0) );
 179  0
                     actionRequest.setParentActionRequest(primaryDelegateRequest);
 180  0
                     actionRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
 181  
                     
 182  0
                     primaryDelegateRequest.getChildrenRequests().add(0, actionRequest);
 183  
                     
 184  0
                     for (ActionRequestValue delegateRequest : primaryDelegateRequest.getChildrenRequests()) {
 185  0
                             delegateRequest.setParentActionRequest(primaryDelegateRequest);
 186  0
                             delegateRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
 187  
                     }
 188  
                     
 189  0
                     return primaryDelegateRequest;
 190  
             }
 191  
             
 192  0
             return actionRequest;
 193  
     }
 194  
 
 195  
     private List<ActionRequestValue> switchActionRequestPositionsIfPrimaryDelegatesPresent( Collection<ActionRequestValue> actionRequests ) {
 196  0
             List<ActionRequestValue> results = new ArrayList<ActionRequestValue>( actionRequests.size() );
 197  0
             for ( ActionRequestValue actionRequest : actionRequests ) {
 198  0
                         results.add( switchActionRequestPositionIfPrimaryDelegatePresent(actionRequest) );
 199  
             }
 200  0
             return results;
 201  
     }
 202  
     
 203  
     @SuppressWarnings("unchecked")
 204  
     private void fixActionRequestsPositions(DocumentRouteHeaderValue routeHeader) {
 205  0
         for (ActionTakenValue actionTaken : routeHeader.getActionsTaken()) {
 206  0
             Collections.sort((List<ActionRequestValue>) actionTaken.getActionRequests(), ROUTE_LOG_ACTION_REQUEST_SORTER);
 207  0
             actionTaken.setActionRequests( actionTaken.getActionRequests() );
 208  
         }
 209  0
     }
 210  
     
 211  
     /**
 212  
      * executes a simulation of the future routing, and sets the futureRootRequests and futureActionRequestCount
 213  
      * properties on the provided RouteLogForm.
 214  
      * 
 215  
      * @param rlForm the RouteLogForm --used in a write-only fashion.
 216  
      * @param document the DocumentRouteHeaderValue for the document whose future routing is being simulated.
 217  
      * @throws Exception
 218  
      */
 219  
     public void populateRouteLogFutureRequests(RouteLogForm rlForm, DocumentRouteHeaderValue document) throws Exception {
 220  
 
 221  0
         ReportCriteriaDTO reportCriteria = new ReportCriteriaDTO(document.getRouteHeaderId());
 222  0
         String serviceNamespace = document.getDocumentType().getServiceNamespace();
 223  0
         WorkflowUtility workflowUtility = 
 224  
                 (WorkflowUtility)GlobalResourceLoader.getService(new QName(serviceNamespace, "WorkflowUtilityService"));
 225  
 
 226  
         // gather the IDs for action requests that predate the simulation
 227  0
                 Set<Long> preexistingActionRequestIds = getActionRequestIds(document);
 228  
         
 229  
                 // run the simulation via WorkflowUtility
 230  0
         DocumentDetailDTO documentDetail = workflowUtility.routingReport(reportCriteria);
 231  
 
 232  
         // fabricate our ActionRequestValueS from the results
 233  0
         List<ActionRequestValue> futureActionRequests = 
 234  
                 reconstituteActionRequestValues(documentDetail, preexistingActionRequestIds);
 235  
 
 236  0
         Collections.sort(futureActionRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
 237  
         
 238  0
         futureActionRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(futureActionRequests);
 239  
         
 240  0
         int pendingActionRequestCount = 0;
 241  0
         for (ActionRequestValue actionRequest: futureActionRequests) {
 242  0
             if (actionRequest.isPending()) {
 243  0
                 pendingActionRequestCount++;
 244  
 
 245  0
                 if (KEWConstants.ACTION_REQUEST_INITIALIZED.equals(actionRequest.getStatus())) {
 246  0
                     actionRequest.setDisplayStatus("PENDING");
 247  0
                 } else if (KEWConstants.ACTION_REQUEST_ACTIVATED.equals(actionRequest.getStatus())) {
 248  0
                     actionRequest.setDisplayStatus("IN ACTION LIST");
 249  
                 }
 250  
             }
 251  
         }
 252  
 
 253  0
         rlForm.setFutureRootRequests(futureActionRequests);
 254  0
         rlForm.setFutureActionRequestCount(pendingActionRequestCount);
 255  0
     }
 256  
 
 257  
 
 258  
         /**
 259  
          * This utility method returns a Set of LongS containing the IDs for the ActionRequestValueS associated with 
 260  
          * this DocumentRouteHeaderValue. 
 261  
          */
 262  
         @SuppressWarnings("unchecked")
 263  
         private Set<Long> getActionRequestIds(DocumentRouteHeaderValue document) {
 264  0
                 Set<Long> actionRequestIds = new HashSet<Long>();
 265  
 
 266  0
                 List<ActionRequestValue> actionRequests = 
 267  
                         KEWServiceLocator.getActionRequestService().findAllActionRequestsByRouteHeaderId(document.getRouteHeaderId());
 268  
                 
 269  0
                 if (actionRequests != null) for (ActionRequestValue actionRequest : actionRequests) {
 270  0
                         if (actionRequest.getActionRequestId() != null) {
 271  0
                                 actionRequestIds.add(actionRequest.getActionRequestId());
 272  
                         }
 273  
                 }
 274  0
                 return actionRequestIds;
 275  
         }
 276  
 
 277  
         /**
 278  
          * This method creates ActionRequestValue objects from the DocumentDetailDTO output from 
 279  
          * {@link WorkflowUtility#routingReport(ReportCriteriaDTO)}Report()
 280  
          * 
 281  
          * @param documentDetail contains the DTOs from which the ActionRequestValues are reconstituted
 282  
          * @param preexistingActionRequestIds this is a Set of ActionRequest IDs that will not be reconstituted
 283  
          * @return the ActionRequestValueS that have been created
 284  
          */
 285  
         private List<ActionRequestValue> reconstituteActionRequestValues(DocumentDetailDTO documentDetail,
 286  
                         Set<Long> preexistingActionRequestIds) {
 287  
 
 288  0
         RouteNodeInstanceFabricator routeNodeInstanceFabricator = 
 289  
                     new RouteNodeInstanceFabricator(KEWServiceLocator.getRouteNodeService());
 290  
 
 291  0
         if (documentDetail.getNodeInstances() != null && documentDetail.getNodeInstances().length > 0) {
 292  0
                 for (RouteNodeInstanceDTO routeNodeInstanceVO : documentDetail.getNodeInstances()) {
 293  0
                         routeNodeInstanceFabricator.importRouteNodeInstanceDTO(routeNodeInstanceVO);
 294  
                 }
 295  
                 }
 296  
         
 297  0
         ActionRequestDTO[] actionRequestVOs = documentDetail.getActionRequests();
 298  0
         List<ActionRequestValue> futureActionRequests = new ArrayList<ActionRequestValue>();
 299  0
         if (actionRequestVOs != null) for (ActionRequestDTO actionRequestVO : actionRequestVOs) if (actionRequestVO != null) {
 300  0
                 if (!preexistingActionRequestIds.contains(actionRequestVO.getActionRequestId())) {
 301  0
                         ActionRequestValue converted = DTOConverter.convertActionRequestDTO(actionRequestVO, routeNodeInstanceFabricator);
 302  0
                         futureActionRequests.add(converted);
 303  
                 }
 304  
         }
 305  0
                 return futureActionRequests;
 306  
         }
 307  
     
 308  
     private ActionRequestService getActionRequestService() {
 309  0
         return (ActionRequestService) KEWServiceLocator.getService(KEWServiceLocator.ACTION_REQUEST_SRV);
 310  
     }
 311  
     
 312  
     private UserSession getUserSession(HttpServletRequest request) {
 313  0
         return UserSession.getAuthenticatedUser();
 314  
     }
 315  
     
 316  
     /**
 317  
      * Creates dummy RouteNodeInstances based on imported data from RouteNodeInstanceDTOs.
 318  
      * It is then able to vend those RouteNodeInstanceS back by their IDs.
 319  
      * 
 320  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 321  
      *
 322  
      */
 323  0
     private static class RouteNodeInstanceFabricator implements RouteNodeInstanceLoader {
 324  
 
 325  0
             private Map<Long,Branch> branches = new HashMap<Long, Branch>();;
 326  0
             private Map<Long,RouteNodeInstance> routeNodeInstances = new HashMap<Long, RouteNodeInstance>();
 327  0
             private Map<Long,RouteNode> routeNodes = new HashMap<Long, RouteNode>();
 328  0
             private Map<Long,NodeState> nodeStates = new HashMap<Long, NodeState>();
 329  
 
 330  
             private RouteNodeService routeNodeService;
 331  
             
 332  
             /**
 333  
                  * This constructs a FutureRouteNodeInstanceFabricator, which will generate bogus
 334  
                  * RouteNodeInstances for SimulationEngine results
 335  
                  * 
 336  
                  */
 337  0
                 public RouteNodeInstanceFabricator(RouteNodeService routeNodeService) {
 338  0
                         this.routeNodeService = routeNodeService;
 339  0
                 }
 340  
 
 341  
                 /**
 342  
                  * 
 343  
                  * This method looks at the given RouteNodeInstanceDTO and imports it (and all it's ancestors)
 344  
                  * as dummy RouteNodeInstanceS
 345  
                  * 
 346  
                  * @param nodeInstanceDTO
 347  
                  */
 348  
                 public void importRouteNodeInstanceDTO(RouteNodeInstanceDTO nodeInstanceDTO) {
 349  0
                         _importRouteNodeInstanceDTO(nodeInstanceDTO);
 350  0
                 }
 351  
                 
 352  
                 /**
 353  
                  * helper method for {@link #importRouteNodeInstanceDTO(RouteNodeInstanceDTO)} which does all
 354  
                  * the work.  The public method just wraps this one but hides the returned RouteNodeInstance,
 355  
                  * which is used for the recursive call to populate the nextNodeInstanceS inside our 
 356  
                  * RouteNodeInstanceS.
 357  
                  * 
 358  
                  * @param nodeInstanceDTO
 359  
                  * @return
 360  
                  */
 361  
             private RouteNodeInstance _importRouteNodeInstanceDTO(RouteNodeInstanceDTO nodeInstanceDTO) {
 362  0
                     if (nodeInstanceDTO == null) {
 363  0
                             return null;
 364  
                     }
 365  0
                     RouteNodeInstance nodeInstance = new RouteNodeInstance();
 366  0
                     nodeInstance.setActive(nodeInstanceDTO.isActive());
 367  
 
 368  0
                     nodeInstance.setComplete(nodeInstanceDTO.isComplete());
 369  0
                     nodeInstance.setDocumentId(nodeInstanceDTO.getDocumentId());
 370  0
                     nodeInstance.setInitial(nodeInstanceDTO.isInitial());
 371  
 
 372  0
                     Branch branch = getBranch(nodeInstanceDTO.getBranchId());
 373  0
                     nodeInstance.setBranch(branch);
 374  
 
 375  0
                     if (nodeInstanceDTO.getRouteNodeId() != null) {
 376  0
                             RouteNode routeNode = routeNodeService.findRouteNodeById(nodeInstanceDTO.getRouteNodeId());
 377  
 
 378  0
                             if (routeNode == null) {
 379  0
                                     routeNode = getRouteNode(nodeInstanceDTO.getRouteNodeId());
 380  0
                                     routeNode.setNodeType(nodeInstanceDTO.getName());
 381  
                             }
 382  
 
 383  0
                             nodeInstance.setRouteNode(routeNode);
 384  
 
 385  0
                             if (routeNode.getBranch() != null) {
 386  0
                                 branch.setName(routeNode.getBranch().getName());
 387  
                         } 
 388  
                     }
 389  
 
 390  0
                     RouteNodeInstance process = getRouteNodeInstance(nodeInstanceDTO.getProcessId());
 391  0
                     nodeInstance.setProcess(process);
 392  
 
 393  0
                     nodeInstance.setRouteNodeInstanceId(nodeInstanceDTO.getRouteNodeInstanceId());
 394  0
                     DTOConverter.convertState(null);
 395  
 
 396  0
                     List<NodeState> nodeState = new ArrayList<NodeState>();
 397  0
                     if (nodeInstanceDTO.getState() != null) for (StateDTO stateDTO : nodeInstanceDTO.getState()) {
 398  0
                             NodeState state = getNodeState(stateDTO.getStateId());
 399  0
                             if (state != null) {
 400  0
                                     state.setKey(stateDTO.getKey());
 401  0
                                     state.setValue(stateDTO.getValue());
 402  0
                                     state.setStateId(stateDTO.getStateId());
 403  0
                                     state.setNodeInstance(nodeInstance);
 404  0
                                     nodeState.add(state);
 405  
                             }
 406  
                     }
 407  0
                     nodeInstance.setState(nodeState);
 408  
 
 409  0
                     List<RouteNodeInstance> nextNodeInstances = new ArrayList<RouteNodeInstance>();
 410  0
                     nodeInstance.setNextNodeInstances(nextNodeInstances);
 411  
 
 412  0
                     for (RouteNodeInstanceDTO nextNodeInstanceVO : nodeInstanceDTO.getNextNodes()) {
 413  
                             // recurse to populate nextNodeInstances
 414  0
                             nextNodeInstances.add(_importRouteNodeInstanceDTO(nextNodeInstanceVO));
 415  
                     }
 416  
 
 417  0
                     routeNodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
 418  0
                     return nodeInstance;
 419  
             }
 420  
             
 421  
                 /**
 422  
                  * This method returns a dummy RouteNodeInstance for the given ID, or null if it hasn't
 423  
                  * imported from a RouteNodeInstanceDTO with that ID
 424  
                  * 
 425  
                  * @see org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader#load(java.lang.Long)
 426  
                  */
 427  
                 public RouteNodeInstance load(Long 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(Long 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(Long 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(Long 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(Long 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
                 Long routeHeaderId = null;
 532  0
                 if (!Utilities.isEmpty(routeLogForm.getRouteHeaderId())) {
 533  0
                         routeHeaderId = new Long(routeLogForm.getRouteHeaderId());
 534  0
                 } else if (!Utilities.isEmpty(routeLogForm.getDocId())) {
 535  0
                         routeHeaderId = new Long(routeLogForm.getDocId());
 536  
                 } else {
 537  0
                         throw new WorkflowRuntimeException("No paramater provided to fetch document");
 538  
                 }
 539  
                 
 540  0
                 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(routeHeaderId);
 541  
                 
 542  
                 // check user has permission to add a route log message
 543  0
                 boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
 544  
                                 .canAddRouteLogMessage(UserSession.getAuthenticatedUser().getPrincipalId(), routeHeader);
 545  
 
 546  0
                 if (!isAuthorizedToAddRouteLogMessage) {
 547  0
                         throw new InvalidActionTakenException("Principal with name '"
 548  
                                         + UserSession.getAuthenticatedUser().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 " + UserSession.getAuthenticatedUser().getPrincipalName()
 554  
                                 + ", route header id " + routeHeader);
 555  0
                 KEWServiceLocator.getWorkflowDocumentService().logDocumentAction(
 556  
                                 UserSession.getAuthenticatedUser().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(routeHeaderId, true);
 563  0
                 fixActionRequestsPositions(routeHeader);
 564  0
                 request.setAttribute("routeHeader", routeHeader);
 565  
 
 566  0
                 return mapping.findForward(getDefaultMapping());
 567  
         }
 568  
     
 569  
 }