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