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