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