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