Coverage Report - org.kuali.rice.krad.document.DocumentBase
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentBase
0%
0/194
0%
0/48
1.778
 
 1  
 /*
 2  
  * Copyright 2005-2007 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.document;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.apache.log4j.Logger;
 20  
 import org.kuali.rice.kew.api.KewApiServiceLocator;
 21  
 import org.kuali.rice.kew.dto.ActionTakenEventDTO;
 22  
 import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO;
 23  
 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
 24  
 import org.kuali.rice.kew.exception.WorkflowException;
 25  
 import org.kuali.rice.kew.util.KEWConstants;
 26  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 27  
 import org.kuali.rice.kim.bo.Person;
 28  
 import org.kuali.rice.krad.bo.AdHocRoutePerson;
 29  
 import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
 30  
 import org.kuali.rice.krad.bo.DocumentHeader;
 31  
 import org.kuali.rice.krad.bo.Note;
 32  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 33  
 import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
 34  
 import org.kuali.rice.krad.datadictionary.DocumentEntry;
 35  
 import org.kuali.rice.krad.datadictionary.WorkflowAttributes;
 36  
 import org.kuali.rice.krad.datadictionary.WorkflowProperties;
 37  
 import org.kuali.rice.krad.document.authorization.PessimisticLock;
 38  
 import org.kuali.rice.krad.exception.PessimisticLockingException;
 39  
 import org.kuali.rice.krad.exception.ValidationException;
 40  
 import org.kuali.rice.krad.rule.event.KualiDocumentEvent;
 41  
 import org.kuali.rice.krad.service.AttachmentService;
 42  
 import org.kuali.rice.krad.service.DocumentSerializerService;
 43  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 44  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 45  
 import org.kuali.rice.krad.service.NoteService;
 46  
 import org.kuali.rice.krad.util.ErrorMessage;
 47  
 import org.kuali.rice.krad.util.GlobalVariables;
 48  
 import org.kuali.rice.krad.util.KRADConstants;
 49  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 50  
 import org.kuali.rice.krad.util.NoteType;
 51  
 import org.kuali.rice.krad.util.ObjectUtils;
 52  
 import org.kuali.rice.krad.util.documentserializer.AlwaysFalsePropertySerializabilityEvaluator;
 53  
 import org.kuali.rice.krad.util.documentserializer.AlwaysTruePropertySerializibilityEvaluator;
 54  
 import org.kuali.rice.krad.util.documentserializer.BusinessObjectPropertySerializibilityEvaluator;
 55  
 import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator;
 56  
 import org.kuali.rice.krad.workflow.DocumentInitiator;
 57  
 import org.kuali.rice.krad.workflow.KualiDocumentXmlMaterializer;
 58  
 import org.kuali.rice.krad.workflow.KualiTransactionalDocumentInformation;
 59  
 import org.springframework.util.AutoPopulatingList;
 60  
 
 61  
 import javax.persistence.CascadeType;
 62  
 import javax.persistence.Column;
 63  
 import javax.persistence.FetchType;
 64  
 import javax.persistence.Id;
 65  
 import javax.persistence.JoinColumn;
 66  
 import javax.persistence.MappedSuperclass;
 67  
 import javax.persistence.OneToMany;
 68  
 import javax.persistence.OneToOne;
 69  
 import javax.persistence.Transient;
 70  
 import java.util.ArrayList;
 71  
 import java.util.Iterator;
 72  
 import java.util.List;
 73  
 import java.util.Map;
 74  
 
 75  
 
 76  
 /**
 77  
  * @see Document
 78  
  */
 79  0
 @MappedSuperclass
 80  
 public abstract class DocumentBase extends PersistableBusinessObjectBase implements Document {
 81  0
     private static final Logger LOG = Logger.getLogger(DocumentBase.class);
 82  
     
 83  
     @Id
 84  
     @Column(name="DOC_HDR_ID")
 85  
     protected String documentNumber;
 86  
     @OneToOne(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE})
 87  
         @JoinColumn(name="DOC_HDR_ID", insertable=false, updatable=false)
 88  
     protected DocumentHeader documentHeader;    
 89  
 
 90  
     @OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE})
 91  
         @JoinColumn(name="DOC_HDR_ID", insertable=false, updatable=false)
 92  
     private List<PessimisticLock> pessimisticLocks;
 93  
 
 94  
     @Transient
 95  
     private List<AdHocRoutePerson> adHocRoutePersons;
 96  
     @Transient
 97  
     private List<AdHocRouteWorkgroup> adHocRouteWorkgroups;
 98  
     @Transient
 99  
     private List<Note> notes;
 100  
     
 101  
     private transient NoteService noteService;
 102  
     private transient AttachmentService attachmentService;
 103  
 
 104  
     /**
 105  
      * Constructs a DocumentBase.java.
 106  
      */
 107  0
     public DocumentBase() {
 108  
         try {
 109  
             // create a new document header object
 110  0
             Class<? extends DocumentHeader> documentHeaderClass = KRADServiceLocatorWeb.getDocumentHeaderService().getDocumentHeaderBaseClass();
 111  0
             setDocumentHeader(documentHeaderClass.newInstance());
 112  0
             pessimisticLocks = new ArrayList<PessimisticLock>();
 113  0
             adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
 114  0
             adHocRouteWorkgroups = new ArrayList<AdHocRouteWorkgroup>();
 115  0
             notes = new ArrayList<Note>();
 116  
         }
 117  0
         catch (IllegalAccessException e) {
 118  0
             throw new RuntimeException("Error instantiating DocumentHeader", e);
 119  
         }
 120  0
         catch (InstantiationException e) {
 121  0
             throw new RuntimeException("Error instantiating DocumentHeader", e);
 122  0
         }
 123  0
     }
 124  
 
 125  
     /**
 126  
      * @see org.kuali.rice.krad.document.Document#getAllowsCopy()
 127  
      */
 128  
     public boolean getAllowsCopy() {
 129  
         // TODO Auto-generated method stub
 130  0
         return false;
 131  
     }
 132  
 
 133  
     /**
 134  
      * This is the default document title implementation. It concatenates the document's data dictionary file label attribute and
 135  
      * the document's document header description together. This title is used to populate workflow and will show up in document
 136  
      * search results and user action lists.
 137  
      *
 138  
      * @see org.kuali.rice.krad.document.Document#getDocumentTitle()
 139  
      */
 140  
     public String getDocumentTitle() {
 141  0
         String documentTypeLabel = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(this.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()).getLabel();
 142  0
         if (null == documentTypeLabel) {
 143  0
             documentTypeLabel = "";
 144  
         }
 145  
     
 146  0
         String description = this.getDocumentHeader().getDocumentDescription();
 147  0
         if (null == description) {
 148  0
             description = "";
 149  
         }
 150  
     
 151  0
         return documentTypeLabel + " - " + description;
 152  
     }
 153  
 
 154  
     /**
 155  
      * Uses the persistence service's implementation of OJB's retrieveNonKey() fields method.
 156  
      *
 157  
      * @see org.kuali.rice.krad.bo.BusinessObject#refresh()
 158  
      */
 159  
     @Override
 160  
     public void refresh() {
 161  0
         KRADServiceLocator.getPersistenceService().retrieveNonKeyFields(this);
 162  0
     }
 163  
 
 164  
     /**
 165  
      * Checks to see if the objectId value is empty. If so, it will try to refresh the object from the DB.
 166  
      *
 167  
      * @see org.kuali.rice.krad.document.Document#refreshIfEmpty()
 168  
      */
 169  
     public void refreshIfEmpty() {
 170  0
         if (null == this.getDocumentHeader()) {
 171  0
             this.refresh();
 172  
         }
 173  0
         else if (StringUtils.isEmpty(this.getDocumentHeader().getObjectId())) {
 174  0
             this.refresh();
 175  
         }
 176  0
     }
 177  
 
 178  
     /**
 179  
      * Uses the persistence service to retrieve a reference object of a parent.
 180  
      *
 181  
      * @see org.kuali.rice.krad.document.Document#refreshReferenceObject(java.lang.String)
 182  
      */
 183  
     @Override
 184  
     public void refreshReferenceObject(String referenceObjectName) {
 185  0
         KRADServiceLocator.getPersistenceService().retrieveReferenceObject(this, referenceObjectName);
 186  0
     }
 187  
 
 188  
     /**
 189  
      * @see org.kuali.rice.krad.document.Document#prepareForSave()
 190  
      */
 191  
     public void prepareForSave() {
 192  
         // do nothing
 193  0
     }
 194  
 
 195  
     /**
 196  
      * @see org.kuali.rice.krad.document.Document#processAfterRetrieve()
 197  
      */
 198  
     public void processAfterRetrieve() {
 199  
             // do nothing
 200  0
     }
 201  
 
 202  
     /**
 203  
      * The the default implementation for RouteLevelChange does nothing, but is meant to provide a hook for documents to implement
 204  
      * for other needs.
 205  
      *
 206  
      * @see org.kuali.rice.krad.document.Document#doRouteLevelChange(org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO)
 207  
      */
 208  
     public void doRouteLevelChange(DocumentRouteLevelChangeDTO levelChangeEvent) {
 209  
         // do nothing
 210  0
     }
 211  
     
 212  
     /**
 213  
      * @see org.kuali.rice.krad.document.Document#doActionTaken(org.kuali.rice.kew.dto.ActionTakenEventDTO)
 214  
      */
 215  
     public void doActionTaken(ActionTakenEventDTO event) {
 216  0
         if ( (KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(this.getClass().getName()).getUseWorkflowPessimisticLocking()) && (!getNonLockingActionTakenCodes().contains(event.getActionTaken().getActionTaken())) ) {
 217  
             //DocumentAuthorizer documentAuthorizer = KRADServiceLocatorInternal.getDocumentAuthorizationService().getDocumentAuthorizer(this);
 218  
             //documentAuthorizer.establishWorkflowPessimisticLocking(this);
 219  0
                 KRADServiceLocatorWeb.getPessimisticLockService().establishWorkflowPessimisticLocking(this);
 220  
         }
 221  0
     }
 222  
     
 223  
     protected List<String> getNonLockingActionTakenCodes() {
 224  0
         List<String> actionTakenStatusCodes = new ArrayList<String>();
 225  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_SAVED_CD);
 226  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_ACKNOWLEDGED_CD);
 227  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_FYI_CD);
 228  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_DENIED_CD);
 229  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_CANCELED_CD);
 230  0
         actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_LOG_DOCUMENT_ACTION_CD);
 231  0
         return actionTakenStatusCodes;
 232  
     }
 233  
 
 234  
     /**
 235  
      * The the default implementation for afterWorkflowEngineProcess does nothing, but is meant to provide a hook for
 236  
      * documents to implement for other needs.
 237  
      * 
 238  
      * @see org.kuali.rice.krad.document.Document#afterWorkflowEngineProcess(boolean)
 239  
      */
 240  
     public void afterWorkflowEngineProcess(boolean successfullyProcessed) {
 241  0
         if (KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(this.getClass().getName()).getUseWorkflowPessimisticLocking()) {
 242  0
             if (successfullyProcessed) {
 243  
                 //DocumentAuthorizer documentAuthorizer = KRADServiceLocatorInternal.getDocumentAuthorizationService().getDocumentAuthorizer(this);
 244  
                 //documentAuthorizer.releaseWorkflowPessimisticLocking(this);
 245  0
                     KRADServiceLocatorWeb.getPessimisticLockService().releaseWorkflowPessimisticLocking(this);
 246  
             }
 247  
         }
 248  0
     }
 249  
 
 250  
     /**
 251  
      * The the default implementation for beforeWorkflowEngineProcess does nothing, but is meant to provide a hook for
 252  
      * documents to implement for other needs.
 253  
      * 
 254  
      * @see org.kuali.rice.krad.document.Document#beforeWorkflowEngineProcess()
 255  
      */
 256  
     public void beforeWorkflowEngineProcess() {
 257  
     // do nothing
 258  0
     }
 259  
     
 260  
     
 261  
 
 262  
     /**
 263  
      * The default implementation returns no additional ids for the workflow engine to lock prior to processing.
 264  
      * 
 265  
      * @see org.kuali.rice.krad.document.Document#getWorkflowEngineDocumentIdsToLock()
 266  
      */
 267  
     public List<Long> getWorkflowEngineDocumentIdsToLock() {
 268  0
                 return null;
 269  
         }
 270  
 
 271  
         /**
 272  
      * @see org.kuali.rice.krad.document.Copyable#toCopy()
 273  
      */
 274  
     public void toCopy() throws WorkflowException, IllegalStateException {
 275  0
         if (!this.getAllowsCopy()) {
 276  0
             throw new IllegalStateException(this.getClass().getName() + " does not support document-level copying");
 277  
         }
 278  0
         String sourceDocumentHeaderId = getDocumentNumber();
 279  0
         setNewDocumentHeader();
 280  
                 
 281  0
         getDocumentHeader().setDocumentTemplateNumber(sourceDocumentHeaderId);
 282  
 
 283  0
         addCopyErrorDocumentNote("copied from document " + sourceDocumentHeaderId);
 284  0
     }
 285  
 
 286  
     /**
 287  
      * Gets a new document header for this documents type and sets in the document instance.
 288  
      * 
 289  
      * @throws WorkflowException
 290  
      */
 291  
     protected void setNewDocumentHeader() throws WorkflowException {
 292  0
         TransactionalDocument newDoc = (TransactionalDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument(getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
 293  0
         newDoc.getDocumentHeader().setDocumentDescription(getDocumentHeader().getDocumentDescription());
 294  0
         newDoc.getDocumentHeader().setOrganizationDocumentNumber(getDocumentHeader().getOrganizationDocumentNumber());
 295  
 
 296  
         try {
 297  0
             ObjectUtils.setObjectPropertyDeep(this, KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber.getClass(), newDoc.getDocumentNumber());
 298  
         }
 299  0
         catch (Exception e) {
 300  0
             LOG.error("Unable to set document number property in copied document " + e.getMessage(),e);
 301  0
             throw new RuntimeException("Unable to set document number property in copied document " + e.getMessage(),e);
 302  0
         }
 303  
 
 304  
         // replace current documentHeader with new documentHeader
 305  0
         setDocumentHeader(newDoc.getDocumentHeader());
 306  0
     }
 307  
 
 308  
     /**
 309  
      * Adds a note to the document indicating it was created by a copy or error correction.
 310  
      * 
 311  
      * @param noteText - text for note
 312  
      */
 313  
     protected void addCopyErrorDocumentNote(String noteText) {
 314  0
         Note note = null;
 315  
         try {
 316  0
             note = KRADServiceLocatorWeb.getDocumentService().createNoteFromDocument(this,noteText);
 317  
         }
 318  0
         catch (Exception e) {
 319  0
          logErrors();
 320  0
          throw new RuntimeException("Couldn't create note on copy or error",e);
 321  0
         }
 322  0
         addNote(note);
 323  0
     }
 324  
 
 325  
     /**
 326  
      * @see org.kuali.rice.krad.document.Document#getXmlForRouteReport()
 327  
      */
 328  
     public String getXmlForRouteReport() {
 329  0
         prepareForSave();
 330  0
         populateDocumentForRouting();
 331  0
         return getDocumentHeader().getWorkflowDocument().getApplicationContent();
 332  
     }
 333  
 
 334  
     /**
 335  
      * @see org.kuali.rice.krad.document.Document#populateDocumentForRouting()
 336  
      */
 337  
     public void populateDocumentForRouting() {
 338  0
         getDocumentHeader().getWorkflowDocument().setApplicationContent(serializeDocumentToXml());
 339  0
     }
 340  
     
 341  
     /**
 342  
      * @see org.kuali.rice.krad.document.Document#serializeDocumentToXml()
 343  
      */
 344  
     public String serializeDocumentToXml() {
 345  0
         DocumentSerializerService documentSerializerService = KRADServiceLocatorWeb.getDocumentSerializerService();
 346  0
         String xml = documentSerializerService.serializeDocumentToXmlForRouting(this);
 347  0
         return xml;
 348  
     }
 349  
 
 350  
     /**
 351  
      * Wraps a document in an instance of KualiDocumentXmlMaterializer, that provides additional metadata for serialization
 352  
      * 
 353  
      * @see org.kuali.rice.krad.document.Document#wrapDocumentWithMetadataForXmlSerialization()
 354  
      */
 355  
     public KualiDocumentXmlMaterializer wrapDocumentWithMetadataForXmlSerialization() {
 356  0
         KualiTransactionalDocumentInformation transInfo = new KualiTransactionalDocumentInformation();
 357  0
         DocumentInitiator initiator = new DocumentInitiator();
 358  0
         String initiatorPrincipalId = getDocumentHeader().getWorkflowDocument().getDocument().getInitiatorPrincipalId();
 359  0
         Person initiatorUser = KimApiServiceLocator.getPersonService().getPerson(initiatorPrincipalId);
 360  0
         initiator.setPerson(initiatorUser);
 361  0
         transInfo.setDocumentInitiator(initiator);
 362  0
         KualiDocumentXmlMaterializer xmlWrapper = new KualiDocumentXmlMaterializer();
 363  0
         xmlWrapper.setDocument(this);
 364  0
         xmlWrapper.setKualiTransactionalDocumentInformation(transInfo);
 365  0
         return xmlWrapper;
 366  
     }
 367  
 
 368  
     /**
 369  
      * If workflowProperties have been defined within the data dictionary for this document, then it returns an instance of 
 370  
      * {@link BusinessObjectPropertySerializibilityEvaluator} initialized with the properties.  If none have been defined, then returns 
 371  
      * {@link AlwaysTruePropertySerializibilityEvaluator}.
 372  
      * 
 373  
      * @see org.kuali.rice.krad.document.Document#getDocumentPropertySerizabilityEvaluator()
 374  
      */
 375  
     public PropertySerializabilityEvaluator getDocumentPropertySerizabilityEvaluator() {
 376  0
         String docTypeName = getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
 377  0
         DocumentEntry documentEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(docTypeName);
 378  0
         WorkflowProperties workflowProperties = documentEntry.getWorkflowProperties();
 379  0
         WorkflowAttributes workflowAttributes = documentEntry.getWorkflowAttributes();
 380  0
         return createPropertySerializabilityEvaluator(workflowProperties, workflowAttributes);
 381  
     }
 382  
     
 383  
     protected PropertySerializabilityEvaluator createPropertySerializabilityEvaluator(WorkflowProperties workflowProperties, WorkflowAttributes workflowAttributes) {
 384  0
             if (workflowAttributes != null) {
 385  0
                     return new AlwaysFalsePropertySerializabilityEvaluator();
 386  
             }
 387  0
             if (workflowProperties == null) {
 388  0
                     return new AlwaysTruePropertySerializibilityEvaluator();
 389  
             }
 390  0
             PropertySerializabilityEvaluator evaluator = new BusinessObjectPropertySerializibilityEvaluator();
 391  0
             evaluator.initializeEvaluatorForDocument(this);
 392  0
             return evaluator;
 393  
     }
 394  
     
 395  
     /**
 396  
      * Returns the POJO property name of "this" document in the object returned by {@link #wrapDocumentWithMetadataForXmlSerialization()}
 397  
      * 
 398  
      * @see org.kuali.rice.krad.document.Document#getBasePathToDocumentDuringSerialization()
 399  
      */
 400  
     public String getBasePathToDocumentDuringSerialization() {
 401  0
         return "document";
 402  
     }
 403  
     
 404  
     
 405  
     /**
 406  
      * @see org.kuali.rice.krad.document.Document#getDocumentHeader()
 407  
      */
 408  
     public DocumentHeader getDocumentHeader() {
 409  0
         return this.documentHeader;
 410  
     }
 411  
 
 412  
     /**
 413  
      * @see org.kuali.rice.krad.document.Document#setDocumentHeader(org.kuali.rice.krad.document.DocumentHeader)
 414  
      */
 415  
     public void setDocumentHeader(DocumentHeader documentHeader) {
 416  0
         this.documentHeader = documentHeader;
 417  0
     }
 418  
 
 419  
     /**
 420  
      * @see org.kuali.rice.krad.document.Document#getDocumentNumber()
 421  
      */
 422  
     public String getDocumentNumber() {
 423  0
         return documentNumber;
 424  
     }
 425  
 
 426  
     /**
 427  
      * @see org.kuali.rice.krad.document.Document#setDocumentNumber(java.lang.String)
 428  
      */
 429  
     public void setDocumentNumber(String documentNumber) {
 430  0
         this.documentNumber = documentNumber;
 431  0
     }
 432  
 
 433  
     /**
 434  
      * @see org.kuali.rice.krad.document.Document#getAdHocRoutePersons()
 435  
      */
 436  
     public List<AdHocRoutePerson> getAdHocRoutePersons() {
 437  0
         return adHocRoutePersons;
 438  
     }
 439  
 
 440  
     /**
 441  
      * @see org.kuali.rice.krad.document.Document#setAdHocRoutePersons(java.util.List)
 442  
      */
 443  
     public void setAdHocRoutePersons(List<AdHocRoutePerson> adHocRoutePersons) {
 444  0
         this.adHocRoutePersons = adHocRoutePersons;
 445  0
 }
 446  
     /**
 447  
      * @see org.kuali.rice.krad.document.Document#getAdHocRouteWorkgroups()
 448  
      */
 449  
     public List<AdHocRouteWorkgroup> getAdHocRouteWorkgroups() {
 450  0
         return adHocRouteWorkgroups;
 451  
     }
 452  
 
 453  
     /**
 454  
      * @see org.kuali.rice.krad.document.Document#setAdHocRouteWorkgroups(java.util.List)
 455  
      */
 456  
     public void setAdHocRouteWorkgroups(List<AdHocRouteWorkgroup> adHocRouteWorkgroups) {
 457  0
         this.adHocRouteWorkgroups = adHocRouteWorkgroups;
 458  0
     }
 459  
 
 460  
     public void postProcessSave(KualiDocumentEvent event) {
 461  
         // TODO Auto-generated method stub
 462  
 
 463  0
         }
 464  
 
 465  
     /**
 466  
      * Override this method with implementation specific prepareForSave logic
 467  
      * 
 468  
      * @see org.kuali.rice.krad.document.Document#prepareForSave(org.kuali.rice.krad.rule.event.KualiDocumentEvent)
 469  
      */
 470  
     public void prepareForSave(KualiDocumentEvent event) {
 471  
             // do nothing by default
 472  0
     }
 473  
 
 474  
     public void validateBusinessRules(KualiDocumentEvent event) {
 475  0
         if (GlobalVariables.getMessageMap().hasErrors()) {
 476  0
             logErrors();
 477  0
             throw new ValidationException("errors occured before business rule");
 478  
         }
 479  
 
 480  
         // perform validation against rules engine
 481  0
         LOG.info("invoking rules engine on document " + getDocumentNumber());
 482  0
         boolean isValid = true;
 483  0
         isValid = KRADServiceLocatorWeb.getKualiRuleService().applyRules(event);
 484  
 
 485  
         // check to see if the br eval passed or failed
 486  0
         if (!isValid) {
 487  0
             logErrors();
 488  
             // TODO: better error handling at the lower level and a better error message are
 489  
             // needed here
 490  0
             throw new ValidationException("business rule evaluation failed");
 491  
         }
 492  0
         else if (GlobalVariables.getMessageMap().hasErrors()) {
 493  0
             logErrors();
 494  0
             throw new ValidationException("Unreported errors occured during business rule evaluation (rule developer needs to put meaningful error messages into global ErrorMap)");
 495  
         }
 496  0
         LOG.debug("validation completed");
 497  
 
 498  0
     }
 499  
 
 500  
     /**
 501  
      * This method logs errors.
 502  
      */
 503  
     protected void logErrors() {
 504  0
             if ( LOG.isInfoEnabled() ) {
 505  0
                 if (GlobalVariables.getMessageMap().hasErrors()) {
 506  
         
 507  0
                     for (Iterator<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> i = GlobalVariables.getMessageMap().getAllPropertiesAndErrors().iterator(); i.hasNext();) {
 508  0
                         Map.Entry<String, AutoPopulatingList<ErrorMessage>> e = i.next();
 509  
         
 510  0
                         StringBuffer logMessage = new StringBuffer();
 511  0
                         logMessage.append("[" + e.getKey() + "] ");
 512  0
                         boolean first = true;
 513  
         
 514  0
                         AutoPopulatingList<ErrorMessage> errorList = e.getValue();
 515  0
                         for (Iterator<ErrorMessage> j = errorList.iterator(); j.hasNext();) {
 516  0
                             ErrorMessage em = j.next();
 517  
         
 518  0
                             if (first) {
 519  0
                                 first = false;
 520  
                             }
 521  
                             else {
 522  0
                                 logMessage.append(";");
 523  
                             }
 524  0
                             logMessage.append(em);
 525  0
                         }
 526  
         
 527  0
                         LOG.info(logMessage);
 528  0
                     }
 529  
                 }
 530  
             }
 531  0
     }
 532  
 
 533  
     /**
 534  
      * Hook for override
 535  
      * 
 536  
      * @see org.kuali.rice.krad.document.Document#generateSaveEvents()
 537  
      */
 538  
     public List<KualiDocumentEvent> generateSaveEvents() {
 539  0
         return new ArrayList<KualiDocumentEvent>();
 540  
     }
 541  
 
 542  
     /**
 543  
      * @see org.kuali.rice.krad.document.Document#doRouteStatusChange(org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO)
 544  
      */
 545  
     public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
 546  
         // do nothing
 547  0
     }
 548  
     
 549  
     /**
 550  
      * Returns the business object with which notes related to this document should be associated.
 551  
      * By default, the {@link DocumentHeader} of this document will be returned as the note target.
 552  
      * 
 553  
      * <p>Sub classes can override this method if they want notes to be associated with something
 554  
      * other than the document header.  If this method is overridden, the {@link #getNoteType()}
 555  
      * method should be overridden to return {@link NoteType#BUSINESS_OBJECT}
 556  
      * 
 557  
      * @return Returns the documentBusinessObject.
 558  
      */
 559  
     @Override
 560  
     public PersistableBusinessObject getNoteTarget() {
 561  0
         return getDocumentHeader();
 562  
     }
 563  
     
 564  
     /**
 565  
          * Returns the {@link NoteType} to use for notes associated with this document.
 566  
          * By default this returns {@link NoteType#DOCUMENT_HEADER} since notes are
 567  
          * associated with the {@link DocumentHeader} record by default.
 568  
          * 
 569  
          * <p>The case in which this should be overridden is if {@link #getNoteTarget()} is
 570  
          * overridden to return an object other than the DocumentHeader.
 571  
          *
 572  
          * @return the note type to use for notes associated with this document
 573  
          * 
 574  
          * @see org.kuali.rice.krad.document.Document#getNoteType()
 575  
          */
 576  
         @Override
 577  
         public NoteType getNoteType() {
 578  0
                 return NoteType.DOCUMENT_HEADER;
 579  
         }
 580  
 
 581  
         /**
 582  
          * @see org.kuali.rice.krad.document.Document#addNote(org.kuali.rice.krad.bo.Note)
 583  
          */
 584  
     @Override
 585  
         public void addNote(Note note) {
 586  0
             if (note == null) {
 587  0
                     throw new IllegalArgumentException("Note cannot be null.");
 588  
             }
 589  0
                 notes.add(note);
 590  0
         }
 591  
 
 592  
     /**
 593  
      * @see org.kuali.rice.krad.document.Document#removeNote(org.kuali.rice.krad.bo.Note)
 594  
      */
 595  
         @Override
 596  
         public boolean removeNote(Note note) {
 597  0
                 if (note == null) {
 598  0
                     throw new IllegalArgumentException("Note cannot be null.");
 599  
             }
 600  0
                 return notes.remove(note);
 601  
         }
 602  
 
 603  
         /**
 604  
          * @see org.kuali.rice.krad.document.Document#getNote(int)
 605  
          */
 606  
         @Override
 607  
         public Note getNote(int index) {
 608  0
                 return notes.get(index);
 609  
         }
 610  
 
 611  
         /**
 612  
          * @see org.kuali.rice.krad.document.Document#getNotes()
 613  
          */
 614  
         @Override
 615  
         public List<Note> getNotes() {
 616  0
                 return notes;
 617  
         }
 618  
         
 619  
         /**
 620  
          * @see org.kuali.rice.krad.document.Document#setNotes(java.util.List)
 621  
          */
 622  
         @Override
 623  
         public void setNotes(List<Note> notes) {
 624  0
                 if (notes == null) {
 625  0
                         throw new IllegalArgumentException("List of notes must be non-null.");
 626  
                 }
 627  0
                 this.notes = notes;
 628  0
         }
 629  
 
 630  
     /**
 631  
      * @see org.kuali.rice.krad.document.Document#getPessimisticLocks()
 632  
      */
 633  
     public List<PessimisticLock> getPessimisticLocks() {
 634  0
         return this.pessimisticLocks;
 635  
     }
 636  
     
 637  
     /**
 638  
      * @see org.kuali.rice.krad.document.Document#refreshPessimisticLocks()
 639  
      * @deprecated
 640  
      * This is not needed with the relationship set up with JPA annotations
 641  
      */
 642  
     @Deprecated 
 643  
     public void refreshPessimisticLocks() {
 644  0
         this.pessimisticLocks.clear();
 645  0
         this.pessimisticLocks = KRADServiceLocatorWeb.getPessimisticLockService().getPessimisticLocksForDocument(this.documentNumber);
 646  0
     }
 647  
 
 648  
     /**
 649  
      * @param pessimisticLocks the PessimisticLock objects to set
 650  
      */
 651  
     public void setPessimisticLocks(List<PessimisticLock> pessimisticLocks) {
 652  0
         this.pessimisticLocks = pessimisticLocks;
 653  0
     }
 654  
     
 655  
     /**
 656  
      * @see org.kuali.rice.krad.document.Document#addPessimisticLock(org.kuali.rice.krad.document.authorization.PessimisticLock)
 657  
      */
 658  
     public void addPessimisticLock(PessimisticLock lock) {
 659  0
         this.pessimisticLocks.add(lock);
 660  0
     }
 661  
     
 662  
     /**
 663  
      * @see org.kuali.rice.krad.document.Document#getLockClearningMethodNames()
 664  
      */
 665  
     public List<String> getLockClearningMethodNames() {
 666  0
         List<String> methodToCalls = new ArrayList<String>();
 667  0
         methodToCalls.add(KRADConstants.CLOSE_METHOD);
 668  0
         methodToCalls.add(KRADConstants.CANCEL_METHOD);
 669  
 //        methodToCalls.add(RiceConstants.BLANKET_APPROVE_METHOD);
 670  0
         methodToCalls.add(KRADConstants.ROUTE_METHOD);
 671  0
         methodToCalls.add(KRADConstants.APPROVE_METHOD);
 672  0
         methodToCalls.add(KRADConstants.DISAPPROVE_METHOD);
 673  0
         return methodToCalls;
 674  
     }
 675  
 
 676  
     /**
 677  
      * This default implementation simply returns false to indicate that custom lock descriptors are not supported by DocumentBase. If custom lock
 678  
      * descriptors are needed, the appropriate subclasses should override this method.
 679  
      * 
 680  
      * @see org.kuali.rice.krad.document.Document#useCustomLockDescriptors()
 681  
      */
 682  
     public boolean useCustomLockDescriptors() {
 683  0
             return false;
 684  
     }
 685  
 
 686  
     /**
 687  
      * This default implementation just throws a PessimisticLockingException. Subclasses of DocumentBase that need support for custom lock descriptors
 688  
      * should override this method.
 689  
      * 
 690  
      * @see org.kuali.rice.krad.document.Document#getCustomLockDescriptor(org.kuali.rice.kim.bo.Person)
 691  
      */
 692  
     public String getCustomLockDescriptor(Person user) {
 693  0
             throw new PessimisticLockingException("Document " + getDocumentNumber() +
 694  
                             " is using pessimistic locking with custom lock descriptors, but the document class has not overriden the getCustomLockDescriptor method");
 695  
     }
 696  
     
 697  
     protected AttachmentService getAttachmentService() {
 698  0
                 if ( attachmentService == null ) {
 699  0
                         attachmentService = KRADServiceLocator.getAttachmentService();
 700  
                 }
 701  0
                 return attachmentService;
 702  
         }
 703  
     
 704  
     protected NoteService getNoteService() {
 705  0
                 if ( noteService == null ) {
 706  0
                         noteService = KRADServiceLocator.getNoteService();
 707  
                 }
 708  0
                 return noteService;
 709  
         }
 710  
 }