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