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