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