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 }