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