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