1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.commons.lang.time.StopWatch;
20 import org.kuali.rice.core.api.CoreApiServiceLocator;
21 import org.kuali.rice.core.api.config.ConfigurationException;
22 import org.kuali.rice.core.api.config.property.ConfigurationService;
23 import org.kuali.rice.core.api.datetime.DateTimeService;
24 import org.kuali.rice.core.api.util.RiceKeyConstants;
25 import org.kuali.rice.core.framework.persistence.jta.TransactionalNoValidationExceptionRollback;
26 import org.kuali.rice.kew.api.WorkflowDocument;
27 import org.kuali.rice.kew.api.exception.WorkflowException;
28 import org.kuali.rice.kim.api.identity.Person;
29 import org.kuali.rice.kim.api.identity.PersonService;
30 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
31 import org.kuali.rice.krad.UserSessionUtils;
32 import org.kuali.rice.krad.UserSession;
33 import org.kuali.rice.krad.bo.AdHocRoutePerson;
34 import org.kuali.rice.krad.bo.AdHocRouteRecipient;
35 import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
36 import org.kuali.rice.krad.bo.BusinessObject;
37 import org.kuali.rice.krad.bo.DocumentHeader;
38 import org.kuali.rice.krad.bo.Note;
39 import org.kuali.rice.krad.bo.PersistableBusinessObject;
40 import org.kuali.rice.krad.dao.DocumentDao;
41 import org.kuali.rice.krad.datadictionary.exception.UnknownDocumentTypeException;
42 import org.kuali.rice.krad.document.Document;
43 import org.kuali.rice.krad.document.DocumentAuthorizer;
44 import org.kuali.rice.krad.document.DocumentPresentationController;
45 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
46 import org.kuali.rice.krad.maintenance.MaintenanceDocumentBase;
47 import org.kuali.rice.krad.exception.DocumentAuthorizationException;
48 import org.kuali.rice.krad.exception.ValidationException;
49 import org.kuali.rice.krad.rules.rule.event.ApproveDocumentEvent;
50 import org.kuali.rice.krad.rules.rule.event.BlanketApproveDocumentEvent;
51 import org.kuali.rice.krad.rules.rule.event.CompleteDocumentEvent;
52 import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
53 import org.kuali.rice.krad.rules.rule.event.RouteDocumentEvent;
54 import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent;
55 import org.kuali.rice.krad.rules.rule.event.SaveEvent;
56 import org.kuali.rice.krad.service.BusinessObjectService;
57 import org.kuali.rice.krad.service.DataDictionaryService;
58 import org.kuali.rice.krad.service.DocumentDictionaryService;
59 import org.kuali.rice.krad.service.DocumentHeaderService;
60 import org.kuali.rice.krad.service.DocumentService;
61 import org.kuali.rice.krad.service.KRADServiceLocator;
62 import org.kuali.rice.krad.service.KRADServiceLocatorInternal;
63 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
64 import org.kuali.rice.krad.service.NoteService;
65 import org.kuali.rice.krad.util.GlobalVariables;
66 import org.kuali.rice.krad.util.KRADConstants;
67 import org.kuali.rice.krad.util.NoteType;
68 import org.kuali.rice.krad.util.ObjectUtils;
69 import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
70 import org.springframework.dao.OptimisticLockingFailureException;
71
72 import java.lang.reflect.Constructor;
73 import java.lang.reflect.InvocationTargetException;
74 import java.text.MessageFormat;
75 import java.util.ArrayList;
76 import java.util.HashMap;
77 import java.util.List;
78 import java.util.Map;
79
80
81
82
83
84
85
86
87
88
89 @TransactionalNoValidationExceptionRollback
90 public class DocumentServiceImpl implements DocumentService {
91 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentServiceImpl.class);
92
93 private DocumentDao documentDao;
94
95 private DateTimeService dateTimeService;
96 private NoteService noteService;
97 private WorkflowDocumentService workflowDocumentService;
98 private BusinessObjectService businessObjectService;
99 private DataDictionaryService dataDictionaryService;
100 private DocumentHeaderService documentHeaderService;
101 private DocumentDictionaryService documentDictionaryService;
102 private PersonService personService;
103 private ConfigurationService kualiConfigurationService;
104
105
106
107
108 @Override
109 public Document saveDocument(Document document) throws WorkflowException, ValidationException {
110 return saveDocument(document, SaveDocumentEvent.class);
111 }
112
113 @Override
114 public Document saveDocument(Document document,
115 Class<? extends KualiDocumentEvent> kualiDocumentEventClass) throws WorkflowException, ValidationException {
116 checkForNulls(document);
117 if (kualiDocumentEventClass == null) {
118 throw new IllegalArgumentException("invalid (null) kualiDocumentEventClass");
119 }
120
121 if (!SaveEvent.class.isAssignableFrom(kualiDocumentEventClass)) {
122 throw new ConfigurationException("The KualiDocumentEvent class '" + kualiDocumentEventClass.getName() +
123 "' does not implement the class '" + SaveEvent.class.getName() + "'");
124 }
125
126
127
128 document.prepareForSave();
129 Document savedDocument = validateAndPersistDocumentAndSaveAdHocRoutingRecipients(document,
130 generateKualiDocumentEvent(document, kualiDocumentEventClass));
131 prepareWorkflowDocument(savedDocument);
132 getWorkflowDocumentService().save(savedDocument.getDocumentHeader().getWorkflowDocument(), null);
133
134 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
135 savedDocument.getDocumentHeader().getWorkflowDocument());
136
137 return savedDocument;
138 }
139
140 private KualiDocumentEvent generateKualiDocumentEvent(Document document,
141 Class<? extends KualiDocumentEvent> eventClass) throws ConfigurationException {
142 String potentialErrorMessage =
143 "Found error trying to generate Kuali Document Event using event class '" + eventClass.getName() +
144 "' for document " + document.getDocumentNumber();
145
146 try {
147 Constructor<?> usableConstructor = null;
148 List<Object> paramList = new ArrayList<Object>();
149 for (Constructor<?> currentConstructor : eventClass.getConstructors()) {
150 for (Class<?> parameterClass : currentConstructor.getParameterTypes()) {
151 if (Document.class.isAssignableFrom(parameterClass)) {
152 usableConstructor = currentConstructor;
153 paramList.add(document);
154 } else {
155 paramList.add(null);
156 }
157 }
158 if (ObjectUtils.isNotNull(usableConstructor)) {
159 break;
160 }
161 }
162 if (usableConstructor == null) {
163 throw new RuntimeException("Cannot find a constructor for class '" + eventClass.getName() +
164 "' that takes in a document parameter");
165 }
166 return (KualiDocumentEvent) usableConstructor.newInstance(paramList.toArray());
167 } catch (SecurityException e) {
168 throw new ConfigurationException(potentialErrorMessage, e);
169 } catch (IllegalArgumentException e) {
170 throw new ConfigurationException(potentialErrorMessage, e);
171 } catch (InstantiationException e) {
172 throw new ConfigurationException(potentialErrorMessage, e);
173 } catch (IllegalAccessException e) {
174 throw new ConfigurationException(potentialErrorMessage, e);
175 } catch (InvocationTargetException e) {
176 throw new ConfigurationException(potentialErrorMessage, e);
177 }
178 }
179
180
181
182
183
184 @Override
185 public Document routeDocument(Document document, String annotation,
186 List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
187 checkForNulls(document);
188
189
190
191 document.prepareForSave();
192 Document savedDocument = validateAndPersistDocument(document, new RouteDocumentEvent(document));
193 prepareWorkflowDocument(savedDocument);
194 getWorkflowDocumentService()
195 .route(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
196 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
197 savedDocument.getDocumentHeader().getWorkflowDocument());
198 removeAdHocPersonsAndWorkgroups(savedDocument);
199 return savedDocument;
200 }
201
202
203
204
205
206
207 @Override
208 public Document approveDocument(Document document, String annotation,
209 List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
210 checkForNulls(document);
211
212
213
214 document.prepareForSave();
215 Document savedDocument = validateAndPersistDocument(document, new ApproveDocumentEvent(document));
216 prepareWorkflowDocument(savedDocument);
217 getWorkflowDocumentService()
218 .approve(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
219 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
220 savedDocument.getDocumentHeader().getWorkflowDocument());
221 removeAdHocPersonsAndWorkgroups(savedDocument);
222 return savedDocument;
223 }
224
225
226
227
228
229 @Override
230 public Document superUserApproveDocument(Document document, String annotation) throws WorkflowException {
231 getDocumentDao().save(document);
232 prepareWorkflowDocument(document);
233 getWorkflowDocumentService().superUserApprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
234 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
235 document.getDocumentHeader().getWorkflowDocument());
236 removeAdHocPersonsAndWorkgroups(document);
237 return document;
238 }
239
240
241
242
243
244 @Override
245 public Document superUserCancelDocument(Document document, String annotation) throws WorkflowException {
246 getDocumentDao().save(document);
247 prepareWorkflowDocument(document);
248 getWorkflowDocumentService().superUserCancel(document.getDocumentHeader().getWorkflowDocument(), annotation);
249 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
250 document.getDocumentHeader().getWorkflowDocument());
251 removeAdHocPersonsAndWorkgroups(document);
252 return document;
253 }
254
255
256
257
258
259 @Override
260 public Document superUserDisapproveDocument(Document document, String annotation) throws WorkflowException {
261 getDocumentDao().save(document);
262 return superUserDisapproveDocumentWithoutSaving(document, annotation);
263 }
264
265
266
267
268
269 @Override
270 public Document superUserDisapproveDocumentWithoutSaving(Document document, String annotation) throws WorkflowException {
271 prepareWorkflowDocument(document);
272 getWorkflowDocumentService()
273 .superUserDisapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
274 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
275 document.getDocumentHeader().getWorkflowDocument());
276 removeAdHocPersonsAndWorkgroups(document);
277 return document;
278 }
279
280
281
282
283
284
285 @Override
286 public Document disapproveDocument(Document document, String annotation) throws Exception {
287 checkForNulls(document);
288
289 Note note = createNoteFromDocument(document, annotation);
290
291 if (document.getNoteType().equals(NoteType.BUSINESS_OBJECT)) {
292 note.setNoteTypeCode(NoteType.DOCUMENT_HEADER.getCode());
293 note.setRemoteObjectIdentifier(document.getDocumentHeader().getObjectId());
294 }
295 document.addNote(note);
296
297
298
299
300 getNoteService().save(note);
301
302 prepareWorkflowDocument(document);
303 getWorkflowDocumentService().disapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
304 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
305 document.getDocumentHeader().getWorkflowDocument());
306 removeAdHocPersonsAndWorkgroups(document);
307 return document;
308 }
309
310
311
312
313
314 @Override
315 public Document cancelDocument(Document document, String annotation) throws WorkflowException {
316 checkForNulls(document);
317
318
319
320 if (document instanceof MaintenanceDocument) {
321 MaintenanceDocument maintDoc = ((MaintenanceDocument) document);
322 if (maintDoc.getOldMaintainableObject() != null &&
323 (maintDoc.getOldMaintainableObject().getDataObject() instanceof BusinessObject)) {
324 ((BusinessObject) maintDoc.getOldMaintainableObject().getDataObject()).refresh();
325 }
326
327 if (maintDoc.getNewMaintainableObject().getDataObject() instanceof BusinessObject) {
328 ((BusinessObject) maintDoc.getNewMaintainableObject().getDataObject()).refresh();
329 }
330 }
331 prepareWorkflowDocument(document);
332 getWorkflowDocumentService().cancel(document.getDocumentHeader().getWorkflowDocument(), annotation);
333 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
334 document.getDocumentHeader().getWorkflowDocument());
335
336
337 removeAdHocPersonsAndWorkgroups(document);
338 return document;
339 }
340
341 @Override
342 public Document recallDocument(Document document, String annotation, boolean cancel) throws WorkflowException {
343 checkForNulls(document);
344
345 Note note = createNoteFromDocument(document, annotation);
346 document.addNote(note);
347 getNoteService().save(note);
348
349 prepareWorkflowDocument(document);
350 getWorkflowDocumentService().recall(document.getDocumentHeader().getWorkflowDocument(), annotation, cancel);
351 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
352 document.getDocumentHeader().getWorkflowDocument());
353 removeAdHocPersonsAndWorkgroups(document);
354 return document;
355 }
356
357
358
359
360
361
362 @Override
363 public Document acknowledgeDocument(Document document, String annotation,
364 List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException {
365 checkForNulls(document);
366
367
368
369 prepareWorkflowDocument(document);
370 getWorkflowDocumentService()
371 .acknowledge(document.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
372 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
373 document.getDocumentHeader().getWorkflowDocument());
374 removeAdHocPersonsAndWorkgroups(document);
375 return document;
376 }
377
378
379
380
381
382
383 @Override
384 public Document blanketApproveDocument(Document document, String annotation,
385 List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
386 checkForNulls(document);
387
388
389
390 document.prepareForSave();
391 Document savedDocument = validateAndPersistDocument(document, new BlanketApproveDocumentEvent(document));
392 prepareWorkflowDocument(savedDocument);
393 getWorkflowDocumentService()
394 .blanketApprove(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
395 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
396 savedDocument.getDocumentHeader().getWorkflowDocument());
397 removeAdHocPersonsAndWorkgroups(savedDocument);
398 return savedDocument;
399 }
400
401
402
403
404
405 @Override
406 public Document clearDocumentFyi(Document document,
407 List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException {
408 checkForNulls(document);
409
410 document.populateDocumentForRouting();
411 getWorkflowDocumentService().clearFyi(document.getDocumentHeader().getWorkflowDocument(), adHocRecipients);
412 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
413 document.getDocumentHeader().getWorkflowDocument());
414 removeAdHocPersonsAndWorkgroups(document);
415 return document;
416 }
417
418
419
420
421
422
423 @Override
424 public Document completeDocument(Document document, String annotation,
425 List adHocRecipients) throws WorkflowException {
426 checkForNulls(document);
427
428 document.prepareForSave();
429 validateAndPersistDocument(document, new CompleteDocumentEvent(document));
430
431 prepareWorkflowDocument(document);
432 getWorkflowDocumentService().complete(document.getDocumentHeader().getWorkflowDocument(), annotation,
433 adHocRecipients);
434
435 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
436 document.getDocumentHeader().getWorkflowDocument());
437
438 removeAdHocPersonsAndWorkgroups(document);
439
440 return document;
441 }
442
443 protected void checkForNulls(Document document) {
444 if (document == null) {
445 throw new IllegalArgumentException("invalid (null) document");
446 }
447 if (document.getDocumentNumber() == null) {
448 throw new IllegalStateException("invalid (null) documentHeaderId");
449 }
450 }
451
452 private Document validateAndPersistDocumentAndSaveAdHocRoutingRecipients(Document document,
453 KualiDocumentEvent event) {
454
455
456
457
458 List<AdHocRouteRecipient> adHocRoutingRecipients = new ArrayList<AdHocRouteRecipient>();
459 adHocRoutingRecipients.addAll(document.getAdHocRoutePersons());
460 adHocRoutingRecipients.addAll(document.getAdHocRouteWorkgroups());
461
462 for (AdHocRouteRecipient recipient : adHocRoutingRecipients) {
463 recipient.setdocumentNumber(document.getDocumentNumber());
464 }
465 Map<String, String> criteria = new HashMap<String, String>();
466 criteria.put("documentNumber", document.getDocumentNumber());
467 getBusinessObjectService().deleteMatching(AdHocRouteRecipient.class, criteria);
468
469 getBusinessObjectService().save(adHocRoutingRecipients);
470 return validateAndPersistDocument(document, event);
471 }
472
473
474
475
476 @Override
477 public boolean documentExists(String documentHeaderId) {
478
479 if (StringUtils.isBlank(documentHeaderId)) {
480 throw new IllegalArgumentException("invalid (blank) documentHeaderId");
481 }
482
483 boolean internalUserSession = false;
484 try {
485
486
487 if (GlobalVariables.getUserSession() == null) {
488 internalUserSession = true;
489 GlobalVariables.setUserSession(new UserSession(KRADConstants.SYSTEM_USER));
490 GlobalVariables.clear();
491 }
492
493
494 if (getWorkflowDocumentService().workflowDocumentExists(documentHeaderId)) {
495
496 return getDocumentHeaderService().getDocumentHeaderById(documentHeaderId) != null;
497 }
498
499 return false;
500 } finally {
501
502 if (internalUserSession) {
503 GlobalVariables.clear();
504 GlobalVariables.setUserSession(null);
505 }
506 }
507 }
508
509
510
511
512
513
514 @Override
515 public Document getNewDocument(Class<? extends Document> documentClass) throws WorkflowException {
516 if (documentClass == null) {
517 throw new IllegalArgumentException("invalid (null) documentClass");
518 }
519 if (!Document.class.isAssignableFrom(documentClass)) {
520 throw new IllegalArgumentException("invalid (non-Document) documentClass");
521 }
522
523 String documentTypeName = getDataDictionaryService().getDocumentTypeNameByClass(documentClass);
524 if (StringUtils.isBlank(documentTypeName)) {
525 throw new UnknownDocumentTypeException(
526 "unable to get documentTypeName for unknown documentClass '" + documentClass.getName() + "'");
527 }
528 return getNewDocument(documentTypeName);
529 }
530
531
532
533
534
535
536
537
538 @Override
539 public Document getNewDocument(String documentTypeName, String initiatorPrincipalNm) throws WorkflowException {
540
541
542 String watchName = "DocumentServiceImpl.getNewDocument";
543 StopWatch watch = new StopWatch();
544 watch.start();
545 if (LOG.isDebugEnabled()) {
546 LOG.debug(watchName + ": started");
547 }
548 if (StringUtils.isBlank(documentTypeName)) {
549 throw new IllegalArgumentException("invalid (blank) documentTypeName");
550 }
551 if (GlobalVariables.getUserSession() == null) {
552 throw new IllegalStateException(
553 "GlobalVariables must be populated with a valid UserSession before a new document can be created");
554 }
555
556
557 Class<? extends Document> documentClass = getDocumentClassByTypeName(documentTypeName);
558
559
560 Person initiator = null;
561 if (StringUtils.isBlank(initiatorPrincipalNm)) {
562 initiator = GlobalVariables.getUserSession().getPerson();
563 } else {
564 initiator = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorPrincipalNm);
565 if (ObjectUtils.isNull(initiator)) {
566 initiator = GlobalVariables.getUserSession().getPerson();
567 }
568 }
569
570
571 DocumentAuthorizer documentAuthorizer = getDocumentDictionaryService().getDocumentAuthorizer(documentTypeName);
572 DocumentPresentationController documentPresentationController =
573 getDocumentDictionaryService().getDocumentPresentationController(documentTypeName);
574
575 LOG.debug("calling canInitiate from getNewDocument()");
576 if (!documentPresentationController.canInitiate(documentTypeName) ||
577 !documentAuthorizer.canInitiate(documentTypeName, initiator)) {
578 throw new DocumentAuthorizationException(initiator.getPrincipalName(), "initiate", documentTypeName);
579 }
580
581
582 WorkflowDocument workflowDocument = getWorkflowDocumentService().createWorkflowDocument(documentTypeName, initiator);
583 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);
584
585
586 DocumentHeader documentHeader = null;
587 try {
588
589 Class<? extends DocumentHeader> documentHeaderClass =
590 getDocumentHeaderService().getDocumentHeaderBaseClass();
591 documentHeader = documentHeaderClass.newInstance();
592 documentHeader.setWorkflowDocument(workflowDocument);
593 documentHeader.setDocumentNumber(workflowDocument.getDocumentId());
594
595 } catch (IllegalAccessException e) {
596 throw new RuntimeException("Error instantiating DocumentHeader", e);
597 } catch (InstantiationException e) {
598 throw new RuntimeException("Error instantiating DocumentHeader", e);
599 }
600
601
602 Document document = null;
603 try {
604
605 if (MaintenanceDocumentBase.class.isAssignableFrom(documentClass)) {
606 Class<?>[] defaultConstructor = new Class[]{String.class};
607 Constructor<? extends Document> cons = documentClass.getConstructor(defaultConstructor);
608 if (ObjectUtils.isNull(cons)) {
609 throw new ConfigurationException(
610 "Could not find constructor with document type name parameter needed for Maintenance Document Base class");
611 }
612 document = cons.newInstance(documentTypeName);
613 } else {
614
615 document = documentClass.newInstance();
616 }
617 } catch (IllegalAccessException e) {
618 throw new RuntimeException("Error instantiating Document", e);
619 } catch (InstantiationException e) {
620 throw new RuntimeException("Error instantiating Document", e);
621 } catch (SecurityException e) {
622 throw new RuntimeException("Error instantiating Maintenance Document", e);
623 } catch (NoSuchMethodException e) {
624 throw new RuntimeException(
625 "Error instantiating Maintenance Document: No constructor with String parameter found", e);
626 } catch (IllegalArgumentException e) {
627 throw new RuntimeException("Error instantiating Maintenance Document", e);
628 } catch (InvocationTargetException e) {
629 throw new RuntimeException("Error instantiating Maintenance Document", e);
630 }
631
632 document.setDocumentHeader(documentHeader);
633 document.setDocumentNumber(documentHeader.getDocumentNumber());
634
635 watch.stop();
636 if (LOG.isDebugEnabled()) {
637 LOG.debug(watchName + ": " + watch.toString());
638 }
639
640 return document;
641 }
642
643
644
645
646
647
648 @Override
649 public Document getNewDocument(String documentTypeName) throws WorkflowException {
650 return getNewDocument(documentTypeName, null);
651 }
652
653
654
655
656
657
658
659
660
661
662
663 @Override
664 public Document getByDocumentHeaderId(String documentHeaderId) throws WorkflowException {
665 if (documentHeaderId == null) {
666 throw new IllegalArgumentException("invalid (null) documentHeaderId");
667 }
668 boolean internalUserSession = false;
669 try {
670
671
672 if (GlobalVariables.getUserSession() == null) {
673 internalUserSession = true;
674 GlobalVariables.setUserSession(new UserSession(KRADConstants.SYSTEM_USER));
675 GlobalVariables.clear();
676 }
677
678 WorkflowDocument workflowDocument = null;
679
680 if (LOG.isDebugEnabled()) {
681 LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
682 }
683 workflowDocument = getWorkflowDocumentService()
684 .loadWorkflowDocument(documentHeaderId, GlobalVariables.getUserSession().getPerson());
685 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);
686
687 Class<? extends Document> documentClass = getDocumentClassByTypeName(workflowDocument.getDocumentTypeName());
688
689
690 Document document = getDocumentDao().findByDocumentHeaderId(documentClass, documentHeaderId);
691
692 return postProcessDocument(documentHeaderId, workflowDocument, document);
693 } finally {
694
695 if (internalUserSession) {
696 GlobalVariables.clear();
697 GlobalVariables.setUserSession(null);
698 }
699 }
700 }
701
702
703
704
705 @Override
706 public Document getByDocumentHeaderIdSessionless(String documentHeaderId) throws WorkflowException {
707 if (documentHeaderId == null) {
708 throw new IllegalArgumentException("invalid (null) documentHeaderId");
709 }
710
711 WorkflowDocument workflowDocument = null;
712
713 if (LOG.isDebugEnabled()) {
714 LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
715 }
716
717 Person person = getPersonService().getPersonByPrincipalName(KRADConstants.SYSTEM_USER);
718 workflowDocument = workflowDocumentService.loadWorkflowDocument(documentHeaderId, person);
719
720 Class<? extends Document> documentClass = getDocumentClassByTypeName(workflowDocument.getDocumentTypeName());
721
722
723 Document document = getDocumentDao().findByDocumentHeaderId(documentClass, documentHeaderId);
724
725 return postProcessDocument(documentHeaderId, workflowDocument, document);
726 }
727
728 private Class<? extends Document> getDocumentClassByTypeName(String documentTypeName) {
729 if (StringUtils.isBlank(documentTypeName)) {
730 throw new IllegalArgumentException("invalid (blank) documentTypeName");
731 }
732
733 Class<? extends Document> clazz = getDataDictionaryService().getDocumentClassByTypeName(documentTypeName);
734 if (clazz == null) {
735 throw new UnknownDocumentTypeException(
736 "unable to get class for unknown documentTypeName '" + documentTypeName + "'");
737 }
738 return clazz;
739 }
740
741
742
743
744
745
746 protected void loadNotes(Document document) {
747 if (isNoteTargetReady(document)) {
748 List<Note> notes = new ArrayList<Note>();
749 if (StringUtils.isNotBlank(document.getNoteTarget().getObjectId())) {
750 notes.addAll(getNoteService().getByRemoteObjectId(document.getNoteTarget().getObjectId()));
751 }
752
753 if (document.getNoteType().equals(NoteType.BUSINESS_OBJECT)
754 && document.getDocumentHeader().getWorkflowDocument().isDisapproved()) {
755 notes.addAll(getNoteService().getByRemoteObjectId(document.getDocumentHeader().getObjectId()));
756 }
757
758
759
760 for (Note note : notes) {
761 note.refreshReferenceObject("attachment");
762 }
763 document.setNotes(notes);
764 }
765 }
766
767
768
769
770
771
772
773
774 private Document postProcessDocument(String documentHeaderId, WorkflowDocument workflowDocument, Document document) {
775 if (document != null) {
776 document.getDocumentHeader().setWorkflowDocument(workflowDocument);
777 document.processAfterRetrieve();
778 loadNotes(document);
779 }
780 return document;
781 }
782
783
784
785
786
787
788
789 @Override
790 public List<Document> getDocumentsByListOfDocumentHeaderIds(Class<? extends Document> documentClass,
791 List<String> documentHeaderIds) throws WorkflowException {
792
793 if (documentHeaderIds == null) {
794 throw new IllegalArgumentException("invalid (null) documentHeaderId list");
795 }
796 int index = 0;
797 for (String documentHeaderId : documentHeaderIds) {
798 if (StringUtils.isBlank(documentHeaderId)) {
799 throw new IllegalArgumentException("invalid (blank) documentHeaderId at list index " + index);
800 }
801 index++;
802 }
803
804 boolean internalUserSession = false;
805 try {
806
807
808 if (GlobalVariables.getUserSession() == null) {
809 internalUserSession = true;
810 GlobalVariables.setUserSession(new UserSession(KRADConstants.SYSTEM_USER));
811 GlobalVariables.clear();
812 }
813
814
815 List<? extends Document> rawDocuments =
816 getDocumentDao().findByDocumentHeaderIds(documentClass, documentHeaderIds);
817
818
819 List<Document> documents = new ArrayList<Document>();
820 for (Document document : rawDocuments) {
821 WorkflowDocument workflowDocument = getWorkflowDocumentService().loadWorkflowDocument(document.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
822
823 document = postProcessDocument(document.getDocumentNumber(), workflowDocument, document);
824 documents.add(document);
825 }
826 return documents;
827 } finally {
828
829 if (internalUserSession) {
830 GlobalVariables.clear();
831 GlobalVariables.setUserSession(null);
832 }
833 }
834 }
835
836
837
838
839
840
841 @Override
842 public Document validateAndPersistDocument(Document document, KualiDocumentEvent event) throws ValidationException {
843 if (document == null) {
844 LOG.error("document passed to validateAndPersist was null");
845 throw new IllegalArgumentException("invalid (null) document");
846 }
847 if (LOG.isDebugEnabled()) {
848 LOG.debug("validating and preparing to persist document " + document.getDocumentNumber());
849 }
850
851 document.validateBusinessRules(event);
852 document.prepareForSave(event);
853
854
855 Document savedDocument = null;
856 try {
857 if (LOG.isInfoEnabled()) {
858 LOG.info("storing document " + document.getDocumentNumber());
859 }
860 savedDocument = getDocumentDao().save(document);
861 } catch (OptimisticLockingFailureException e) {
862 LOG.error("exception encountered on store of document " + e.getMessage());
863 throw e;
864 }
865
866 boolean notesSaved = saveDocumentNotes(document);
867 if (!notesSaved) {
868 if (LOG.isInfoEnabled()) {
869 LOG.info(
870 "Notes not saved during validateAndPersistDocument, likely means that note save needs to be deferred because note target is not ready.");
871 }
872 }
873
874 savedDocument.postProcessSave(event);
875
876 return savedDocument;
877 }
878
879
880
881
882
883
884
885 @Override
886 public void prepareWorkflowDocument(Document document) throws WorkflowException {
887
888 document.populateDocumentForRouting();
889
890
891 populateDocumentTitle(document);
892
893
894 populateApplicationDocumentId(document);
895 }
896
897
898
899
900
901
902
903
904
905 private void populateDocumentTitle(Document document) throws WorkflowException {
906 String documentTitle = document.getDocumentTitle();
907 if (StringUtils.isNotBlank(documentTitle)) {
908 document.getDocumentHeader().getWorkflowDocument().setTitle(documentTitle);
909 }
910 }
911
912
913
914
915
916
917
918
919 private void populateApplicationDocumentId(Document document) {
920 String organizationDocumentNumber = document.getDocumentHeader().getOrganizationDocumentNumber();
921 if (StringUtils.isNotBlank(organizationDocumentNumber)) {
922 document.getDocumentHeader().getWorkflowDocument().setApplicationDocumentId(organizationDocumentNumber);
923 }
924 }
925
926
927
928
929
930
931 @Override
932 public Document updateDocument(Document document) {
933 checkForNulls(document);
934 return getDocumentDao().save(document);
935 }
936
937
938
939
940
941 @Override
942 public Note createNoteFromDocument(Document document, String text) {
943 Note note = new Note();
944
945 note.setNotePostedTimestamp(getDateTimeService().getCurrentTimestamp());
946 note.setVersionNumber(Long.valueOf(1));
947 note.setNoteText(text);
948 note.setNoteTypeCode(document.getNoteType().getCode());
949
950 PersistableBusinessObject bo = document.getNoteTarget();
951
952 Person kualiUser = GlobalVariables.getUserSession().getPerson();
953 if (kualiUser == null) {
954 throw new IllegalStateException("Current UserSession has a null Person.");
955 }
956 return bo == null ? null : getNoteService().createNote(note, bo, kualiUser.getPrincipalId());
957 }
958
959
960
961
962 @Override
963 public boolean saveDocumentNotes(Document document) {
964 if (isNoteTargetReady(document)) {
965 List<Note> notes = document.getNotes();
966 for (Note note : document.getNotes()) {
967 linkNoteRemoteObjectId(note, document.getNoteTarget());
968 }
969 getNoteService().saveNoteList(notes);
970 return true;
971 }
972 return false;
973 }
974
975
976
977
978 @Override
979 public void sendNoteRouteNotification(Document document, Note note, Person sender) throws WorkflowException {
980 AdHocRouteRecipient routeRecipient = note.getAdHocRouteRecipient();
981
982
983 Person requestedUser = this.getPersonService().getPersonByPrincipalName(routeRecipient.getId());
984 String senderName = sender.getFirstName() + " " + sender.getLastName();
985 String requestedName = requestedUser.getFirstName() + " " + requestedUser.getLastName();
986
987 String notificationText =
988 kualiConfigurationService.getPropertyValueAsString(
989 RiceKeyConstants.MESSAGE_NOTE_NOTIFICATION_ANNOTATION);
990 if (StringUtils.isBlank(notificationText)) {
991 throw new RuntimeException(
992 "No annotation message found for note notification. Message needs added to application resources with key:" +
993 RiceKeyConstants.MESSAGE_NOTE_NOTIFICATION_ANNOTATION);
994 }
995 notificationText =
996 MessageFormat.format(notificationText, new Object[]{senderName, requestedName, note.getNoteText()});
997
998 List<AdHocRouteRecipient> routeRecipients = new ArrayList<AdHocRouteRecipient>();
999 routeRecipients.add(routeRecipient);
1000
1001 workflowDocumentService
1002 .sendWorkflowNotification(document.getDocumentHeader().getWorkflowDocument(), notificationText,
1003 routeRecipients, KRADConstants.NOTE_WORKFLOW_NOTIFICATION_REQUEST_LABEL);
1004
1005
1006 note.setAdHocRouteRecipient(new AdHocRoutePerson());
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 protected boolean isNoteTargetReady(Document document) {
1018
1019
1020 if (document.getDocumentHeader().getWorkflowDocument().isDisapproved()) {
1021 return true;
1022 }
1023 PersistableBusinessObject noteTarget = document.getNoteTarget();
1024 if (noteTarget == null || StringUtils.isBlank(noteTarget.getObjectId())) {
1025 return false;
1026 }
1027 return true;
1028 }
1029
1030 private void linkNoteRemoteObjectId(Note note, PersistableBusinessObject noteTarget) {
1031 String objectId = noteTarget.getObjectId();
1032 if (StringUtils.isBlank(objectId)) {
1033 throw new IllegalStateException(
1034 "Attempted to link a Note with a PersistableBusinessObject with no object id");
1035 }
1036 note.setRemoteObjectIdentifier(noteTarget.getObjectId());
1037 }
1038
1039
1040
1041
1042 @Override
1043 public void sendAdHocRequests(Document document, String annotation,
1044 List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException {
1045 prepareWorkflowDocument(document);
1046 getWorkflowDocumentService()
1047 .sendWorkflowNotification(document.getDocumentHeader().getWorkflowDocument(), annotation,
1048 adHocRecipients);
1049 UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(),
1050 document.getDocumentHeader().getWorkflowDocument());
1051
1052
1053 removeAdHocPersonsAndWorkgroups(document);
1054 }
1055
1056 private void removeAdHocPersonsAndWorkgroups(Document document) {
1057 List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
1058 List<AdHocRouteWorkgroup> adHocRouteWorkgroups = new ArrayList<AdHocRouteWorkgroup>();
1059 getBusinessObjectService().delete(document.getAdHocRoutePersons());
1060 getBusinessObjectService().delete(document.getAdHocRouteWorkgroups());
1061 document.setAdHocRoutePersons(adHocRoutePersons);
1062 document.setAdHocRouteWorkgroups(adHocRouteWorkgroups);
1063 }
1064
1065 public void setDateTimeService(DateTimeService dateTimeService) {
1066 this.dateTimeService = dateTimeService;
1067 }
1068
1069 protected DateTimeService getDateTimeService() {
1070 if (this.dateTimeService == null) {
1071 this.dateTimeService = CoreApiServiceLocator.getDateTimeService();
1072 }
1073 return this.dateTimeService;
1074 }
1075
1076 public void setNoteService(NoteService noteService) {
1077 this.noteService = noteService;
1078 }
1079
1080 protected NoteService getNoteService() {
1081 if (this.noteService == null) {
1082 this.noteService = KRADServiceLocator.getNoteService();
1083 }
1084 return this.noteService;
1085 }
1086
1087 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
1088 this.businessObjectService = businessObjectService;
1089 }
1090
1091 protected BusinessObjectService getBusinessObjectService() {
1092 if (this.businessObjectService == null) {
1093 this.businessObjectService = KRADServiceLocator.getBusinessObjectService();
1094 }
1095 return this.businessObjectService;
1096 }
1097
1098 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
1099 this.workflowDocumentService = workflowDocumentService;
1100 }
1101
1102 protected WorkflowDocumentService getWorkflowDocumentService() {
1103 if (this.workflowDocumentService == null) {
1104 this.workflowDocumentService = KRADServiceLocatorWeb.getWorkflowDocumentService();
1105 }
1106 return this.workflowDocumentService;
1107 }
1108
1109 public void setDocumentDao(DocumentDao documentDao) {
1110 this.documentDao = documentDao;
1111 }
1112
1113 protected DocumentDao getDocumentDao() {
1114 if (this.documentDao == null) {
1115 this.documentDao = KRADServiceLocatorInternal.getDocumentDao();
1116 }
1117 return documentDao;
1118 }
1119
1120 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1121 this.dataDictionaryService = dataDictionaryService;
1122 }
1123
1124 protected DataDictionaryService getDataDictionaryService() {
1125 if (this.dataDictionaryService == null) {
1126 this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
1127 }
1128 return this.dataDictionaryService;
1129 }
1130
1131 public void setDocumentHeaderService(DocumentHeaderService documentHeaderService) {
1132 this.documentHeaderService = documentHeaderService;
1133 }
1134
1135 protected DocumentHeaderService getDocumentHeaderService() {
1136 if (this.documentHeaderService == null) {
1137 this.documentHeaderService = KRADServiceLocatorWeb.getDocumentHeaderService();
1138 }
1139 return this.documentHeaderService;
1140 }
1141
1142 protected DocumentDictionaryService getDocumentDictionaryService() {
1143 if (documentDictionaryService == null) {
1144 documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
1145 }
1146 return documentDictionaryService;
1147 }
1148
1149 public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
1150 this.documentDictionaryService = documentDictionaryService;
1151 }
1152
1153 public PersonService getPersonService() {
1154 if (personService == null) {
1155 personService = KimApiServiceLocator.getPersonService();
1156 }
1157 return personService;
1158 }
1159
1160 public void setKualiConfigurationService(ConfigurationService kualiConfigurationService) {
1161 this.kualiConfigurationService = kualiConfigurationService;
1162 }
1163
1164 }