Coverage Report - org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentRouteHeaderValue
0%
0/416
0%
0/176
1.966
 
 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.routeheader;
 17  
 
 18  
 import org.apache.commons.lang.ObjectUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.log4j.Logger;
 21  
 import org.hibernate.annotations.Fetch;
 22  
 import org.hibernate.annotations.FetchMode;
 23  
 import org.hibernate.annotations.GenericGenerator;
 24  
 import org.hibernate.annotations.Parameter;
 25  
 import org.joda.time.DateTime;
 26  
 import org.kuali.rice.core.api.exception.RiceRuntimeException;
 27  
 import org.kuali.rice.kew.actionitem.ActionItem;
 28  
 import org.kuali.rice.kew.actionlist.CustomActionListAttribute;
 29  
 import org.kuali.rice.kew.actionlist.DefaultCustomActionListAttribute;
 30  
 import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
 31  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 32  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 33  
 import org.kuali.rice.kew.api.KewApiConstants;
 34  
 import org.kuali.rice.kew.api.WorkflowRuntimeException;
 35  
 import org.kuali.rice.kew.api.document.Document;
 36  
 import org.kuali.rice.kew.api.document.DocumentContract;
 37  
 import org.kuali.rice.kew.api.document.DocumentStatus;
 38  
 import org.kuali.rice.kew.api.document.DocumentUpdate;
 39  
 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
 40  
 import org.kuali.rice.kew.api.exception.WorkflowException;
 41  
 import org.kuali.rice.kew.api.util.CodeTranslator;
 42  
 import org.kuali.rice.kew.docsearch.DocumentSearchCriteriaEbo;
 43  
 import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
 44  
 import org.kuali.rice.kew.doctype.ApplicationDocumentStatus;
 45  
 import org.kuali.rice.kew.doctype.DocumentTypePolicy;
 46  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 47  
 import org.kuali.rice.kew.engine.CompatUtils;
 48  
 import org.kuali.rice.kew.engine.node.Branch;
 49  
 import org.kuali.rice.kew.engine.node.BranchState;
 50  
 import org.kuali.rice.kew.engine.node.RouteNode;
 51  
 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
 52  
 import org.kuali.rice.kew.api.exception.ResourceUnavailableException;
 53  
 import org.kuali.rice.kew.mail.CustomEmailAttribute;
 54  
 import org.kuali.rice.kew.mail.CustomEmailAttributeImpl;
 55  
 import org.kuali.rice.kew.notes.CustomNoteAttribute;
 56  
 import org.kuali.rice.kew.notes.CustomNoteAttributeImpl;
 57  
 import org.kuali.rice.kew.notes.Note;
 58  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 59  
 import org.kuali.rice.kim.api.identity.principal.Principal;
 60  
 import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
 61  
 
 62  
 import javax.persistence.CascadeType;
 63  
 import javax.persistence.Column;
 64  
 import javax.persistence.Entity;
 65  
 import javax.persistence.FetchType;
 66  
 import javax.persistence.GeneratedValue;
 67  
 import javax.persistence.Id;
 68  
 import javax.persistence.JoinColumn;
 69  
 import javax.persistence.JoinTable;
 70  
 import javax.persistence.ManyToMany;
 71  
 import javax.persistence.NamedQueries;
 72  
 import javax.persistence.NamedQuery;
 73  
 import javax.persistence.OneToMany;
 74  
 import javax.persistence.OrderBy;
 75  
 import javax.persistence.Table;
 76  
 import javax.persistence.Transient;
 77  
 import java.sql.Timestamp;
 78  
 import java.util.ArrayList;
 79  
 import java.util.Collection;
 80  
 import java.util.HashMap;
 81  
 import java.util.Iterator;
 82  
 import java.util.List;
 83  
 import java.util.Map;
 84  
 
 85  
 
 86  
 
 87  
 /**
 88  
  * A document within KEW.  A document effectively represents a process that moves through
 89  
  * the workflow engine.  It is created from a particular {@link DocumentType} and follows
 90  
  * the route path defined by that DocumentType.
 91  
  *
 92  
  * <p>During a document's lifecycle it progresses through a series of statuses, starting
 93  
  * with INITIATED and moving to one of the terminal states (such as FINAL, CANCELED, etc).
 94  
  * The list of status on a document are defined in the {@link KewApiConstants} class and
 95  
  * include the constants starting with "ROUTE_HEADER_" and ending with "_CD".
 96  
  *
 97  
  * <p>Associated with the document is the document content.  The document content is XML
 98  
  * which represents the content of that document.  This XML content is typically used
 99  
  * to make routing decisions for the document.
 100  
  *
 101  
  * <p>A document has associated with it a set of {@link ActionRequestValue} object and
 102  
  * {@link ActionTakenValue} objects.  Action Requests represent requests for user
 103  
  * action (such as Approve, Acknowledge, etc).  Action Takens represent action that
 104  
  * users have performed on the document, such as approvals or cancelling of the document.
 105  
  *
 106  
  * <p>The instantiated route path of a document is defined by it's graph of
 107  
  * {@link RouteNodeInstance} objects.  The path starts at the initial node of the document
 108  
  * and progresses from there following the next nodes of each node instance.  The current
 109  
  * active nodes on the document are defined by the "active" flag on the node instance
 110  
  * where are not marked as "complete".
 111  
  *
 112  
  * @see DocumentType
 113  
  * @see ActionRequestValue
 114  
  * @see ActionItem
 115  
  * @see ActionTakenValue
 116  
  * @see RouteNodeInstance
 117  
  * @see KewApiConstants
 118  
  *
 119  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 120  
  */
 121  
 @Entity
 122  
 @Table(name="KREW_DOC_HDR_T")
 123  
 //@Sequence(name="KREW_DOC_HDR_S", property="documentId")
 124  
 @NamedQueries({
 125  
         @NamedQuery(name="DocumentRouteHeaderValue.FindByDocumentId", query="select d from DocumentRouteHeaderValue as d where d.documentId = :documentId"),
 126  
         @NamedQuery(name="DocumentRouteHeaderValue.QuickLinks.FindWatchedDocumentsByInitiatorWorkflowId", query="SELECT NEW org.kuali.rice.kew.quicklinks.WatchedDocument(documentId, docRouteStatus, docTitle) FROM DocumentRouteHeaderValue WHERE initiatorWorkflowId = :initiatorWorkflowId AND docRouteStatus IN ('"+ KewApiConstants.ROUTE_HEADER_ENROUTE_CD +"','"+ KewApiConstants.ROUTE_HEADER_EXCEPTION_CD +"') ORDER BY createDate DESC"),
 127  
         @NamedQuery(name="DocumentRouteHeaderValue.GetAppDocId", query="SELECT d.appDocId from DocumentRouteHeaderValue as d where d.documentId = :documentId")
 128  
 })
 129  
 public class DocumentRouteHeaderValue extends PersistableBusinessObjectBase implements DocumentContract, DocumentSearchCriteriaEbo {
 130  
     private static final long serialVersionUID = -4700736340527913220L;
 131  0
     private static final Logger LOG = Logger.getLogger(DocumentRouteHeaderValue.class);
 132  
 
 133  
     public static final String CURRENT_ROUTE_NODE_NAME_DELIMITER = ", ";
 134  
     
 135  
     @Column(name="DOC_TYP_ID")
 136  
         private String documentTypeId;
 137  
     @Column(name="DOC_HDR_STAT_CD")
 138  
         private java.lang.String docRouteStatus;
 139  
     @Column(name="RTE_LVL")
 140  
         private java.lang.Integer docRouteLevel;
 141  
         @Column(name="STAT_MDFN_DT")
 142  
         private java.sql.Timestamp statusModDate;
 143  
         @Column(name="CRTE_DT")
 144  
         private java.sql.Timestamp createDate;
 145  
         @Column(name="APRV_DT")
 146  
         private java.sql.Timestamp approvedDate;
 147  
         @Column(name="FNL_DT")
 148  
         private java.sql.Timestamp finalizedDate;
 149  
     @Transient
 150  
     private DocumentRouteHeaderValueContent documentContent;
 151  
     @Column(name="TTL")
 152  
         private java.lang.String docTitle;
 153  
     @Column(name="APP_DOC_ID")
 154  
         private java.lang.String appDocId;
 155  0
     @Column(name="DOC_VER_NBR")
 156  
     private java.lang.Integer docVersion = new Integer(KewApiConstants.DocumentContentVersions.NODAL);
 157  
     @Column(name="INITR_PRNCPL_ID")
 158  
         private java.lang.String initiatorWorkflowId;
 159  
     @Column(name="RTE_PRNCPL_ID")
 160  
         private java.lang.String routedByUserWorkflowId;
 161  
         @Column(name="RTE_STAT_MDFN_DT")
 162  
         private java.sql.Timestamp routeStatusDate;
 163  
         @Column(name="RTE_LVL_MDFN_DT")
 164  
         private java.sql.Timestamp routeLevelDate;
 165  
     @Column(name="APP_DOC_STAT")
 166  
         private java.lang.String appDocStatus;
 167  
         @Column(name="APP_DOC_STAT_MDFN_DT")
 168  
         private java.sql.Timestamp appDocStatusDate;
 169  
         
 170  
     @Id
 171  
     @GeneratedValue(generator="KREW_DOC_HDR_S")
 172  
         @GenericGenerator(name="KREW_DOC_HDR_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
 173  
                         @Parameter(name="sequence_name",value="KREW_DOC_HDR_S"),
 174  
                         @Parameter(name="value_column",value="id")
 175  
         })
 176  
         @Column(name="DOC_HDR_ID")
 177  
         private java.lang.String documentId;
 178  
     
 179  
     //@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.REMOVE, mappedBy="routeHeader")
 180  
     //@Fetch(value = FetchMode.SELECT)
 181  
     //private List<ActionRequestValue> actionRequests = new ArrayList<ActionRequestValue>();
 182  
     
 183  
     //@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.REMOVE, mappedBy="routeHeader")
 184  
     //@OrderBy("actionDate ASC")
 185  
     //@Fetch(value = FetchMode.SELECT)
 186  
     //private List<ActionTakenValue> actionsTaken = new ArrayList<ActionTakenValue>();
 187  
     
 188  
     //@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.REMOVE, mappedBy="routeHeader")
 189  
     //@Fetch(value = FetchMode.SELECT)
 190  
     //private List<ActionItem> actionItems = new ArrayList<ActionItem>();
 191  
     
 192  
     /**
 193  
      * The appDocStatusHistory keeps a list of Application Document Status transitions
 194  
      * for the document.  It tracks the previous status, the new status, and a timestamp of the 
 195  
      * transition for each status transition.
 196  
      */
 197  0
     @OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, mappedBy="documentId")
 198  
     //@JoinColumn(referencedColumnName="DOC_HDR_ID")
 199  
     @OrderBy("statusTransitionId ASC")
 200  
     @Fetch(value = FetchMode.SELECT)
 201  
     private List<DocumentStatusTransition> appDocStatusHistory = new ArrayList<DocumentStatusTransition>();
 202  
     
 203  0
     @OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.REMOVE})
 204  
     @JoinColumn(name="DOC_HDR_ID")
 205  
     @OrderBy("noteId ASC")
 206  
     private List<Note> notes = new ArrayList<Note>();
 207  
     
 208  0
     @Transient
 209  
     private List<SearchableAttributeValue> searchableAttributeValues = new ArrayList<SearchableAttributeValue>();
 210  0
     @Transient
 211  
     private Collection queueItems = new ArrayList();
 212  0
     @Transient
 213  
     private boolean routingReport = false;
 214  
     @Transient
 215  
     private List<ActionRequestValue> simulatedActionRequests;
 216  
     
 217  
     private static final boolean FINAL_STATE = true;
 218  
     protected static final HashMap<String,String> legalActions;
 219  
     protected static final HashMap<String,String> stateTransitionMap;
 220  
 
 221  
     /* New Workflow 2.1 Field */
 222  0
     @ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.REMOVE)
 223  
     @JoinTable(name = "KREW_INIT_RTE_NODE_INSTN_T", joinColumns = @JoinColumn(name = "DOC_HDR_ID"), inverseJoinColumns = @JoinColumn(name = "RTE_NODE_INSTN_ID")) 
 224  
     @Fetch(value = FetchMode.SELECT)
 225  
     private List<RouteNodeInstance> initialRouteNodeInstances = new ArrayList<RouteNodeInstance>();
 226  
 
 227  
     static {
 228  0
         stateTransitionMap = new HashMap<String,String>();
 229  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_INITIATED_CD, KewApiConstants.ROUTE_HEADER_SAVED_CD + KewApiConstants.ROUTE_HEADER_ENROUTE_CD + KewApiConstants.ROUTE_HEADER_CANCEL_CD);
 230  
 
 231  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_SAVED_CD, KewApiConstants.ROUTE_HEADER_SAVED_CD + KewApiConstants.ROUTE_HEADER_ENROUTE_CD + KewApiConstants.ROUTE_HEADER_CANCEL_CD + KewApiConstants.ROUTE_HEADER_PROCESSED_CD);
 232  
 
 233  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD +
 234  
                 KewApiConstants.ROUTE_HEADER_CANCEL_CD + KewApiConstants.ROUTE_HEADER_PROCESSED_CD + KewApiConstants.ROUTE_HEADER_EXCEPTION_CD + KewApiConstants.ROUTE_HEADER_SAVED_CD);
 235  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD, "");
 236  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_CANCEL_CD, "");
 237  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_FINAL_CD, "");
 238  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_EXCEPTION_CD, KewApiConstants.ROUTE_HEADER_EXCEPTION_CD + KewApiConstants.ROUTE_HEADER_ENROUTE_CD + KewApiConstants.ROUTE_HEADER_CANCEL_CD + KewApiConstants.ROUTE_HEADER_PROCESSED_CD + KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD + KewApiConstants.ROUTE_HEADER_SAVED_CD);
 239  0
         stateTransitionMap.put(KewApiConstants.ROUTE_HEADER_PROCESSED_CD, KewApiConstants.ROUTE_HEADER_FINAL_CD + KewApiConstants.ROUTE_HEADER_PROCESSED_CD);
 240  
 
 241  0
         legalActions = new HashMap<String,String>();
 242  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_INITIATED_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_SAVED_CD + KewApiConstants.ACTION_TAKEN_COMPLETED_CD + KewApiConstants.ACTION_TAKEN_ROUTED_CD + KewApiConstants.ACTION_TAKEN_CANCELED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD + KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD + KewApiConstants.ACTION_TAKEN_MOVE_CD);
 243  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_SAVED_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_SAVED_CD + KewApiConstants.ACTION_TAKEN_COMPLETED_CD + KewApiConstants.ACTION_TAKEN_ROUTED_CD + KewApiConstants.ACTION_TAKEN_APPROVED_CD + KewApiConstants.ACTION_TAKEN_CANCELED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD + KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD + KewApiConstants.ACTION_TAKEN_MOVE_CD);
 244  
         /* ACTION_TAKEN_ROUTED_CD not included in enroute state
 245  
          * ACTION_TAKEN_SAVED_CD removed as of version 2.4
 246  
          */
 247  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, /*KewApiConstants.ACTION_TAKEN_SAVED_CD + KewApiConstants.ACTION_TAKEN_ROUTED_CD + */KewApiConstants.ACTION_TAKEN_APPROVED_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ADHOC_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD + KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD + KewApiConstants.ACTION_TAKEN_CANCELED_CD + KewApiConstants.ACTION_TAKEN_COMPLETED_CD + KewApiConstants.ACTION_TAKEN_DENIED_CD + KewApiConstants.ACTION_TAKEN_SU_APPROVED_CD + KewApiConstants.ACTION_TAKEN_SU_CANCELED_CD + KewApiConstants.ACTION_TAKEN_SU_DISAPPROVED_CD + KewApiConstants.ACTION_TAKEN_SU_ROUTE_LEVEL_APPROVED_CD + KewApiConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD + KewApiConstants.ACTION_TAKEN_SU_RETURNED_TO_PREVIOUS_CD + KewApiConstants.ACTION_TAKEN_MOVE_CD);
 248  
         /* ACTION_TAKEN_ROUTED_CD not included in exception state
 249  
          * ACTION_TAKEN_SAVED_CD removed as of version 2.4.2
 250  
          */
 251  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_EXCEPTION_CD, /*KewApiConstants.ACTION_TAKEN_SAVED_CD + */KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD + KewApiConstants.ACTION_TAKEN_APPROVED_CD + KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD + KewApiConstants.ACTION_TAKEN_CANCELED_CD + KewApiConstants.ACTION_TAKEN_COMPLETED_CD + KewApiConstants.ACTION_TAKEN_DENIED_CD + KewApiConstants.ACTION_TAKEN_SU_APPROVED_CD + KewApiConstants.ACTION_TAKEN_SU_CANCELED_CD + KewApiConstants.ACTION_TAKEN_SU_DISAPPROVED_CD + KewApiConstants.ACTION_TAKEN_SU_ROUTE_LEVEL_APPROVED_CD + KewApiConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD + KewApiConstants.ACTION_TAKEN_SU_RETURNED_TO_PREVIOUS_CD + KewApiConstants.ACTION_TAKEN_MOVE_CD);
 252  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_FINAL_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD);
 253  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_CANCEL_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD);
 254  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD);
 255  0
         legalActions.put(KewApiConstants.ROUTE_HEADER_PROCESSED_CD, KewApiConstants.ACTION_TAKEN_FYI_CD + KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD + KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD);
 256  0
     }
 257  
 
 258  0
     public DocumentRouteHeaderValue() {
 259  0
     }
 260  
 
 261  
     public Principal getInitiatorPrincipal() {
 262  
             // if we are running a simulation, there will be no initiator
 263  0
             if (getInitiatorWorkflowId() == null) {
 264  0
                     return null;
 265  
             }
 266  0
             return KEWServiceLocator.getIdentityHelperService().getPrincipal(getInitiatorWorkflowId());
 267  
     }
 268  
     
 269  
     public Principal getRoutedByPrincipal()
 270  
     {
 271  0
             if (getRoutedByUserWorkflowId() == null) {
 272  0
                     return null;
 273  
             }
 274  0
             return KEWServiceLocator.getIdentityHelperService().getPrincipal(getRoutedByUserWorkflowId());
 275  
            }
 276  
         
 277  
     public String getInitiatorDisplayName() {
 278  0
         return KEWServiceLocator.getIdentityHelperService().getPerson(getInitiatorWorkflowId()).getName();
 279  
     }
 280  
 
 281  
     public String getRoutedByDisplayName() {
 282  0
             return KEWServiceLocator.getIdentityHelperService().getPerson(getRoutedByUserWorkflowId()).getName();
 283  
     }
 284  
         
 285  
     public String getCurrentRouteLevelName() {
 286  0
         String name = "Not Found";
 287  
         // TODO the isRouteLevelDocument junk can be ripped out
 288  0
             if(routingReport){
 289  0
                     name = "Routing Report";
 290  0
             } else if (CompatUtils.isRouteLevelDocument(this)) {
 291  0
             int routeLevelInt = getDocRouteLevel().intValue();
 292  0
             LOG.info("Getting current route level name for a Route level document: " + routeLevelInt+CURRENT_ROUTE_NODE_NAME_DELIMITER+documentId);
 293  0
             List routeLevelNodes = CompatUtils.getRouteLevelCompatibleNodeList(getDocumentType());
 294  0
             LOG.info("Route level compatible node list has " + routeLevelNodes.size() + " nodes");
 295  0
             if (routeLevelInt < routeLevelNodes.size()) {
 296  0
                 name = ((RouteNode)routeLevelNodes.get(routeLevelInt)).getRouteNodeName();
 297  
             }
 298  0
         } else {
 299  0
                 name = "";
 300  0
                 for (Iterator<String> iterator = getCurrentNodeNames().iterator(); iterator.hasNext();) {
 301  0
                         String nodeName = iterator.next();
 302  0
                         name += nodeName + (iterator.hasNext() ? CURRENT_ROUTE_NODE_NAME_DELIMITER : "");
 303  0
                 }
 304  
         }
 305  0
         return name;
 306  
     }
 307  
     
 308  
     public List<String> getCurrentNodeNames() {
 309  0
             List<String> currentNodeNames = new ArrayList<String>();
 310  0
             Collection<RouteNodeInstance> nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(getDocumentId());
 311  0
         if (nodeInstances.isEmpty()) {
 312  0
             nodeInstances = KEWServiceLocator.getRouteNodeService().getTerminalNodeInstances(getDocumentId());
 313  
         }
 314  0
         for (RouteNodeInstance nodeInstance : nodeInstances) {
 315  0
             if (nodeInstance.getRouteNode() != null) {
 316  0
                 currentNodeNames.add(nodeInstance.getRouteNode().getRouteNodeName());
 317  
             }
 318  
             else {
 319  0
                 currentNodeNames.add("");
 320  
             }
 321  
         }
 322  0
         return currentNodeNames;
 323  
     }
 324  
 
 325  
     public String getRouteStatusLabel() {
 326  0
         return CodeTranslator.getRouteStatusLabel(getDocRouteStatus());
 327  
     }
 328  
 
 329  
     public String getDocRouteStatusLabel() {
 330  0
         return CodeTranslator.getRouteStatusLabel(getDocRouteStatus());
 331  
     }
 332  
     /**
 333  
      * 
 334  
      * This method returns the Document Status Policy for the document type associated with this Route Header.
 335  
      * The Document Status Policy denotes whether the KEW Route Status, or the Application Document Status,
 336  
      * or both are to be displayed.
 337  
      * 
 338  
      * @return
 339  
      */
 340  
     public String getDocStatusPolicy() {
 341  0
             return getDocumentType().getDocumentStatusPolicy().getPolicyStringValue();
 342  
     }
 343  
     
 344  
     public Collection getQueueItems() {
 345  0
         return queueItems;
 346  
     }
 347  
 
 348  
     public void setQueueItems(Collection queueItems) {
 349  0
         this.queueItems = queueItems;
 350  0
     }
 351  
 
 352  
     public List<ActionItem> getActionItems() {
 353  0
         return (List<ActionItem>) KEWServiceLocator.getActionListService().findByDocumentId(documentId);
 354  
     }
 355  
 
 356  
     public List<ActionTakenValue> getActionsTaken() {
 357  0
         return (List<ActionTakenValue>) KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
 358  
     }
 359  
 
 360  
     public List<ActionRequestValue> getActionRequests() {
 361  0
             if (this.simulatedActionRequests == null || this.simulatedActionRequests.isEmpty()) {
 362  0
                     return KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
 363  
             } else {
 364  0
                     return this.simulatedActionRequests;
 365  
             }
 366  
     }
 367  
 
 368  
     public List<ActionRequestValue> getSimulatedActionRequests() {
 369  0
             if (this.simulatedActionRequests == null) {
 370  0
                     this.simulatedActionRequests = new ArrayList<ActionRequestValue>();
 371  
             }
 372  0
                 return this.simulatedActionRequests;
 373  
         }
 374  
 
 375  
         public void setSimulatedActionRequests(List<ActionRequestValue> simulatedActionRequests) {
 376  0
                 this.simulatedActionRequests = simulatedActionRequests;
 377  0
         }
 378  
 
 379  
         public DocumentType getDocumentType() {
 380  0
             return KEWServiceLocator.getDocumentTypeService().findById(getDocumentTypeId());
 381  
     }
 382  
 
 383  
     public java.lang.String getAppDocId() {
 384  0
         return appDocId;
 385  
     }
 386  
 
 387  
     public void setAppDocId(java.lang.String appDocId) {
 388  0
         this.appDocId = appDocId;
 389  0
     }
 390  
 
 391  
     public java.sql.Timestamp getApprovedDate() {
 392  0
         return approvedDate;
 393  
     }
 394  
 
 395  
     public void setApprovedDate(java.sql.Timestamp approvedDate) {
 396  0
         this.approvedDate = approvedDate;
 397  0
     }
 398  
 
 399  
     public java.sql.Timestamp getCreateDate() {
 400  0
         return createDate;
 401  
     }
 402  
 
 403  
     public void setCreateDate(java.sql.Timestamp createDate) {
 404  0
         this.createDate = createDate;
 405  0
     }
 406  
 
 407  
     public java.lang.String getDocContent() {
 408  0
             return getDocumentContent().getDocumentContent();
 409  
     }
 410  
 
 411  
     public void setDocContent(java.lang.String docContent) {
 412  0
             DocumentRouteHeaderValueContent content = getDocumentContent();
 413  0
             content.setDocumentContent(docContent);
 414  0
     }
 415  
 
 416  
     public java.lang.Integer getDocRouteLevel() {
 417  0
         return docRouteLevel;
 418  
     }
 419  
 
 420  
     public void setDocRouteLevel(java.lang.Integer docRouteLevel) {
 421  0
         this.docRouteLevel = docRouteLevel;
 422  0
     }
 423  
 
 424  
     public java.lang.String getDocRouteStatus() {
 425  0
         return docRouteStatus;
 426  
     }
 427  
 
 428  
     public void setDocRouteStatus(java.lang.String docRouteStatus) {
 429  0
         this.docRouteStatus = docRouteStatus;
 430  0
     }
 431  
 
 432  
     public java.lang.String getDocTitle() {
 433  0
         return docTitle;
 434  
     }
 435  
 
 436  
     public void setDocTitle(java.lang.String docTitle) {
 437  0
         this.docTitle = docTitle;
 438  0
     }
 439  
 
 440  
     @Override
 441  
     public String getDocumentTypeId() {
 442  0
         return documentTypeId;
 443  
     }
 444  
 
 445  
     public void setDocumentTypeId(String documentTypeId) {
 446  0
         this.documentTypeId = documentTypeId;
 447  0
     }
 448  
 
 449  
     public java.lang.Integer getDocVersion() {
 450  0
         return docVersion;
 451  
     }
 452  
 
 453  
     public void setDocVersion(java.lang.Integer docVersion) {
 454  0
         this.docVersion = docVersion;
 455  0
     }
 456  
 
 457  
     public java.sql.Timestamp getFinalizedDate() {
 458  0
         return finalizedDate;
 459  
     }
 460  
 
 461  
     public void setFinalizedDate(java.sql.Timestamp finalizedDate) {
 462  0
         this.finalizedDate = finalizedDate;
 463  0
     }
 464  
 
 465  
     public java.lang.String getInitiatorWorkflowId() {
 466  0
         return initiatorWorkflowId;
 467  
     }
 468  
 
 469  
     public void setInitiatorWorkflowId(java.lang.String initiatorWorkflowId) {
 470  0
         this.initiatorWorkflowId = initiatorWorkflowId;
 471  0
     }
 472  
 
 473  
     public java.lang.String getRoutedByUserWorkflowId() {
 474  0
         if ( (isEnroute()) && (StringUtils.isBlank(routedByUserWorkflowId)) ) {
 475  0
             return initiatorWorkflowId;
 476  
         }
 477  0
         return routedByUserWorkflowId;
 478  
     }
 479  
 
 480  
     public void setRoutedByUserWorkflowId(java.lang.String routedByUserWorkflowId) {
 481  0
         this.routedByUserWorkflowId = routedByUserWorkflowId;
 482  0
     }
 483  
 
 484  
     @Override
 485  
     public String getDocumentId() {
 486  0
         return documentId;
 487  
     }
 488  
 
 489  
     public void setDocumentId(java.lang.String documentId) {
 490  0
         this.documentId = documentId;
 491  0
     }
 492  
 
 493  
     public java.sql.Timestamp getRouteLevelDate() {
 494  0
         return routeLevelDate;
 495  
     }
 496  
 
 497  
     public void setRouteLevelDate(java.sql.Timestamp routeLevelDate) {
 498  0
         this.routeLevelDate = routeLevelDate;
 499  0
     }
 500  
 
 501  
     public java.sql.Timestamp getRouteStatusDate() {
 502  0
         return routeStatusDate;
 503  
     }
 504  
 
 505  
     public void setRouteStatusDate(java.sql.Timestamp routeStatusDate) {
 506  0
         this.routeStatusDate = routeStatusDate;
 507  0
     }
 508  
 
 509  
     public java.sql.Timestamp getStatusModDate() {
 510  0
         return statusModDate;
 511  
     }
 512  
 
 513  
     public void setStatusModDate(java.sql.Timestamp statusModDate) {
 514  0
         this.statusModDate = statusModDate;
 515  0
     }
 516  
 
 517  
     /**
 518  
      * 
 519  
      * This method returns the Application Document Status.
 520  
      * This status is an alternative to the Route Status that may be used for a document.
 521  
      * It is configurable per document type.
 522  
      * 
 523  
      * @see ApplicationDocumentStatus
 524  
      * @see DocumentTypePolicy
 525  
      * 
 526  
      * @return
 527  
      */
 528  
     public java.lang.String getAppDocStatus() {
 529  0
             if (appDocStatus == null || "".equals(appDocStatus)){
 530  0
                     return KewApiConstants.UNKNOWN_STATUS;
 531  
             }
 532  0
         return appDocStatus;
 533  
     }
 534  
 
 535  
     public void setAppDocStatus(java.lang.String appDocStatus){
 536  0
         this.appDocStatus = appDocStatus;
 537  0
     }
 538  
     
 539  
     /**
 540  
      * 
 541  
      * This method returns a combination of the route status label and the app doc status.
 542  
      * 
 543  
      * @return
 544  
      */
 545  
     public String getCombinedStatus(){
 546  0
             String routeStatus = getRouteStatusLabel();
 547  0
             String appStatus = getAppDocStatus();
 548  0
             if (routeStatus != null && routeStatus.length()>0){
 549  0
                     if (appStatus.length() > 0){
 550  0
                             routeStatus += ", "+appStatus;
 551  
                     }
 552  
             } else {
 553  0
                     return appStatus;
 554  
             }
 555  0
             return routeStatus;
 556  
     }
 557  
 
 558  
     /**
 559  
      * 
 560  
      * This method sets the appDocStatus.
 561  
      * It firsts validates the new value against the defined acceptable values, if defined.
 562  
      * It also updates the AppDocStatus date, and saves the status transition information
 563  
      * 
 564  
      * @param appDocStatus
 565  
      * @throws WorkflowRuntimeException
 566  
      */
 567  
     public void updateAppDocStatus(java.lang.String appDocStatus) throws WorkflowRuntimeException{
 568  
                //validate against allowable values if defined
 569  0
             if (appDocStatus != null && appDocStatus.length() > 0 && !appDocStatus.equalsIgnoreCase(this.appDocStatus)){                    
 570  0
                     DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findById(this.getDocumentTypeId());            
 571  0
                     if (documentType.getValidApplicationStatuses() != null  && documentType.getValidApplicationStatuses().size() > 0){
 572  0
                             Iterator<ApplicationDocumentStatus> iter = documentType.getValidApplicationStatuses().iterator();
 573  0
                             boolean statusValidated = false;
 574  0
                             while (iter.hasNext())
 575  
                             {
 576  0
                                     ApplicationDocumentStatus myAppDocStat = iter.next();
 577  0
                                     if (appDocStatus.compareToIgnoreCase(myAppDocStat.getStatusName()) == 0)
 578  
                                     {
 579  0
                                             statusValidated = true;
 580  0
                                             break;
 581  
                                     }
 582  0
                             }
 583  0
                             if (!statusValidated){
 584  0
                                     WorkflowRuntimeException xpee = new WorkflowRuntimeException("AppDocStatus value " +  appDocStatus + " not allowable."); 
 585  0
                                     LOG.error("Error validating nextAppDocStatus name: " +  appDocStatus + " against acceptable values.", xpee);
 586  0
                                     throw xpee; 
 587  
                             }
 588  
                     }
 589  
 
 590  
                     // set the status value
 591  0
                     String oldStatus = this.appDocStatus;
 592  0
                     this.appDocStatus = appDocStatus;
 593  
 
 594  
                     // update the timestamp
 595  0
                     setAppDocStatusDate(new Timestamp(System.currentTimeMillis()));
 596  
 
 597  
                     // save the status transition
 598  0
                     this.appDocStatusHistory.add(new DocumentStatusTransition(documentId, oldStatus, appDocStatus));
 599  
             }
 600  
 
 601  0
     }
 602  
     
 603  
     
 604  
     public java.sql.Timestamp getAppDocStatusDate() {
 605  0
         return appDocStatusDate;
 606  
     }
 607  
 
 608  
     public void setAppDocStatusDate(java.sql.Timestamp appDocStatusDate) {
 609  0
         this.appDocStatusDate = appDocStatusDate;
 610  0
     }
 611  
 
 612  
     public Object copy(boolean preserveKeys) {
 613  0
         throw new UnsupportedOperationException("The copy method is deprecated and unimplemented!");
 614  
     }
 615  
 
 616  
     /**
 617  
      * @return True if the document is in the state of Initiated
 618  
      */
 619  
     public boolean isStateInitiated() {
 620  0
         return KewApiConstants.ROUTE_HEADER_INITIATED_CD.equals(docRouteStatus);
 621  
     }
 622  
 
 623  
     /**
 624  
      * @return True if the document is in the state of Saved
 625  
      */
 626  
     public boolean isStateSaved() {
 627  0
         return KewApiConstants.ROUTE_HEADER_SAVED_CD.equals(docRouteStatus);
 628  
     }
 629  
 
 630  
     /**
 631  
      * @return true if the document has ever been inte enroute state
 632  
      */
 633  
     public boolean isRouted() {
 634  0
         return !(isStateInitiated() || isStateSaved());
 635  
     }
 636  
 
 637  
     public boolean isInException() {
 638  0
         return KewApiConstants.ROUTE_HEADER_EXCEPTION_CD.equals(docRouteStatus);
 639  
     }
 640  
 
 641  
     public boolean isDisaproved() {
 642  0
         return KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD.equals(docRouteStatus);
 643  
     }
 644  
 
 645  
     public boolean isCanceled() {
 646  0
         return KewApiConstants.ROUTE_HEADER_CANCEL_CD.equals(docRouteStatus);
 647  
     }
 648  
 
 649  
     public boolean isFinal() {
 650  0
         return KewApiConstants.ROUTE_HEADER_FINAL_CD.equals(docRouteStatus);
 651  
     }
 652  
 
 653  
     public boolean isEnroute() {
 654  0
             return KewApiConstants.ROUTE_HEADER_ENROUTE_CD.equals(docRouteStatus);
 655  
     }
 656  
 
 657  
     /**
 658  
      * @return true if the document is in the processed state
 659  
      */
 660  
     public boolean isProcessed() {
 661  0
         return KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(docRouteStatus);
 662  
     }
 663  
 
 664  
     public boolean isRoutable() {
 665  0
         return KewApiConstants.ROUTE_HEADER_ENROUTE_CD.equals(docRouteStatus) ||
 666  
                         //KewApiConstants.ROUTE_HEADER_EXCEPTION_CD.equals(docRouteStatus) ||
 667  
                         KewApiConstants.ROUTE_HEADER_SAVED_CD.equals(docRouteStatus) ||
 668  
                         KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(docRouteStatus);
 669  
     }
 670  
 
 671  
     /**
 672  
      * Return true if the given action code is valid for this document's current state.
 673  
      *
 674  
      * @param actionCd
 675  
      *            The action code to be tested.
 676  
      * @return True if the action code is valid for the document's status.
 677  
      */
 678  
     public boolean isValidActionToTake(String actionCd) {
 679  0
         String actions = (String) legalActions.get(docRouteStatus);
 680  0
         if (!actions.contains(actionCd)) {
 681  0
             return false;
 682  
         } else {
 683  0
             return true;
 684  
         }
 685  
     }
 686  
 
 687  
     public boolean isValidStatusChange(String newStatus) {
 688  0
             return ((String) stateTransitionMap.get(getDocRouteStatus())).contains(newStatus);
 689  
     }
 690  
 
 691  
     public void setRouteStatus(String newStatus, boolean finalState) throws InvalidActionTakenException {
 692  0
         if (newStatus != getDocRouteStatus()) {
 693  
             // only modify the status mod date if the status actually changed
 694  0
             setRouteStatusDate(new Timestamp(System.currentTimeMillis()));
 695  
         }
 696  0
         if (((String) stateTransitionMap.get(getDocRouteStatus())).contains(newStatus)) {
 697  0
             LOG.debug("changing status");
 698  0
             setDocRouteStatus(newStatus);
 699  
         } else {
 700  0
             LOG.debug("unable to change status");
 701  0
             throw new InvalidActionTakenException("Document status " + CodeTranslator.getRouteStatusLabel(getDocRouteStatus()) + " cannot transition to status " + CodeTranslator
 702  
                     .getRouteStatusLabel(newStatus));
 703  
         }
 704  0
         setStatusModDate(new Timestamp(System.currentTimeMillis()));
 705  0
         if (finalState) {
 706  0
             LOG.debug("setting final timeStamp");
 707  0
             setFinalizedDate(new Timestamp(System.currentTimeMillis()));
 708  
         }
 709  0
     }
 710  
 
 711  
     /**
 712  
      * Mark the document as being processed.
 713  
      *
 714  
      * @throws org.kuali.rice.kew.api.exception.ResourceUnavailableException
 715  
      * @throws InvalidActionTakenException
 716  
      */
 717  
     public void markDocumentProcessed() throws InvalidActionTakenException {
 718  0
         LOG.debug(this + " marked processed");
 719  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_PROCESSED_CD, !FINAL_STATE);
 720  0
     }
 721  
 
 722  
     /**
 723  
      * Mark document cancled.
 724  
      *
 725  
      * @throws org.kuali.rice.kew.api.exception.ResourceUnavailableException
 726  
      * @throws InvalidActionTakenException
 727  
      */
 728  
     public void markDocumentCanceled() throws InvalidActionTakenException {
 729  0
         LOG.debug(this + " marked canceled");
 730  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_CANCEL_CD, FINAL_STATE);
 731  0
     }
 732  
 
 733  
     /**
 734  
      * Mark document disapproved
 735  
      *
 736  
      * @throws ResourceUnavailableException
 737  
      * @throws InvalidActionTakenException
 738  
      */
 739  
     public void markDocumentDisapproved() throws InvalidActionTakenException {
 740  0
         LOG.debug(this + " marked disapproved");
 741  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD, FINAL_STATE);
 742  0
     }
 743  
 
 744  
     /**
 745  
      * Mark document saved
 746  
      *
 747  
      * @throws org.kuali.rice.kew.api.exception.ResourceUnavailableException
 748  
      * @throws InvalidActionTakenException
 749  
      */
 750  
     public void markDocumentSaved() throws InvalidActionTakenException {
 751  0
         LOG.debug(this + " marked saved");
 752  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_SAVED_CD, !FINAL_STATE);
 753  0
     }
 754  
 
 755  
     /**
 756  
      * Mark the document as being in the exception state.
 757  
      *
 758  
      * @throws org.kuali.rice.kew.api.exception.ResourceUnavailableException
 759  
      * @throws InvalidActionTakenException
 760  
      */
 761  
     public void markDocumentInException() throws InvalidActionTakenException {
 762  0
         LOG.debug(this + " marked in exception");
 763  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_EXCEPTION_CD, !FINAL_STATE);
 764  0
     }
 765  
 
 766  
     /**
 767  
      * Mark the document as being actively routed.
 768  
      *
 769  
      * @throws ResourceUnavailableException
 770  
      * @throws InvalidActionTakenException
 771  
      */
 772  
     public void markDocumentEnroute() throws InvalidActionTakenException {
 773  0
         LOG.debug(this + " marked enroute");
 774  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, !FINAL_STATE);
 775  0
     }
 776  
 
 777  
     /**
 778  
      * Mark document finalized.
 779  
      *
 780  
      * @throws ResourceUnavailableException
 781  
      * @throws InvalidActionTakenException
 782  
      */
 783  
     public void markDocumentFinalized() throws InvalidActionTakenException {
 784  0
         LOG.debug(this + " marked finalized");
 785  0
         setRouteStatus(KewApiConstants.ROUTE_HEADER_FINAL_CD, FINAL_STATE);
 786  0
     }
 787  
 
 788  
     /**
 789  
      * This method takes data from a VO and sets it on this route header
 790  
      * @param routeHeaderVO
 791  
      * @throws org.kuali.rice.kew.api.exception.WorkflowException
 792  
      */
 793  
     public void setRouteHeaderData(Document routeHeaderVO) throws WorkflowException {
 794  0
         if (!ObjectUtils.equals(getDocTitle(), routeHeaderVO.getTitle())) {
 795  0
                 KEWServiceLocator.getActionListService().updateActionItemsForTitleChange(getDocumentId(), routeHeaderVO.getTitle());
 796  
         }
 797  0
         setDocTitle(routeHeaderVO.getTitle());
 798  0
         setAppDocId(routeHeaderVO.getApplicationDocumentId());
 799  0
         setStatusModDate(new Timestamp(System.currentTimeMillis()));
 800  0
         updateAppDocStatus(routeHeaderVO.getApplicationDocumentStatus());
 801  
 
 802  
         /* set the variables from the routeHeaderVO */
 803  0
         for (Map.Entry<String, String> kvp : routeHeaderVO.getVariables().entrySet()) {
 804  0
             setVariable(kvp.getKey(), kvp.getValue());
 805  
         }
 806  0
     }
 807  
     
 808  
     public void applyDocumentUpdate(DocumentUpdate documentUpdate) {
 809  0
             if (documentUpdate != null) {
 810  0
                     String thisDocTitle = getDocTitle() == null ? "" : getDocTitle();
 811  0
                     String updateDocTitle = documentUpdate.getTitle() == null ? "" : documentUpdate.getTitle();
 812  0
                     if (!StringUtils.equals(thisDocTitle, updateDocTitle)) {
 813  0
                     KEWServiceLocator.getActionListService().updateActionItemsForTitleChange(getDocumentId(), documentUpdate.getTitle());
 814  
             }
 815  0
             setDocTitle(updateDocTitle);
 816  0
             setAppDocId(documentUpdate.getApplicationDocumentId());
 817  0
             setStatusModDate(new Timestamp(System.currentTimeMillis()));
 818  0
             updateAppDocStatus(documentUpdate.getApplicationDocumentStatus());
 819  
             
 820  0
             Map<String, String> variables = documentUpdate.getVariables();
 821  0
             for (String variableName : variables.keySet()) {
 822  0
                 setVariable(variableName, variables.get(variableName));
 823  
             }
 824  
             }
 825  0
     }
 826  
 
 827  
     /**
 828  
      * Convenience method that returns the branch of the first (and presumably only?) initial node
 829  
      * @return the branch of the first (and presumably only?) initial node
 830  
      */
 831  
     public Branch getRootBranch() {
 832  0
         if (!this.initialRouteNodeInstances.isEmpty()) {
 833  0
             return ((RouteNodeInstance) getInitialRouteNodeInstance(0)).getBranch();
 834  
         } 
 835  0
         return null;
 836  
     }
 837  
 
 838  
     /**
 839  
      * Looks up a variable (embodied in a "BranchState" key/value pair) in the
 840  
      * branch state table.
 841  
      */
 842  
     private BranchState findVariable(String name) {
 843  0
         Branch rootBranch = getRootBranch();
 844  0
         if (rootBranch != null) {
 845  0
             List<BranchState> branchState = rootBranch.getBranchState();
 846  0
             Iterator<BranchState> it = branchState.iterator();
 847  0
             while (it.hasNext()) {
 848  0
                 BranchState state = it.next();
 849  0
                 if (ObjectUtils.equals(state.getKey(), BranchState.VARIABLE_PREFIX + name)) {
 850  0
                     return state;
 851  
                 }
 852  0
             }
 853  
         }
 854  0
         return null;
 855  
     }
 856  
 
 857  
     /**
 858  
      * Gets a variable
 859  
      * @param name variable name
 860  
      * @return variable value, or null if variable is not defined
 861  
      */
 862  
     public String getVariable(String name) {
 863  0
         BranchState state = findVariable(name);
 864  0
         if (state == null) {
 865  0
             LOG.debug("Variable not found: '" + name + "'");
 866  0
             return null;
 867  
         }
 868  0
         return state.getValue();
 869  
     }
 870  
 
 871  
     public void removeVariableThatContains(String name) {
 872  0
         List<BranchState> statesToRemove = new ArrayList<BranchState>();
 873  0
         for (BranchState state : this.getRootBranchState()) {
 874  0
             if (state.getKey().contains(name)) {
 875  0
                 statesToRemove.add(state);
 876  
             }
 877  
         }
 878  0
         this.getRootBranchState().removeAll(statesToRemove);
 879  0
     }
 880  
     
 881  
     /**
 882  
      * Sets a variable
 883  
      * @param name variable name
 884  
      * @param value variable value, or null if variable should be removed
 885  
      */
 886  
     public void setVariable(String name, String value) {
 887  0
         BranchState state = findVariable(name);
 888  0
         Branch rootBranch = getRootBranch();
 889  0
         if (rootBranch != null) {
 890  0
             List<BranchState> branchState = rootBranch.getBranchState();
 891  0
             if (state == null) {
 892  0
                 if (value == null) {
 893  0
                     LOG.debug("set non existent variable '" + name + "' to null value");
 894  0
                     return;
 895  
                 }
 896  0
                 LOG.debug("Adding branch state: '" + name + "'='" + value + "'");
 897  0
                 state = new BranchState();
 898  0
                 state.setBranch(rootBranch);
 899  0
                 state.setKey(BranchState.VARIABLE_PREFIX + name);
 900  0
                 state.setValue(value);
 901  0
                 rootBranch.addBranchState(state);
 902  
             } else {
 903  0
                 if (value == null) {
 904  0
                     LOG.debug("Removing value: " + state.getKey() + "=" + state.getValue());
 905  0
                     branchState.remove(state);
 906  
                 } else {
 907  0
                     LOG.debug("Setting value of variable '" + name + "' to '" + value + "'");
 908  0
                     state.setValue(value);
 909  
                 }
 910  
             }
 911  
         }
 912  0
     }
 913  
     
 914  
     public List<BranchState> getRootBranchState() {
 915  0
         if (this.getRootBranch() != null) {
 916  0
             return this.getRootBranch().getBranchState();
 917  
         }
 918  0
         return null;
 919  
     }
 920  
 
 921  
     public CustomActionListAttribute getCustomActionListAttribute() throws WorkflowException {
 922  0
         CustomActionListAttribute customActionListAttribute = null;
 923  0
         if (this.getDocumentType() != null) {
 924  0
                 customActionListAttribute = this.getDocumentType().getCustomActionListAttribute();
 925  0
                 if (customActionListAttribute != null) {
 926  0
                         return customActionListAttribute;
 927  
                 }
 928  
         }
 929  0
         customActionListAttribute = new DefaultCustomActionListAttribute();
 930  0
         return customActionListAttribute;
 931  
     }
 932  
 
 933  
     public CustomEmailAttribute getCustomEmailAttribute() throws WorkflowException {
 934  0
         CustomEmailAttribute customEmailAttribute = null;
 935  
         try {
 936  0
             if (this.getDocumentType() != null) {
 937  0
                 customEmailAttribute = this.getDocumentType().getCustomEmailAttribute();
 938  0
                 if (customEmailAttribute != null) {
 939  0
                     customEmailAttribute.setRouteHeaderVO(DocumentRouteHeaderValue.to(this));
 940  0
                     return customEmailAttribute;
 941  
                 }
 942  
             }
 943  0
         } catch (Exception e) {
 944  0
             LOG.debug("Error in retrieving custom email attribute", e);
 945  0
         }
 946  0
         customEmailAttribute = new CustomEmailAttributeImpl();
 947  0
         customEmailAttribute.setRouteHeaderVO(DocumentRouteHeaderValue.to(this));
 948  0
         return customEmailAttribute;
 949  
     }
 950  
 
 951  
     public CustomNoteAttribute getCustomNoteAttribute() throws WorkflowException
 952  
     {
 953  0
         CustomNoteAttribute customNoteAttribute = null;
 954  
         try {
 955  0
             if (this.getDocumentType() != null) {
 956  0
                 customNoteAttribute = this.getDocumentType().getCustomNoteAttribute();
 957  0
                 if (customNoteAttribute != null) {
 958  0
                     customNoteAttribute.setRouteHeaderVO(DocumentRouteHeaderValue.to(this));
 959  0
                     return customNoteAttribute;
 960  
                 }
 961  
             }
 962  0
         } catch (Exception e) {
 963  0
             LOG.debug("Error in retrieving custom note attribute", e);
 964  0
         }
 965  0
         customNoteAttribute = new CustomNoteAttributeImpl();
 966  0
         customNoteAttribute.setRouteHeaderVO(DocumentRouteHeaderValue.to(this));
 967  0
         return customNoteAttribute;
 968  
     }
 969  
 
 970  
     public ActionRequestValue getDocActionRequest(int index) {
 971  0
             List<ActionRequestValue> actionRequests = getActionRequests();
 972  0
         while (actionRequests.size() <= index) {
 973  0
                 ActionRequestValue actionRequest = new ActionRequestFactory(this).createBlankActionRequest();
 974  0
                 actionRequest.setNodeInstance(new RouteNodeInstance());
 975  0
             actionRequests.add(actionRequest);
 976  0
         }
 977  0
         return (ActionRequestValue) actionRequests.get(index);
 978  
     }
 979  
 
 980  
     public ActionTakenValue getDocActionTaken(int index) {
 981  0
             List<ActionTakenValue> actionsTaken = getActionsTaken();
 982  0
         while (actionsTaken.size() <= index) {
 983  0
             actionsTaken.add(new ActionTakenValue());
 984  
         }
 985  0
         return (ActionTakenValue) actionsTaken.get(index);
 986  
     }
 987  
 
 988  
     public ActionItem getDocActionItem(int index) {
 989  0
             List<ActionItem> actionItems = getActionItems();
 990  0
         while (actionItems.size() <= index) {
 991  0
             actionItems.add(new ActionItem());
 992  
         }
 993  0
         return (ActionItem) actionItems.get(index);
 994  
     }
 995  
 
 996  
     private RouteNodeInstance getInitialRouteNodeInstance(int index) {
 997  0
             if (initialRouteNodeInstances.size() >= index) {
 998  0
                 return (RouteNodeInstance) initialRouteNodeInstances.get(index);
 999  
             } 
 1000  0
             return null;
 1001  
     }
 1002  
 
 1003  
 //        /**
 1004  
 //         * @param searchableAttributeValues The searchableAttributeValues to set.
 1005  
 //         */
 1006  
 //        public void setSearchableAttributeValues(List<SearchableAttributeValue> searchableAttributeValues) {
 1007  
 //                this.searchableAttributeValues = searchableAttributeValues;
 1008  
 //        }
 1009  
 //
 1010  
 //        /**
 1011  
 //         * @return Returns the searchableAttributeValues.
 1012  
 //         */
 1013  
 //        public List<SearchableAttributeValue> getSearchableAttributeValues() {
 1014  
 //                return searchableAttributeValues;
 1015  
 //        }
 1016  
 
 1017  
         public boolean isRoutingReport() {
 1018  0
                 return routingReport;
 1019  
         }
 1020  
 
 1021  
         public void setRoutingReport(boolean routingReport) {
 1022  0
                 this.routingReport = routingReport;
 1023  0
         }
 1024  
 
 1025  
     public List<RouteNodeInstance> getInitialRouteNodeInstances() {
 1026  0
         return initialRouteNodeInstances;
 1027  
     }
 1028  
 
 1029  
     public void setInitialRouteNodeInstances(List<RouteNodeInstance> initialRouteNodeInstances) {
 1030  0
         this.initialRouteNodeInstances = initialRouteNodeInstances;
 1031  0
     }
 1032  
 
 1033  
         public List<Note> getNotes() {
 1034  0
                 return notes;
 1035  
         }
 1036  
 
 1037  
         public void setNotes(List<Note> notes) {
 1038  0
                 this.notes = notes;
 1039  0
         }
 1040  
 
 1041  
         public DocumentRouteHeaderValueContent getDocumentContent() {
 1042  0
                 if (documentContent == null) {
 1043  0
                         documentContent = KEWServiceLocator.getRouteHeaderService().getContent(getDocumentId());
 1044  
                 }
 1045  0
                 return documentContent;
 1046  
         }
 1047  
 
 1048  
         public void setDocumentContent(DocumentRouteHeaderValueContent documentContent) {
 1049  0
                 this.documentContent = documentContent;
 1050  0
         }
 1051  
 
 1052  
         public List<DocumentStatusTransition> getAppDocStatusHistory() {
 1053  0
                 return this.appDocStatusHistory;
 1054  
         }
 1055  
 
 1056  
         public void setAppDocStatusHistory(
 1057  
                         List<DocumentStatusTransition> appDocStatusHistory) {
 1058  0
                 this.appDocStatusHistory = appDocStatusHistory;
 1059  0
         }
 1060  
         
 1061  
         @Override
 1062  
         public DocumentStatus getStatus() {
 1063  0
                 return DocumentStatus.fromCode(getDocRouteStatus());
 1064  
         }
 1065  
         
 1066  
         @Override
 1067  
         public DateTime getDateCreated() {
 1068  0
                 if (getCreateDate() == null) {
 1069  0
                         return null;
 1070  
                 }
 1071  0
                 return new DateTime(getCreateDate().getTime());
 1072  
         }
 1073  
         
 1074  
         @Override
 1075  
         public DateTime getDateLastModified() {
 1076  0
                 if (getStatusModDate() == null) {
 1077  0
                         return null;
 1078  
                 }
 1079  0
                 return new DateTime(getStatusModDate().getTime());
 1080  
         }
 1081  
 
 1082  
         @Override
 1083  
         public DateTime getDateApproved() {
 1084  0
                 if (getApprovedDate() == null) {
 1085  0
                         return null;
 1086  
                 }
 1087  0
                 return new DateTime(getApprovedDate().getTime());
 1088  
         }
 1089  
 
 1090  
         @Override
 1091  
         public DateTime getDateFinalized() {
 1092  0
                 if (getFinalizedDate() == null) {
 1093  0
                         return null;
 1094  
                 }
 1095  0
                 return new DateTime(getFinalizedDate().getTime());
 1096  
         }
 1097  
         
 1098  
         @Override
 1099  
         public String getTitle() {
 1100  0
                 return docTitle;
 1101  
         }
 1102  
 
 1103  
         @Override
 1104  
         public String getApplicationDocumentId() {
 1105  0
                 return appDocId;
 1106  
         }
 1107  
 
 1108  
         @Override
 1109  
         public String getInitiatorPrincipalId() {
 1110  0
                 return initiatorWorkflowId;
 1111  
         }
 1112  
 
 1113  
         @Override
 1114  
         public String getRoutedByPrincipalId() {
 1115  0
                 return routedByUserWorkflowId;
 1116  
         }
 1117  
         
 1118  
         @Override
 1119  
         public String getDocumentTypeName() {
 1120  0
                 return getDocumentType().getName();
 1121  
         }
 1122  
         
 1123  
         @Override
 1124  
         public String getDocumentHandlerUrl() {
 1125  0
                 return getDocumentType().getDocHandlerUrl();
 1126  
         }
 1127  
         
 1128  
         @Override
 1129  
         public String getApplicationDocumentStatus() {
 1130  0
                 return appDocStatus;
 1131  
         }
 1132  
         
 1133  
         @Override
 1134  
         public DateTime getApplicationDocumentStatusDate() {
 1135  0
                 if (appDocStatusDate == null) {
 1136  0
                         return null;
 1137  
                 }
 1138  0
                 return new DateTime(appDocStatusDate.getTime());
 1139  
         }
 1140  
         
 1141  
         @Override
 1142  
         public Map<String, String> getVariables() {
 1143  0
                 Map<String, String> documentVariables = new HashMap<String, String>();
 1144  
                 /* populate the routeHeaderVO with the document variables */
 1145  
         // FIXME: we assume there is only one for now
 1146  0
         Branch routeNodeInstanceBranch = getRootBranch();
 1147  
         // Ok, we are using the "branch state" as the arbitrary convenient repository for flow/process/edoc variables
 1148  
         // so we need to stuff them into the VO
 1149  0
         if (routeNodeInstanceBranch != null) {
 1150  0
             List<BranchState> listOfBranchStates = routeNodeInstanceBranch.getBranchState();
 1151  0
             for (BranchState bs : listOfBranchStates) {
 1152  0
                 if (bs.getKey() != null && bs.getKey().startsWith(BranchState.VARIABLE_PREFIX)) {
 1153  0
                     LOG.debug("Setting branch state variable on vo: " + bs.getKey() + "=" + bs.getValue());
 1154  0
                     documentVariables.put(bs.getKey().substring(BranchState.VARIABLE_PREFIX.length()), bs.getValue());
 1155  
                 }
 1156  
             }
 1157  
         }
 1158  0
         return documentVariables;
 1159  
         }
 1160  
 
 1161  
         public static Document to(DocumentRouteHeaderValue documentBo) {
 1162  0
                 if (documentBo == null) {
 1163  0
                         return null;
 1164  
                 }
 1165  0
                 Document.Builder builder = Document.Builder.create(documentBo);
 1166  0
                 return builder.build();
 1167  
         }
 1168  
         
 1169  
         public static DocumentRouteHeaderValue from(Document document) {
 1170  0
             DocumentRouteHeaderValue documentBo = new DocumentRouteHeaderValue();
 1171  0
         documentBo.setAppDocId(document.getApplicationDocumentId());
 1172  0
         if (document.getDateApproved() != null) {
 1173  0
             documentBo.setApprovedDate(new Timestamp(document.getDateApproved().getMillis()));
 1174  
         }
 1175  0
         if (document.getDateCreated() != null) {
 1176  0
             documentBo.setCreateDate(new Timestamp(document.getDateCreated().getMillis()));
 1177  
         }
 1178  0
         if (StringUtils.isEmpty(documentBo.getDocContent())) {
 1179  0
             documentBo.setDocContent(KewApiConstants.DEFAULT_DOCUMENT_CONTENT);
 1180  
         }
 1181  0
         documentBo.setDocRouteStatus(document.getStatus().getCode());
 1182  0
         documentBo.setDocTitle(document.getTitle());
 1183  0
         if (document.getDocumentTypeName() != null) {
 1184  0
             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(document.getDocumentTypeName());
 1185  0
             if (documentType == null) {
 1186  0
                 throw new RiceRuntimeException("Could not locate the given document type name: " + document.getDocumentTypeName());
 1187  
             }
 1188  0
             documentBo.setDocumentTypeId(documentType.getDocumentTypeId());
 1189  
         }
 1190  0
         if (document.getDateFinalized() != null) {
 1191  0
             documentBo.setFinalizedDate(new Timestamp(document.getDateFinalized().getMillis()));
 1192  
         }
 1193  0
         documentBo.setInitiatorWorkflowId(document.getInitiatorPrincipalId());
 1194  0
         documentBo.setRoutedByUserWorkflowId(document.getRoutedByPrincipalId());
 1195  0
         documentBo.setDocumentId(document.getDocumentId());
 1196  0
         if (document.getDateLastModified() != null) {
 1197  0
             documentBo.setStatusModDate(new Timestamp(document.getDateLastModified().getMillis()));
 1198  
         }
 1199  0
         documentBo.setAppDocStatus(document.getApplicationDocumentStatus());
 1200  0
         if (document.getApplicationDocumentStatusDate() != null) {
 1201  0
             documentBo.setAppDocStatusDate(new Timestamp(document.getApplicationDocumentStatusDate().getMillis()));
 1202  
         }
 1203  
 
 1204  
         
 1205  
         // Convert the variables
 1206  0
         Map<String, String> variables = document.getVariables();
 1207  0
         if( variables != null && !variables.isEmpty()){
 1208  0
             for(String kvp : variables.keySet()){
 1209  0
                 documentBo.setVariable(kvp, variables.get(kvp));
 1210  
             }
 1211  
         }
 1212  
         
 1213  0
         return documentBo;
 1214  
         }
 1215  
 
 1216  
 }