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