Coverage Report - org.kuali.rice.kns.service.impl.DocumentServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentServiceImpl
0%
0/403
0%
0/138
3.333
 
 1  
 /*
 2  
  * Copyright 2006-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.kuali.rice.kns.service.impl;
 18  
 
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.commons.lang.time.StopWatch;
 21  
 import org.kuali.rice.core.api.datetime.DateTimeService;
 22  
 import org.kuali.rice.core.api.services.CoreApiServiceLocator;
 23  
 import org.kuali.rice.core.api.config.ConfigurationException;
 24  
 import org.kuali.rice.core.api.config.property.ConfigurationService;
 25  
 import org.kuali.rice.core.framework.persistence.jta.TransactionalNoValidationExceptionRollback;
 26  
 import org.kuali.rice.core.util.RiceKeyConstants;
 27  
 import org.kuali.rice.kew.exception.WorkflowException;
 28  
 import org.kuali.rice.kim.bo.Person;
 29  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 30  
 import org.kuali.rice.kim.service.PersonService;
 31  
 import org.kuali.rice.kns.UserSession;
 32  
 import org.kuali.rice.kns.bo.AdHocRoutePerson;
 33  
 import org.kuali.rice.kns.bo.AdHocRouteRecipient;
 34  
 import org.kuali.rice.kns.bo.AdHocRouteWorkgroup;
 35  
 import org.kuali.rice.kns.bo.DocumentHeader;
 36  
 import org.kuali.rice.kns.bo.Note;
 37  
 import org.kuali.rice.kns.bo.PersistableBusinessObject;
 38  
 import org.kuali.rice.kns.dao.DocumentDao;
 39  
 import org.kuali.rice.kns.datadictionary.exception.UnknownDocumentTypeException;
 40  
 import org.kuali.rice.kns.document.Document;
 41  
 import org.kuali.rice.kns.document.MaintenanceDocument;
 42  
 import org.kuali.rice.kns.document.MaintenanceDocumentBase;
 43  
 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
 44  
 import org.kuali.rice.kns.document.authorization.DocumentPresentationController;
 45  
 import org.kuali.rice.kns.exception.DocumentAuthorizationException;
 46  
 import org.kuali.rice.kns.exception.ValidationException;
 47  
 import org.kuali.rice.kns.rule.event.ApproveDocumentEvent;
 48  
 import org.kuali.rice.kns.rule.event.BlanketApproveDocumentEvent;
 49  
 import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
 50  
 import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
 51  
 import org.kuali.rice.kns.rule.event.SaveDocumentEvent;
 52  
 import org.kuali.rice.kns.rule.event.SaveEvent;
 53  
 import org.kuali.rice.kns.service.BusinessObjectService;
 54  
 import org.kuali.rice.kns.service.DataDictionaryService;
 55  
 import org.kuali.rice.kns.service.DocumentHeaderService;
 56  
 import org.kuali.rice.kns.service.DocumentHelperService;
 57  
 import org.kuali.rice.kns.service.DocumentService;
 58  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 59  
 import org.kuali.rice.kns.service.KNSServiceLocatorInternal;
 60  
 import org.kuali.rice.kns.service.KNSServiceLocatorWeb;
 61  
 import org.kuali.rice.kns.service.NoteService;
 62  
 import org.kuali.rice.kns.util.GlobalVariables;
 63  
 import org.kuali.rice.kns.util.KNSConstants;
 64  
 import org.kuali.rice.kns.util.ObjectUtils;
 65  
 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
 66  
 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
 67  
 import org.springframework.dao.OptimisticLockingFailureException;
 68  
 
 69  
 import java.lang.reflect.Constructor;
 70  
 import java.lang.reflect.InvocationTargetException;
 71  
 import java.text.MessageFormat;
 72  
 import java.util.ArrayList;
 73  
 import java.util.HashMap;
 74  
 import java.util.List;
 75  
 import java.util.Map;
 76  
 
 77  
 
 78  
 
 79  
 /**
 80  
  * This class is the service implementation for the Document structure. It contains all of the document level type of processing and
 81  
  * calling back into documents for various centralization of functionality. This is the default, Kuali delivered implementation
 82  
  * which utilizes Workflow.
 83  
  */
 84  
 @TransactionalNoValidationExceptionRollback
 85  0
 public class DocumentServiceImpl implements DocumentService {
 86  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentServiceImpl.class);
 87  
 
 88  
     private DateTimeService dateTimeService;
 89  
 
 90  
     private NoteService noteService;
 91  
 
 92  
     protected WorkflowDocumentService workflowDocumentService;
 93  
 
 94  
     protected BusinessObjectService businessObjectService;
 95  
 
 96  
     /**
 97  
      * Don't access directly, use synchronized getter and setter to access
 98  
      */
 99  
     private DocumentDao documentDao;
 100  
 
 101  
     private DataDictionaryService dataDictionaryService;
 102  
 
 103  
     private DocumentHeaderService documentHeaderService;
 104  
 
 105  
     private PersonService personService;
 106  
 
 107  
     private DocumentHelperService documentHelperService;
 108  
 
 109  
     private ConfigurationService kualiConfigurationService;
 110  
 
 111  
     /**
 112  
      * @see org.kuali.rice.kns.service.DocumentService#saveDocument(org.kuali.rice.kns.document.Document)
 113  
      */
 114  
     @Override
 115  
         public Document saveDocument(Document document) throws WorkflowException, ValidationException {
 116  0
         return saveDocument(document, SaveDocumentEvent.class);
 117  
     }
 118  
 
 119  
     @Override
 120  
         public Document saveDocument(Document document, Class<? extends KualiDocumentEvent> kualiDocumentEventClass) throws WorkflowException, ValidationException {
 121  0
         checkForNulls(document);
 122  0
         if (kualiDocumentEventClass == null) {
 123  0
             throw new IllegalArgumentException("invalid (null) kualiDocumentEventClass");
 124  
         }
 125  
         // if event is not an instance of a SaveDocumentEvent or a SaveOnlyDocumentEvent
 126  0
         if (!SaveEvent.class.isAssignableFrom(kualiDocumentEventClass)) {
 127  0
             throw new ConfigurationException("The KualiDocumentEvent class '" + kualiDocumentEventClass.getName() + "' does not implement the class '" + SaveEvent.class.getName() + "'");
 128  
         }
 129  
 //        if (!getDocumentActionFlags(document).getCanSave()) {
 130  
 //            throw buildAuthorizationException("save", document);
 131  
 //        }
 132  0
         document.prepareForSave();
 133  0
         Document savedDocument = validateAndPersistDocumentAndSaveAdHocRoutingRecipients(document, generateKualiDocumentEvent(document, kualiDocumentEventClass));
 134  0
         prepareWorkflowDocument(savedDocument);
 135  0
         getWorkflowDocumentService().save(savedDocument.getDocumentHeader().getWorkflowDocument(), null);
 136  
         
 137  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),savedDocument.getDocumentHeader().getWorkflowDocument());
 138  
 
 139  0
         return savedDocument;
 140  
     }
 141  
 
 142  
     private KualiDocumentEvent generateKualiDocumentEvent(Document document, Class<? extends KualiDocumentEvent> eventClass) throws ConfigurationException {
 143  0
             String potentialErrorMessage = "Found error trying to generate Kuali Document Event using event class '" + 
 144  
             eventClass.getName() + "' for document " + document.getDocumentNumber();
 145  
             
 146  
             try {
 147  0
                     Constructor<?> usableConstructor = null;
 148  0
                     List<Object> paramList = new ArrayList<Object>();
 149  0
                     for (Constructor<?> currentConstructor : eventClass.getConstructors()) {
 150  0
                             for (Class<?> parameterClass : currentConstructor.getParameterTypes()) {
 151  0
                                     if (Document.class.isAssignableFrom(parameterClass)) {
 152  0
                                             usableConstructor = currentConstructor;
 153  0
                                             paramList.add(document);
 154  
                                     } else {
 155  0
                                             paramList.add(null);
 156  
                                     }
 157  
                             }
 158  0
                             if (ObjectUtils.isNotNull(usableConstructor)) {
 159  0
                                     break;
 160  
                             }
 161  
                     }
 162  0
                     if (usableConstructor == null) {
 163  0
                             throw new RuntimeException("Cannot find a constructor for class '" + eventClass.getName() + "' that takes in a document parameter");
 164  
                     }
 165  0
                     return (KualiDocumentEvent) usableConstructor.newInstance(paramList.toArray());
 166  0
             } catch (SecurityException e) {
 167  0
                     throw new ConfigurationException(potentialErrorMessage, e);
 168  0
             } catch (IllegalArgumentException e) {
 169  0
                     throw new ConfigurationException(potentialErrorMessage, e);
 170  0
             } catch (InstantiationException e) {
 171  0
                     throw new ConfigurationException(potentialErrorMessage, e);
 172  0
             } catch (IllegalAccessException e) {
 173  0
                     throw new ConfigurationException(potentialErrorMessage, e);
 174  0
             } catch (InvocationTargetException e) {
 175  0
                     throw new ConfigurationException(potentialErrorMessage, e);
 176  
             }
 177  
     }
 178  
 
 179  
     /**
 180  
      * @see org.kuali.rice.kns.service.DocumentService#routeDocument(org.kuali.rice.kns.document.Document, java.lang.String, java.util.List)
 181  
      */
 182  
     @Override
 183  
         public Document routeDocument(Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
 184  0
         checkForNulls(document);
 185  
         //if (!getDocumentActionFlags(document).getCanRoute()) {
 186  
         //    throw buildAuthorizationException("route", document);
 187  
         //}
 188  0
         document.prepareForSave();
 189  0
         Document savedDocument = validateAndPersistDocument(document, new RouteDocumentEvent(document));
 190  0
         prepareWorkflowDocument(savedDocument);
 191  0
         getWorkflowDocumentService().route(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
 192  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),savedDocument.getDocumentHeader().getWorkflowDocument());
 193  0
         removeAdHocPersonsAndWorkgroups(savedDocument);
 194  0
         return savedDocument;
 195  
     }
 196  
 
 197  
     /**
 198  
      * @see org.kuali.rice.kns.service.DocumentService#approveDocument(org.kuali.rice.kns.document.Document, java.lang.String,
 199  
      *      java.util.List)
 200  
      */
 201  
     @Override
 202  
         public Document approveDocument(Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
 203  0
         checkForNulls(document);
 204  
         //if (!getDocumentActionFlags(document).getCanApprove()) {
 205  
         //    throw buildAuthorizationException("approve", document);
 206  
         //}
 207  0
         document.prepareForSave();
 208  0
         Document savedDocument = validateAndPersistDocument(document, new ApproveDocumentEvent(document));
 209  0
         prepareWorkflowDocument(savedDocument);
 210  0
         getWorkflowDocumentService().approve(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
 211  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),savedDocument.getDocumentHeader().getWorkflowDocument());
 212  0
         removeAdHocPersonsAndWorkgroups(savedDocument);
 213  0
         return savedDocument;
 214  
     }
 215  
 
 216  
 
 217  
     /**
 218  
      * @see org.kuali.rice.kns.service.DocumentService#superUserApproveDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 219  
      */
 220  
     @Override
 221  
         public Document superUserApproveDocument(Document document, String annotation) throws WorkflowException {
 222  0
         getDocumentDao().save(document);
 223  0
         prepareWorkflowDocument(document);
 224  0
         getWorkflowDocumentService().superUserApprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
 225  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 226  0
         removeAdHocPersonsAndWorkgroups(document);
 227  0
         return document;
 228  
     }
 229  
 
 230  
     /**
 231  
      * @see org.kuali.rice.kns.service.DocumentService#superUserCancelDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 232  
      */
 233  
     @Override
 234  
         public Document superUserCancelDocument(Document document, String annotation) throws WorkflowException {
 235  0
         getDocumentDao().save(document);
 236  0
         prepareWorkflowDocument(document);
 237  0
         getWorkflowDocumentService().superUserCancel(document.getDocumentHeader().getWorkflowDocument(), annotation);
 238  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 239  0
         removeAdHocPersonsAndWorkgroups(document);
 240  0
         return document;
 241  
     }
 242  
 
 243  
     /**
 244  
      * @see org.kuali.rice.kns.service.DocumentService#superUserCancelDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 245  
      */
 246  
     @Override
 247  
         public Document superUserDisapproveDocument(Document document, String annotation) throws WorkflowException {
 248  0
         getDocumentDao().save(document);
 249  0
         prepareWorkflowDocument(document);
 250  0
         getWorkflowDocumentService().superUserDisapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
 251  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 252  0
         removeAdHocPersonsAndWorkgroups(document);
 253  0
         return document;
 254  
     }
 255  
 
 256  
     /**
 257  
      * @see org.kuali.rice.kns.service.DocumentService#disapproveDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 258  
      */
 259  
     @Override
 260  
         public Document disapproveDocument(Document document, String annotation) throws Exception {
 261  0
         checkForNulls(document);
 262  
 
 263  0
         Note note = createNoteFromDocument(document,annotation);
 264  0
         document.addNote(note);
 265  
 
 266  
         //SAVE THE NOTE
 267  
         //Note: This save logic is replicated here and in KualiDocumentAction, when to save (based on doc state) should be moved
 268  
         //      into a doc service method
 269  0
         getNoteService().save(note);
 270  
 
 271  0
         prepareWorkflowDocument(document);
 272  0
         getWorkflowDocumentService().disapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
 273  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 274  0
         removeAdHocPersonsAndWorkgroups(document);
 275  0
         return document;
 276  
     }
 277  
 
 278  
     /**
 279  
      * @see org.kuali.rice.kns.service.DocumentService#cancelDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 280  
      */
 281  
     @Override
 282  
         public Document cancelDocument(Document document, String annotation) throws WorkflowException {
 283  0
         checkForNulls(document);
 284  
         //if (!getDocumentActionFlags(document).getCanCancel()) {
 285  
         //    throw buildAuthorizationException("cancel", document);
 286  
         //}
 287  0
         if (document instanceof MaintenanceDocument) {
 288  0
                 MaintenanceDocument maintDoc = ((MaintenanceDocument) document);
 289  0
                 if (maintDoc.getOldMaintainableObject() != null) {
 290  0
                         maintDoc.getOldMaintainableObject().getBusinessObject().refresh();
 291  
                 }
 292  0
                        maintDoc.getNewMaintainableObject().getBusinessObject().refresh();
 293  
         }
 294  0
         prepareWorkflowDocument(document);
 295  0
         getWorkflowDocumentService().cancel(document.getDocumentHeader().getWorkflowDocument(), annotation);
 296  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 297  
         //getBusinessObjectService().delete(document.getAdHocRoutePersons());
 298  
         //getBusinessObjectService().delete(document.getAdHocRouteWorkgroups());
 299  0
         removeAdHocPersonsAndWorkgroups(document);
 300  0
         return document;
 301  
     }
 302  
 
 303  
     /**
 304  
      * @see org.kuali.rice.kns.service.DocumentService#acknowledgeDocument(org.kuali.rice.kns.document.Document, java.lang.String,
 305  
      *      java.util.List)
 306  
      */
 307  
     @Override
 308  
         public Document acknowledgeDocument(Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException {
 309  0
         checkForNulls(document);
 310  
         //if (!getDocumentActionFlags(document).getCanAcknowledge()) {
 311  
         //    throw buildAuthorizationException("acknowledge", document);
 312  
         //}
 313  0
         prepareWorkflowDocument(document);
 314  0
         getWorkflowDocumentService().acknowledge(document.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
 315  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 316  0
         removeAdHocPersonsAndWorkgroups(document);
 317  0
         return document;
 318  
     }
 319  
 
 320  
     /**
 321  
      * @see org.kuali.rice.kns.service.DocumentService#blanketApproveDocument(org.kuali.rice.kns.document.Document, java.lang.String,
 322  
      *      java.util.List)
 323  
      */
 324  
     @Override
 325  
         public Document blanketApproveDocument(Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients) throws ValidationException, WorkflowException {
 326  0
         checkForNulls(document);
 327  
         //if (!getDocumentActionFlags(document).getCanBlanketApprove()) {
 328  
         //    throw buildAuthorizationException("blanket approve", document);
 329  
         //}
 330  0
         document.prepareForSave();
 331  0
         Document savedDocument = validateAndPersistDocument(document, new BlanketApproveDocumentEvent(document));
 332  0
         prepareWorkflowDocument(savedDocument);
 333  0
         getWorkflowDocumentService().blanketApprove(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
 334  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),savedDocument.getDocumentHeader().getWorkflowDocument());
 335  0
         removeAdHocPersonsAndWorkgroups(savedDocument);
 336  0
         return savedDocument;
 337  
     }
 338  
 
 339  
     /**
 340  
      * @see org.kuali.rice.kns.service.DocumentService#clearDocumentFyi(org.kuali.rice.kns.document.Document, java.util.List)
 341  
      */
 342  
     @Override
 343  
         public Document clearDocumentFyi(Document document, List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException {
 344  0
         checkForNulls(document);
 345  
         // populate document content so searchable attributes will be indexed properly
 346  0
         document.populateDocumentForRouting();
 347  0
         getWorkflowDocumentService().clearFyi(document.getDocumentHeader().getWorkflowDocument(), adHocRecipients);
 348  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 349  0
         removeAdHocPersonsAndWorkgroups(document);
 350  0
         return document;
 351  
     }
 352  
 
 353  
     protected void checkForNulls(Document document) {
 354  0
         if (document == null) {
 355  0
             throw new IllegalArgumentException("invalid (null) document");
 356  
         }
 357  0
         if (document.getDocumentNumber() == null) {
 358  0
             throw new IllegalStateException("invalid (null) documentHeaderId");
 359  
         }
 360  0
     }
 361  
 
 362  
     private Document validateAndPersistDocumentAndSaveAdHocRoutingRecipients(Document document, KualiDocumentEvent event) {
 363  
         /*
 364  
          * Using this method to wrap validateAndPersistDocument to keep everything in one transaction. This avoids modifying the
 365  
          * signature on validateAndPersistDocument method
 366  
          */
 367  0
         List<AdHocRouteRecipient> adHocRoutingRecipients = new ArrayList<AdHocRouteRecipient>();
 368  0
         adHocRoutingRecipients.addAll(document.getAdHocRoutePersons());
 369  0
         adHocRoutingRecipients.addAll(document.getAdHocRouteWorkgroups());
 370  
 
 371  0
         for (AdHocRouteRecipient recipient : adHocRoutingRecipients) {
 372  0
                         recipient.setdocumentNumber(document.getDocumentNumber());
 373  
                 }
 374  0
         Map<String, String> criteria = new HashMap<String, String>();
 375  0
         criteria.put("documentNumber", document.getDocumentNumber());
 376  0
         getBusinessObjectService().deleteMatching(AdHocRouteRecipient.class, criteria);
 377  
 
 378  0
         getBusinessObjectService().save(adHocRoutingRecipients);
 379  0
         return validateAndPersistDocument(document, event);
 380  
     }
 381  
 
 382  
     /**
 383  
      * @see org.kuali.rice.kns.service.DocumentService#documentExists(java.lang.String)
 384  
      */
 385  
     @Override
 386  
         public boolean documentExists(String documentHeaderId) {
 387  
         // validate parameters
 388  0
         if (StringUtils.isBlank(documentHeaderId)) {
 389  0
             throw new IllegalArgumentException("invalid (blank) documentHeaderId");
 390  
         }
 391  
 
 392  0
             boolean internalUserSession = false;
 393  
             try {
 394  
                     // KFSMI-2543 - allowed method to run without a user session so it can be used
 395  
                     // by workflow processes
 396  0
                 if (GlobalVariables.getUserSession() == null) {
 397  0
                         internalUserSession = true;
 398  0
                         GlobalVariables.setUserSession(new UserSession(KNSConstants.SYSTEM_USER));
 399  0
                         GlobalVariables.clear();
 400  
                 }
 401  
 
 402  
                 // look for workflowDocumentHeader, since that supposedly won't break the transaction
 403  0
                 if (getWorkflowDocumentService().workflowDocumentExists(documentHeaderId)) {
 404  
                     // look for docHeaderId, since that fails without breaking the transaction
 405  0
                     return getDocumentHeaderService().getDocumentHeaderById(documentHeaderId) != null;
 406  
                 }
 407  
 
 408  0
                 return false;
 409  
             } finally {
 410  
                     // if a user session was established for this call, clear it our
 411  0
                     if ( internalUserSession ) {
 412  0
                             GlobalVariables.clear();
 413  0
                             GlobalVariables.setUserSession(null);
 414  
                     }
 415  
             }
 416  
     }
 417  
 
 418  
     /**
 419  
      * Creates a new document by class.
 420  
      *
 421  
      * @see org.kuali.rice.kns.service.DocumentService#getNewDocument(java.lang.Class)
 422  
      */
 423  
     @Override
 424  
         public Document getNewDocument(Class<? extends Document> documentClass) throws WorkflowException {
 425  0
         if (documentClass == null) {
 426  0
             throw new IllegalArgumentException("invalid (null) documentClass");
 427  
         }
 428  0
         if (!Document.class.isAssignableFrom(documentClass)) {
 429  0
             throw new IllegalArgumentException("invalid (non-Document) documentClass");
 430  
         }
 431  
 
 432  0
         String documentTypeName = getDataDictionaryService().getDocumentTypeNameByClass(documentClass);
 433  0
         if (StringUtils.isBlank(documentTypeName)) {
 434  0
             throw new UnknownDocumentTypeException("unable to get documentTypeName for unknown documentClass '" + documentClass.getName() + "'");
 435  
         }
 436  0
         return getNewDocument(documentTypeName);
 437  
     }
 438  
 
 439  
 
 440  
     /**
 441  
      * Creates a new document by document type name.
 442  
      *
 443  
      * @see org.kuali.rice.kns.service.DocumentService#getNewDocument(java.lang.String)
 444  
      */
 445  
     @Override
 446  
         public Document getNewDocument(String documentTypeName) throws WorkflowException {
 447  
 
 448  
         // argument validation
 449  0
         String watchName = "DocumentServiceImpl.getNewDocument";
 450  0
         StopWatch watch = new StopWatch();
 451  0
         watch.start();
 452  0
         if (LOG.isDebugEnabled()) {
 453  0
             LOG.debug(watchName + ": started");
 454  
         }
 455  0
         if (StringUtils.isBlank(documentTypeName)) {
 456  0
             throw new IllegalArgumentException("invalid (blank) documentTypeName");
 457  
         }
 458  0
         if (GlobalVariables.getUserSession() == null) {
 459  0
             throw new IllegalStateException("GlobalVariables must be populated with a valid UserSession before a new document can be created");
 460  
         }
 461  
 
 462  
         // get the class for this docTypeName
 463  0
         Class<? extends Document> documentClass = getDocumentClassByTypeName(documentTypeName);
 464  
 
 465  
         // get the current user
 466  0
         Person currentUser = GlobalVariables.getUserSession().getPerson();
 467  
 
 468  
         // get the authorization
 469  0
         DocumentAuthorizer documentAuthorizer = getDocumentHelperService().getDocumentAuthorizer(documentTypeName);
 470  0
         DocumentPresentationController documentPresentationController = getDocumentHelperService().getDocumentPresentationController(documentTypeName);
 471  
         // make sure this person is authorized to initiate
 472  0
         LOG.debug("calling canInitiate from getNewDocument()");
 473  0
         if (!documentPresentationController.canInitiate(documentTypeName) || !documentAuthorizer.canInitiate(documentTypeName, currentUser)) {
 474  0
                 throw new DocumentAuthorizationException(currentUser.getPrincipalName(), "initiate", documentTypeName);
 475  
         }
 476  
 
 477  
         // initiate new workflow entry, get the workflow doc
 478  0
         KualiWorkflowDocument workflowDocument = getWorkflowDocumentService().createWorkflowDocument(documentTypeName, GlobalVariables.getUserSession().getPerson());
 479  0
         KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),workflowDocument);
 480  
 
 481  
         // create a new document header object
 482  0
         DocumentHeader documentHeader = null;
 483  
         try {
 484  
             // create a new document header object
 485  0
             Class<? extends DocumentHeader> documentHeaderClass = getDocumentHeaderService().getDocumentHeaderBaseClass();
 486  0
             documentHeader = documentHeaderClass.newInstance();
 487  0
             documentHeader.setWorkflowDocument(workflowDocument);
 488  0
             documentHeader.setDocumentNumber(workflowDocument.getDocumentId());
 489  
             // status and notes are initialized correctly in the constructor
 490  
         }
 491  0
         catch (IllegalAccessException e) {
 492  0
             throw new RuntimeException("Error instantiating DocumentHeader", e);
 493  
         }
 494  0
         catch (InstantiationException e) {
 495  0
             throw new RuntimeException("Error instantiating DocumentHeader", e);
 496  0
         }
 497  
 
 498  
         // build Document of specified type
 499  0
         Document document = null;
 500  
         try {
 501  
             // all maintenance documents have same class
 502  0
             if (MaintenanceDocumentBase.class.isAssignableFrom(documentClass)) {
 503  0
                 Class<?>[] defaultConstructor = new Class[]{String.class};
 504  0
                 Constructor<? extends Document> cons = documentClass.getConstructor(defaultConstructor);
 505  0
                 if (ObjectUtils.isNull(cons)) {
 506  0
                     throw new ConfigurationException("Could not find constructor with document type name parameter needed for Maintenance Document Base class");
 507  
                 }
 508  0
                 document = cons.newInstance(documentTypeName);
 509  0
             } else {
 510  
                 // non-maintenance document
 511  0
                 document = documentClass.newInstance();
 512  
             }
 513  0
         } catch (IllegalAccessException e) {
 514  0
             throw new RuntimeException("Error instantiating Document", e);
 515  0
         } catch (InstantiationException e) {
 516  0
             throw new RuntimeException("Error instantiating Document", e);
 517  0
         } catch (SecurityException e) {
 518  0
             throw new RuntimeException("Error instantiating Maintenance Document", e);
 519  0
         } catch (NoSuchMethodException e) {
 520  0
             throw new RuntimeException("Error instantiating Maintenance Document: No constructor with String parameter found", e);
 521  0
         } catch (IllegalArgumentException e) {
 522  0
             throw new RuntimeException("Error instantiating Maintenance Document", e);
 523  0
         } catch (InvocationTargetException e) {
 524  0
             throw new RuntimeException("Error instantiating Maintenance Document", e);
 525  0
         }
 526  
 
 527  0
         document.setDocumentHeader(documentHeader);
 528  0
         document.setDocumentNumber(documentHeader.getDocumentNumber());
 529  
 
 530  0
         watch.stop();
 531  0
         if (LOG.isDebugEnabled()) {
 532  0
             LOG.debug(watchName + ": " + watch.toString());        
 533  
         }
 534  0
         return document;
 535  
     }
 536  
 
 537  
     /**
 538  
      * This is temporary until workflow 2.0 and reads from a table to get documents whose status has changed to A (approved - no
 539  
      * outstanding approval actions requested)
 540  
      *
 541  
      * @param documentHeaderId
 542  
      * @throws WorkflowException
 543  
      * @return Document
 544  
      */
 545  
     @Override
 546  
         public Document getByDocumentHeaderId(String documentHeaderId) throws WorkflowException {
 547  0
         if (documentHeaderId == null) {
 548  0
             throw new IllegalArgumentException("invalid (null) documentHeaderId");
 549  
         }
 550  0
             boolean internalUserSession = false;
 551  
             try {
 552  
                     // KFSMI-2543 - allowed method to run without a user session so it can be used
 553  
                     // by workflow processes
 554  0
                 if (GlobalVariables.getUserSession() == null) {
 555  0
                         internalUserSession = true;
 556  0
                         GlobalVariables.setUserSession(new UserSession(KNSConstants.SYSTEM_USER));
 557  0
                         GlobalVariables.clear();
 558  
                 }
 559  
 
 560  0
                 KualiWorkflowDocument workflowDocument = null;
 561  
 
 562  0
                 if ( LOG.isDebugEnabled() ) {
 563  0
                         LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
 564  
                 }
 565  0
                 workflowDocument = getWorkflowDocumentService().loadWorkflowDocument(documentHeaderId, GlobalVariables.getUserSession().getPerson());
 566  0
                 KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),workflowDocument);
 567  
 
 568  0
                 Class<? extends Document> documentClass = getDocumentClassByTypeName(workflowDocument.getDocumentType());
 569  
 
 570  
                 // retrieve the Document
 571  0
                 Document document = getDocumentDao().findByDocumentHeaderId(documentClass, documentHeaderId);
 572  
                 
 573  0
                 return postProcessDocument(documentHeaderId, workflowDocument, document);
 574  
             } finally {
 575  
                     // if a user session was established for this call, clear it out
 576  0
                     if ( internalUserSession ) {
 577  0
                             GlobalVariables.clear();
 578  0
                             GlobalVariables.setUserSession(null);
 579  
                     }
 580  
             }
 581  
     }
 582  
 
 583  
         /**
 584  
          * @see org.kuali.rice.kns.service.DocumentService#getByDocumentHeaderIdSessionless(java.lang.String)
 585  
          */
 586  
         @Override
 587  
         public Document getByDocumentHeaderIdSessionless(String documentHeaderId)
 588  
                         throws WorkflowException {
 589  0
         if (documentHeaderId == null) {
 590  0
             throw new IllegalArgumentException("invalid (null) documentHeaderId");
 591  
         }
 592  
 
 593  0
         KualiWorkflowDocument workflowDocument = null;
 594  
 
 595  0
         if ( LOG.isDebugEnabled() ) {
 596  0
             LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
 597  
         }
 598  
 
 599  0
         Person person = getPersonService().getPersonByPrincipalName(KNSConstants.SYSTEM_USER);
 600  0
         workflowDocument = workflowDocumentService.loadWorkflowDocument(documentHeaderId, person);
 601  
 
 602  0
         Class<? extends Document> documentClass = getDocumentClassByTypeName(workflowDocument.getDocumentType());
 603  
 
 604  
         // retrieve the Document
 605  0
         Document document = getDocumentDao().findByDocumentHeaderId(documentClass, documentHeaderId);
 606  
         
 607  0
         return postProcessDocument(documentHeaderId, workflowDocument, document);
 608  
         }
 609  
 
 610  
     private Class<? extends Document> getDocumentClassByTypeName(String documentTypeName) {
 611  0
         if (StringUtils.isBlank(documentTypeName)) {
 612  0
             throw new IllegalArgumentException("invalid (blank) documentTypeName");
 613  
         }
 614  
 
 615  0
         Class<? extends Document> clazz = getDataDictionaryService().getDocumentClassByTypeName(documentTypeName);
 616  0
         if (clazz == null) {
 617  0
             throw new UnknownDocumentTypeException("unable to get class for unknown documentTypeName '" + documentTypeName + "'");
 618  
         }
 619  0
         return clazz;
 620  
     }
 621  
     
 622  
     /**
 623  
      * Loads the Notes for the note target on this Document.
 624  
      * 
 625  
      * @param document the document for which to load the notes
 626  
      */
 627  
     protected void loadNotes(Document document) {
 628  0
             if (isNoteTargetReady(document)) {
 629  0
                     List<Note> notes = getNoteService().getByRemoteObjectId(document.getNoteTarget().getObjectId());
 630  
                     // KULRNE-5692 - force a refresh of the attachments
 631  
             // they are not (non-updateable) references and don't seem to update properly upon load
 632  0
                     for (Note note : notes) {
 633  0
                             note.refreshReferenceObject("attachment");
 634  
                     }
 635  0
                     document.setNotes(notes);
 636  
             }
 637  0
     }
 638  
 
 639  
     /**
 640  
      * Performs required post-processing for every document from the documentDao
 641  
      *
 642  
      * @param documentHeaderId
 643  
      * @param workflowDocument
 644  
      * @param document
 645  
      */
 646  
     private Document postProcessDocument(String documentHeaderId, KualiWorkflowDocument workflowDocument, Document document) {
 647  0
         if (document != null) {
 648  0
             document.getDocumentHeader().setWorkflowDocument(workflowDocument);
 649  0
             document.processAfterRetrieve();
 650  0
             loadNotes(document);
 651  
         }
 652  0
         return document;
 653  
     }
 654  
 
 655  
 
 656  
     /**
 657  
      * The default implementation - this retrieves all documents by a list of documentHeader for a given class.
 658  
      *
 659  
      * @see org.kuali.rice.kns.service.DocumentService#getDocumentsByListOfDocumentHeaderIds(java.lang.Class, java.util.List)
 660  
      */
 661  
     @Override
 662  
         public List<Document> getDocumentsByListOfDocumentHeaderIds(Class<? extends Document> documentClass, List<String> documentHeaderIds) throws WorkflowException {
 663  
         // validate documentHeaderIdList and contents
 664  0
         if (documentHeaderIds == null) {
 665  0
             throw new IllegalArgumentException("invalid (null) documentHeaderId list");
 666  
         }
 667  0
         int index = 0;
 668  0
         for (String documentHeaderId : documentHeaderIds) {
 669  0
             if (StringUtils.isBlank(documentHeaderId)) {
 670  0
                 throw new IllegalArgumentException("invalid (blank) documentHeaderId at list index " + index);
 671  
             }
 672  0
             index++;
 673  
         }
 674  
 
 675  0
             boolean internalUserSession = false;
 676  
             try {
 677  
                     // KFSMI-2543 - allowed method to run without a user session so it can be used
 678  
                     // by workflow processes
 679  0
                 if (GlobalVariables.getUserSession() == null) {
 680  0
                         internalUserSession = true;
 681  0
                         GlobalVariables.setUserSession(new UserSession(KNSConstants.SYSTEM_USER));
 682  0
                         GlobalVariables.clear();
 683  
                 }
 684  
 
 685  
                 // retrieve all documents that match the document header ids
 686  0
                 List<? extends Document> rawDocuments = getDocumentDao().findByDocumentHeaderIds(documentClass, documentHeaderIds);
 687  
 
 688  
                 // post-process them
 689  0
                 List<Document> documents = new ArrayList<Document>();
 690  0
                 for (Document document : rawDocuments) {
 691  0
                     KualiWorkflowDocument workflowDocument = getWorkflowDocumentService().loadWorkflowDocument(document.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
 692  
 
 693  0
                     document = postProcessDocument(document.getDocumentNumber(), workflowDocument, document);
 694  0
                     documents.add(document);
 695  0
                 }
 696  0
                 return documents;
 697  
             } finally {
 698  
                     // if a user session was established for this call, clear it our
 699  0
                     if ( internalUserSession ) {
 700  0
                             GlobalVariables.clear();
 701  0
                             GlobalVariables.setUserSession(null);
 702  
                     }
 703  
             }
 704  
     }
 705  
 
 706  
     /* Helper Methods */
 707  
 
 708  
     /**
 709  
      * Validates and persists a document.
 710  
      *
 711  
      * @see org.kuali.rice.kns.service.DocumentService#validateAndPersistDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 712  
      */
 713  
     public Document validateAndPersistDocument(Document document, KualiDocumentEvent event) throws ValidationException {
 714  0
         if (document == null) {
 715  0
             LOG.error("document passed to validateAndPersist was null");
 716  0
             throw new IllegalArgumentException("invalid (null) document");
 717  
         }
 718  0
         if ( LOG.isDebugEnabled() ) {
 719  0
                 LOG.debug("validating and preparing to persist document " + document.getDocumentNumber());
 720  
         }
 721  
 
 722  0
         document.validateBusinessRules(event);
 723  0
         document.prepareForSave(event);
 724  
 
 725  
         // save the document
 726  0
         Document savedDocument = null;
 727  
         try {
 728  0
                 if ( LOG.isInfoEnabled() ) {
 729  0
                         LOG.info("storing document " + document.getDocumentNumber());
 730  
                 }
 731  0
             savedDocument = getDocumentDao().save(document);
 732  
         }
 733  0
         catch (OptimisticLockingFailureException e) {
 734  0
             LOG.error("exception encountered on store of document " + e.getMessage());
 735  0
             throw e;
 736  0
         }
 737  
         
 738  0
         boolean notesSaved = saveDocumentNotes(document);
 739  0
         if (!notesSaved) {
 740  0
                 if (LOG.isInfoEnabled()) {
 741  0
                         LOG.info("Notes not saved during validateAndPersistDocument, likely means that note save needs to be deferred because note target is not ready.");
 742  
                 }
 743  
         }
 744  
 
 745  0
         savedDocument.postProcessSave(event);
 746  
 
 747  0
         return savedDocument;
 748  
     }
 749  
 
 750  
 
 751  
     /**
 752  
      * Sets the title and app document id in the flex document
 753  
      *
 754  
      * @param document
 755  
      * @throws WorkflowException
 756  
      */
 757  
     @Override
 758  
         public void prepareWorkflowDocument(Document document) throws WorkflowException {
 759  
         // populate document content so searchable attributes will be indexed properly
 760  0
         document.populateDocumentForRouting();
 761  
 
 762  
         // make sure we push the document title into the workflowDocument
 763  0
         populateDocumentTitle(document);
 764  
 
 765  
         // make sure we push the application document id into the workflowDocument
 766  0
         populateApplicationDocumentId(document);
 767  0
     }
 768  
 
 769  
     /**
 770  
      * This method will grab the generated document title from the document and add it to the workflowDocument so that it gets pushed into
 771  
      * workflow when routed.
 772  
      *
 773  
      * @param document
 774  
      * @throws WorkflowException
 775  
      */
 776  
     private void populateDocumentTitle(Document document) throws WorkflowException {
 777  0
         String documentTitle = document.getDocumentTitle();
 778  0
         if (StringUtils.isNotBlank(documentTitle)) {
 779  0
             document.getDocumentHeader().getWorkflowDocument().setTitle(documentTitle);
 780  
         }
 781  0
     }
 782  
 
 783  
     /**
 784  
      * This method will grab the organization document number from the document and add it to the workflowDocument so that it gets pushed
 785  
      * into workflow when routed.
 786  
      *
 787  
      * @param document
 788  
      */
 789  
     private void populateApplicationDocumentId(Document document) {
 790  0
         String organizationDocumentNumber = document.getDocumentHeader().getOrganizationDocumentNumber();
 791  0
         if (StringUtils.isNotBlank(organizationDocumentNumber)) {
 792  0
             document.getDocumentHeader().getWorkflowDocument().setAppDocId(organizationDocumentNumber);
 793  
         }
 794  0
     }
 795  
 
 796  
     /**
 797  
      * This is to allow for updates of document statuses and other related requirements for updates outside of the initial save and
 798  
      * route
 799  
      */
 800  
     @Override
 801  
         public Document updateDocument(Document document) {
 802  0
         checkForNulls(document);
 803  0
         return getDocumentDao().save(document);
 804  
     }
 805  
 
 806  
     /**
 807  
      *
 808  
      * @see org.kuali.rice.kns.service.DocumentService#createNoteFromDocument(org.kuali.rice.kns.document.Document, java.lang.String)
 809  
      */
 810  
     @Override
 811  
         public Note createNoteFromDocument(Document document, String text) {
 812  0
         Note note = new Note();
 813  
 
 814  0
         note.setNotePostedTimestamp(getDateTimeService().getCurrentTimestamp());
 815  0
         note.setVersionNumber(Long.valueOf(1));
 816  0
         note.setNoteText(text);
 817  0
         note.setNoteTypeCode(document.getNoteType().getCode());
 818  
 
 819  0
         PersistableBusinessObject bo = document.getNoteTarget();
 820  
         // TODO gah! this is awful
 821  0
         Person kualiUser = GlobalVariables.getUserSession().getPerson();
 822  0
         if (kualiUser == null) {
 823  0
                 throw new IllegalStateException("Current UserSession has a null Person.");
 824  
         }
 825  0
         return bo == null ? null : getNoteService().createNote(note, bo, kualiUser.getPrincipalId());
 826  
     }
 827  
     
 828  
     
 829  
         /**
 830  
          * @see org.kuali.rice.kns.service.DocumentService#saveDocumentNotes(org.kuali.rice.kns.document.Document)
 831  
          */
 832  
     @Override
 833  
         public boolean saveDocumentNotes(Document document) {
 834  0
                 if (isNoteTargetReady(document)) {
 835  0
                         List<Note> notes = document.getNotes();
 836  0
                         for (Note note : document.getNotes()) {
 837  0
                                 linkNoteRemoteObjectId(note, document.getNoteTarget());
 838  
                         }
 839  0
                         getNoteService().saveNoteList(notes);
 840  0
                         return true;
 841  
                 }
 842  0
                 return false;
 843  
         }
 844  
         
 845  
         /**
 846  
          * Determines if the given document's note target is ready for notes to be
 847  
          * attached and persisted against it.  This method verifies that the document's
 848  
          * note target is non-null as well as checking that it has a non-empty object id. 
 849  
          *
 850  
          * @param the document on which to check for note target readiness
 851  
          * @return true if the note target is ready, false otherwise
 852  
          */
 853  
         protected boolean isNoteTargetReady(Document document) {
 854  0
                 PersistableBusinessObject noteTarget = document.getNoteTarget();
 855  0
                 if (noteTarget == null || StringUtils.isBlank(noteTarget.getObjectId())) {
 856  0
                         return false;
 857  
                 }
 858  0
                 return true;
 859  
         }
 860  
         
 861  
         private void linkNoteRemoteObjectId(Note note, PersistableBusinessObject noteTarget) {
 862  0
             String objectId = noteTarget.getObjectId();
 863  0
             if (StringUtils.isBlank(objectId)) {
 864  0
                     throw new IllegalStateException("Attempted to link a Note with a PersistableBusinessObject with no object id");
 865  
             }
 866  0
             note.setRemoteObjectIdentifier(noteTarget.getObjectId());
 867  0
     }
 868  
 
 869  
     /**
 870  
          * This overridden method ...
 871  
          *
 872  
          * @see org.kuali.rice.kns.service.DocumentService#sendAdHocRequests(org.kuali.rice.kns.document.Document, java.util.List)
 873  
          */
 874  
         @Override
 875  
         public void sendAdHocRequests(Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients) throws WorkflowException{
 876  0
                 prepareWorkflowDocument(document);
 877  0
                 getWorkflowDocumentService().sendWorkflowNotification(document.getDocumentHeader().getWorkflowDocument(),
 878  
                         annotation, adHocRecipients);
 879  0
                 KNSServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),document.getDocumentHeader().getWorkflowDocument());
 880  
                 //getBusinessObjectService().delete(document.getAdHocRoutePersons());
 881  
                 //getBusinessObjectService().delete(document.getAdHocRouteWorkgroups());
 882  0
                 removeAdHocPersonsAndWorkgroups(document);
 883  0
         }
 884  
 
 885  
         /**
 886  
      * spring injected date time service
 887  
      *
 888  
      * @param dateTimeService
 889  
      */
 890  
     public synchronized void setDateTimeService(DateTimeService dateTimeService) {
 891  0
         this.dateTimeService = dateTimeService;
 892  0
     }
 893  
 
 894  
     /**
 895  
      * Gets the DateTimeService, lazily initializing if necessary
 896  
      * @return the DateTimeService
 897  
      */
 898  
     private synchronized DateTimeService getDateTimeService() {
 899  0
         if (this.dateTimeService == null) {
 900  0
             this.dateTimeService = CoreApiServiceLocator.getDateTimeService();
 901  
         }
 902  0
         return this.dateTimeService;
 903  
     }
 904  
 
 905  
     /**
 906  
      * Sets the noteService attribute value.
 907  
      * @param noteService The noteService to set.
 908  
      */
 909  
     public synchronized void setNoteService(NoteService noteService) {
 910  0
         this.noteService = noteService;
 911  0
     }
 912  
 
 913  
     /**
 914  
      * Gets the NoteService, lazily initializing if necessary
 915  
      * @return the NoteService
 916  
      */
 917  
     protected synchronized NoteService getNoteService() {
 918  0
         if (this.noteService == null) {
 919  0
             this.noteService = KNSServiceLocator.getNoteService();
 920  
         }
 921  0
         return this.noteService;
 922  
     }
 923  
 
 924  
     /**
 925  
      * Sets the businessObjectService attribute value.
 926  
      *
 927  
      * @param businessObjectService The businessObjectService to set.
 928  
      */
 929  
     public synchronized void setBusinessObjectService(BusinessObjectService businessObjectService) {
 930  0
         this.businessObjectService = businessObjectService;
 931  0
     }
 932  
 
 933  
     /**
 934  
      * Gets the {@link BusinessObjectService}, lazily initializing if necessary
 935  
      * @return the {@link BusinessObjectService}
 936  
      */
 937  
     protected synchronized BusinessObjectService getBusinessObjectService() {
 938  0
         if (this.businessObjectService == null) {
 939  0
             this.businessObjectService = KNSServiceLocator.getBusinessObjectService();
 940  
         }
 941  0
         return this.businessObjectService;
 942  
     }
 943  
 
 944  
     /**
 945  
      * Sets the workflowDocumentService attribute value.
 946  
      *
 947  
      * @param workflowDocumentService The workflowDocumentService to set.
 948  
      */
 949  
     public synchronized void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
 950  0
         this.workflowDocumentService = workflowDocumentService;
 951  0
     }
 952  
 
 953  
     /**
 954  
      * Gets the {@link WorkflowDocumentService}, lazily initializing if necessary
 955  
      * @return the {@link WorkflowDocumentService}
 956  
      */
 957  
     protected synchronized WorkflowDocumentService getWorkflowDocumentService() {
 958  0
         if (this.workflowDocumentService == null) {
 959  0
             this.workflowDocumentService = KNSServiceLocatorWeb.getWorkflowDocumentService();
 960  
         }
 961  0
         return this.workflowDocumentService;
 962  
     }
 963  
 
 964  
     /**
 965  
      * Sets the documentDao attribute value.
 966  
      *
 967  
      * @param documentDao The documentDao to set.
 968  
      */
 969  
     public synchronized void setDocumentDao(DocumentDao documentDao) {
 970  0
         this.documentDao = documentDao;
 971  0
     }
 972  
 
 973  
     /**
 974  
      * Gets the {@link DocumentDao}, lazily initializing if necessary
 975  
      * @return the {@link DocumentDao}
 976  
      */
 977  
     protected synchronized DocumentDao getDocumentDao() {
 978  0
         if (this.documentDao == null) {
 979  0
             this.documentDao = KNSServiceLocatorInternal.getDocumentDao();
 980  
         }
 981  0
         return documentDao;
 982  
     }
 983  
 
 984  
     /**
 985  
      * Sets the dataDictionaryService attribute value.
 986  
      *
 987  
      * @param dataDictionaryService
 988  
      */
 989  
     public synchronized void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
 990  0
         this.dataDictionaryService = dataDictionaryService;
 991  0
     }
 992  
 
 993  
     /**
 994  
      * Gets the {@link DataDictionaryService}, lazily initializing if necessary
 995  
      * @return the {@link DataDictionaryService}
 996  
      */
 997  
     protected synchronized DataDictionaryService getDataDictionaryService() {
 998  0
         if (this.dataDictionaryService == null) {
 999  0
             this.dataDictionaryService = KNSServiceLocatorWeb.getDataDictionaryService();
 1000  
         }
 1001  0
         return this.dataDictionaryService;
 1002  
     }
 1003  
 
 1004  
     /**
 1005  
      * @param documentHeaderService the documentHeaderService to set
 1006  
      */
 1007  
     public synchronized void setDocumentHeaderService(DocumentHeaderService documentHeaderService) {
 1008  0
         this.documentHeaderService = documentHeaderService;
 1009  0
     }
 1010  
 
 1011  
     /**
 1012  
      * Gets the {@link DocumentHeaderService}, lazily initializing if necessary
 1013  
      * @return the {@link DocumentHeaderService}
 1014  
      */
 1015  
     protected synchronized DocumentHeaderService getDocumentHeaderService() {
 1016  0
         if (this.documentHeaderService == null) {
 1017  0
             this.documentHeaderService = KNSServiceLocatorWeb.getDocumentHeaderService();
 1018  
         }
 1019  0
         return this.documentHeaderService;
 1020  
     }
 1021  
 
 1022  
     /**
 1023  
          * @param personService the personService to set
 1024  
          */
 1025  
         public PersonService getPersonService() {
 1026  0
                 if (personService == null) {
 1027  0
                         personService = KimApiServiceLocator.getPersonService();
 1028  
                 }
 1029  0
                 return personService;
 1030  
         }
 1031  
 
 1032  
     /**
 1033  
      * @return the documentHelperService
 1034  
      */
 1035  
     public DocumentHelperService getDocumentHelperService() {
 1036  0
         if (documentHelperService == null) {
 1037  0
             this.documentHelperService = KNSServiceLocatorWeb.getDocumentHelperService();
 1038  
         }
 1039  0
         return this.documentHelperService;
 1040  
     }
 1041  
 
 1042  
     /**
 1043  
      * @param documentHelperService the documentHelperService to set
 1044  
      */
 1045  
     public void setDocumentHelperService(DocumentHelperService documentHelperService) {
 1046  0
         this.documentHelperService = documentHelperService;
 1047  0
     }
 1048  
     
 1049  
     private void removeAdHocPersonsAndWorkgroups(Document document){
 1050  0
             List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
 1051  0
             List<AdHocRouteWorkgroup> adHocRouteWorkgroups = new ArrayList<AdHocRouteWorkgroup>();
 1052  0
             getBusinessObjectService().delete(document.getAdHocRoutePersons());
 1053  0
             getBusinessObjectService().delete(document.getAdHocRouteWorkgroups());
 1054  0
             document.setAdHocRoutePersons(adHocRoutePersons);
 1055  0
             document.setAdHocRouteWorkgroups(adHocRouteWorkgroups);
 1056  0
     }
 1057  
 
 1058  
     /**
 1059  
      * @see org.kuali.rice.kns.service.DocumentService
 1060  
      */
 1061  
     @Override
 1062  
     public void sendNoteRouteNotification(Document document, Note note, Person sender) throws WorkflowException {
 1063  0
         AdHocRouteRecipient routeRecipient = note.getAdHocRouteRecipient();
 1064  
 
 1065  
         // build notification request
 1066  0
         Person requestedUser = this.getPersonService().getPersonByPrincipalName(routeRecipient.getId());
 1067  0
         String senderName = sender.getFirstName() + " " + sender.getLastName();
 1068  0
         String requestedName = requestedUser.getFirstName() + " " + requestedUser.getLastName();
 1069  
 
 1070  0
         String notificationText = kualiConfigurationService.getPropertyString(RiceKeyConstants.MESSAGE_NOTE_NOTIFICATION_ANNOTATION);
 1071  0
         if (StringUtils.isBlank(notificationText)) {
 1072  0
             throw new RuntimeException("No annotation message found for note notification. Message needs added to application resources with key:" + RiceKeyConstants.MESSAGE_NOTE_NOTIFICATION_ANNOTATION);
 1073  
         }
 1074  0
         notificationText = MessageFormat.format(notificationText, new Object[]{senderName, requestedName, note.getNoteText()});
 1075  
 
 1076  0
         List<AdHocRouteRecipient> routeRecipients = new ArrayList<AdHocRouteRecipient>();
 1077  0
         routeRecipients.add(routeRecipient);
 1078  
 
 1079  0
         workflowDocumentService.sendWorkflowNotification(document.getDocumentHeader().getWorkflowDocument(), notificationText, routeRecipients, KNSConstants.NOTE_WORKFLOW_NOTIFICATION_REQUEST_LABEL);
 1080  
 
 1081  
         // clear recipient allowing an notification to be sent to another person
 1082  0
         note.setAdHocRouteRecipient(new AdHocRoutePerson());
 1083  0
     }
 1084  
 
 1085  
     /**
 1086  
      * @param kualiConfigurationService the kualiConfigurationService to set
 1087  
      */
 1088  
     public void setKualiConfigurationService(ConfigurationService kualiConfigurationService) {
 1089  0
         this.kualiConfigurationService = kualiConfigurationService;
 1090  0
     }
 1091  
 }