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