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