001 /* 002 * Copyright 2005-2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.krad.document; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.apache.log4j.Logger; 020 import org.kuali.rice.kew.api.KewApiServiceLocator; 021 import org.kuali.rice.kew.dto.ActionTakenEventDTO; 022 import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO; 023 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO; 024 import org.kuali.rice.kew.exception.WorkflowException; 025 import org.kuali.rice.kew.util.KEWConstants; 026 import org.kuali.rice.kim.api.identity.Person; 027 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 028 import org.kuali.rice.krad.bo.AdHocRoutePerson; 029 import org.kuali.rice.krad.bo.AdHocRouteWorkgroup; 030 import org.kuali.rice.krad.bo.DocumentHeader; 031 import org.kuali.rice.krad.bo.Note; 032 import org.kuali.rice.krad.bo.PersistableBusinessObject; 033 import org.kuali.rice.krad.bo.PersistableBusinessObjectBase; 034 import org.kuali.rice.krad.datadictionary.DocumentEntry; 035 import org.kuali.rice.krad.datadictionary.WorkflowAttributes; 036 import org.kuali.rice.krad.datadictionary.WorkflowProperties; 037 import org.kuali.rice.krad.document.authorization.PessimisticLock; 038 import org.kuali.rice.krad.exception.PessimisticLockingException; 039 import org.kuali.rice.krad.exception.ValidationException; 040 import org.kuali.rice.krad.rule.event.KualiDocumentEvent; 041 import org.kuali.rice.krad.service.AttachmentService; 042 import org.kuali.rice.krad.service.DocumentSerializerService; 043 import org.kuali.rice.krad.service.KRADServiceLocator; 044 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 045 import org.kuali.rice.krad.service.NoteService; 046 import org.kuali.rice.krad.util.ErrorMessage; 047 import org.kuali.rice.krad.util.GlobalVariables; 048 import org.kuali.rice.krad.util.KRADConstants; 049 import org.kuali.rice.krad.util.KRADPropertyConstants; 050 import org.kuali.rice.krad.util.NoteType; 051 import org.kuali.rice.krad.util.ObjectUtils; 052 import org.kuali.rice.krad.util.documentserializer.AlwaysFalsePropertySerializabilityEvaluator; 053 import org.kuali.rice.krad.util.documentserializer.AlwaysTruePropertySerializibilityEvaluator; 054 import org.kuali.rice.krad.util.documentserializer.BusinessObjectPropertySerializibilityEvaluator; 055 import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator; 056 import org.kuali.rice.krad.workflow.DocumentInitiator; 057 import org.kuali.rice.krad.workflow.KualiDocumentXmlMaterializer; 058 import org.kuali.rice.krad.workflow.KualiTransactionalDocumentInformation; 059 import org.springframework.util.AutoPopulatingList; 060 061 import javax.persistence.CascadeType; 062 import javax.persistence.Column; 063 import javax.persistence.FetchType; 064 import javax.persistence.Id; 065 import javax.persistence.JoinColumn; 066 import javax.persistence.MappedSuperclass; 067 import javax.persistence.OneToMany; 068 import javax.persistence.OneToOne; 069 import javax.persistence.Transient; 070 import java.util.ArrayList; 071 import java.util.Iterator; 072 import java.util.List; 073 import java.util.Map; 074 075 076 /** 077 * @see Document 078 */ 079 @MappedSuperclass 080 public abstract class DocumentBase extends PersistableBusinessObjectBase implements Document { 081 private static final Logger LOG = Logger.getLogger(DocumentBase.class); 082 083 @Id 084 @Column(name="DOC_HDR_ID") 085 protected String documentNumber; 086 @OneToOne(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE}) 087 @JoinColumn(name="DOC_HDR_ID", insertable=false, updatable=false) 088 protected DocumentHeader documentHeader; 089 090 @OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE}) 091 @JoinColumn(name="DOC_HDR_ID", insertable=false, updatable=false) 092 private List<PessimisticLock> pessimisticLocks; 093 094 @Transient 095 private List<AdHocRoutePerson> adHocRoutePersons; 096 @Transient 097 private List<AdHocRouteWorkgroup> adHocRouteWorkgroups; 098 @Transient 099 private List<Note> notes; 100 101 private transient NoteService noteService; 102 private transient AttachmentService attachmentService; 103 104 /** 105 * Constructs a DocumentBase.java. 106 */ 107 public DocumentBase() { 108 try { 109 // create a new document header object 110 Class<? extends DocumentHeader> documentHeaderClass = KRADServiceLocatorWeb.getDocumentHeaderService().getDocumentHeaderBaseClass(); 111 setDocumentHeader(documentHeaderClass.newInstance()); 112 pessimisticLocks = new ArrayList<PessimisticLock>(); 113 adHocRoutePersons = new ArrayList<AdHocRoutePerson>(); 114 adHocRouteWorkgroups = new ArrayList<AdHocRouteWorkgroup>(); 115 notes = new ArrayList<Note>(); 116 } 117 catch (IllegalAccessException e) { 118 throw new RuntimeException("Error instantiating DocumentHeader", e); 119 } 120 catch (InstantiationException e) { 121 throw new RuntimeException("Error instantiating DocumentHeader", e); 122 } 123 } 124 125 /** 126 * @see org.kuali.rice.krad.document.Document#getAllowsCopy() 127 */ 128 public boolean getAllowsCopy() { 129 // TODO Auto-generated method stub 130 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 String documentTypeLabel = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(this.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()).getLabel(); 142 if (null == documentTypeLabel) { 143 documentTypeLabel = ""; 144 } 145 146 String description = this.getDocumentHeader().getDocumentDescription(); 147 if (null == description) { 148 description = ""; 149 } 150 151 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 KRADServiceLocator.getPersistenceService().retrieveNonKeyFields(this); 162 } 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 if (null == this.getDocumentHeader()) { 171 this.refresh(); 172 } 173 else if (StringUtils.isEmpty(this.getDocumentHeader().getObjectId())) { 174 this.refresh(); 175 } 176 } 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 KRADServiceLocator.getPersistenceService().retrieveReferenceObject(this, referenceObjectName); 186 } 187 188 /** 189 * @see org.kuali.rice.krad.document.Document#prepareForSave() 190 */ 191 public void prepareForSave() { 192 // do nothing 193 } 194 195 /** 196 * @see org.kuali.rice.krad.document.Document#processAfterRetrieve() 197 */ 198 public void processAfterRetrieve() { 199 // do nothing 200 } 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 } 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 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 KRADServiceLocatorWeb.getPessimisticLockService().establishWorkflowPessimisticLocking(this); 220 } 221 } 222 223 protected List<String> getNonLockingActionTakenCodes() { 224 List<String> actionTakenStatusCodes = new ArrayList<String>(); 225 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_SAVED_CD); 226 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_ACKNOWLEDGED_CD); 227 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_FYI_CD); 228 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_DENIED_CD); 229 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_CANCELED_CD); 230 actionTakenStatusCodes.add(KEWConstants.ACTION_TAKEN_LOG_DOCUMENT_ACTION_CD); 231 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 if (KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(this.getClass().getName()).getUseWorkflowPessimisticLocking()) { 242 if (successfullyProcessed) { 243 //DocumentAuthorizer documentAuthorizer = KRADServiceLocatorInternal.getDocumentAuthorizationService().getDocumentAuthorizer(this); 244 //documentAuthorizer.releaseWorkflowPessimisticLocking(this); 245 KRADServiceLocatorWeb.getPessimisticLockService().releaseWorkflowPessimisticLocking(this); 246 } 247 } 248 } 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 } 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 return null; 269 } 270 271 /** 272 * @see org.kuali.rice.krad.document.Copyable#toCopy() 273 */ 274 public void toCopy() throws WorkflowException, IllegalStateException { 275 if (!this.getAllowsCopy()) { 276 throw new IllegalStateException(this.getClass().getName() + " does not support document-level copying"); 277 } 278 String sourceDocumentHeaderId = getDocumentNumber(); 279 setNewDocumentHeader(); 280 281 getDocumentHeader().setDocumentTemplateNumber(sourceDocumentHeaderId); 282 283 addCopyErrorDocumentNote("copied from document " + sourceDocumentHeaderId); 284 } 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 TransactionalDocument newDoc = (TransactionalDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument(getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 293 newDoc.getDocumentHeader().setDocumentDescription(getDocumentHeader().getDocumentDescription()); 294 newDoc.getDocumentHeader().setOrganizationDocumentNumber(getDocumentHeader().getOrganizationDocumentNumber()); 295 296 try { 297 ObjectUtils.setObjectPropertyDeep(this, KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber.getClass(), newDoc.getDocumentNumber()); 298 } 299 catch (Exception e) { 300 LOG.error("Unable to set document number property in copied document " + e.getMessage(),e); 301 throw new RuntimeException("Unable to set document number property in copied document " + e.getMessage(),e); 302 } 303 304 // replace current documentHeader with new documentHeader 305 setDocumentHeader(newDoc.getDocumentHeader()); 306 } 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 Note note = null; 315 try { 316 note = KRADServiceLocatorWeb.getDocumentService().createNoteFromDocument(this,noteText); 317 } 318 catch (Exception e) { 319 logErrors(); 320 throw new RuntimeException("Couldn't create note on copy or error",e); 321 } 322 addNote(note); 323 } 324 325 /** 326 * @see org.kuali.rice.krad.document.Document#getXmlForRouteReport() 327 */ 328 public String getXmlForRouteReport() { 329 prepareForSave(); 330 populateDocumentForRouting(); 331 return getDocumentHeader().getWorkflowDocument().getApplicationContent(); 332 } 333 334 /** 335 * @see org.kuali.rice.krad.document.Document#populateDocumentForRouting() 336 */ 337 public void populateDocumentForRouting() { 338 getDocumentHeader().getWorkflowDocument().setApplicationContent(serializeDocumentToXml()); 339 } 340 341 /** 342 * @see org.kuali.rice.krad.document.Document#serializeDocumentToXml() 343 */ 344 public String serializeDocumentToXml() { 345 DocumentSerializerService documentSerializerService = KRADServiceLocatorWeb.getDocumentSerializerService(); 346 String xml = documentSerializerService.serializeDocumentToXmlForRouting(this); 347 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 KualiTransactionalDocumentInformation transInfo = new KualiTransactionalDocumentInformation(); 357 DocumentInitiator initiator = new DocumentInitiator(); 358 String initiatorPrincipalId = getDocumentHeader().getWorkflowDocument().getDocument().getInitiatorPrincipalId(); 359 Person initiatorUser = KimApiServiceLocator.getPersonService().getPerson(initiatorPrincipalId); 360 initiator.setPerson(initiatorUser); 361 transInfo.setDocumentInitiator(initiator); 362 KualiDocumentXmlMaterializer xmlWrapper = new KualiDocumentXmlMaterializer(); 363 xmlWrapper.setDocument(this); 364 xmlWrapper.setKualiTransactionalDocumentInformation(transInfo); 365 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 String docTypeName = getDocumentHeader().getWorkflowDocument().getDocumentTypeName(); 377 DocumentEntry documentEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(docTypeName); 378 WorkflowProperties workflowProperties = documentEntry.getWorkflowProperties(); 379 WorkflowAttributes workflowAttributes = documentEntry.getWorkflowAttributes(); 380 return createPropertySerializabilityEvaluator(workflowProperties, workflowAttributes); 381 } 382 383 protected PropertySerializabilityEvaluator createPropertySerializabilityEvaluator(WorkflowProperties workflowProperties, WorkflowAttributes workflowAttributes) { 384 if (workflowAttributes != null) { 385 return new AlwaysFalsePropertySerializabilityEvaluator(); 386 } 387 if (workflowProperties == null) { 388 return new AlwaysTruePropertySerializibilityEvaluator(); 389 } 390 PropertySerializabilityEvaluator evaluator = new BusinessObjectPropertySerializibilityEvaluator(); 391 evaluator.initializeEvaluatorForDocument(this); 392 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 return "document"; 402 } 403 404 405 /** 406 * @see org.kuali.rice.krad.document.Document#getDocumentHeader() 407 */ 408 public DocumentHeader getDocumentHeader() { 409 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 this.documentHeader = documentHeader; 417 } 418 419 /** 420 * @see org.kuali.rice.krad.document.Document#getDocumentNumber() 421 */ 422 public String getDocumentNumber() { 423 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 this.documentNumber = documentNumber; 431 } 432 433 /** 434 * @see org.kuali.rice.krad.document.Document#getAdHocRoutePersons() 435 */ 436 public List<AdHocRoutePerson> getAdHocRoutePersons() { 437 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 this.adHocRoutePersons = adHocRoutePersons; 445 } 446 /** 447 * @see org.kuali.rice.krad.document.Document#getAdHocRouteWorkgroups() 448 */ 449 public List<AdHocRouteWorkgroup> getAdHocRouteWorkgroups() { 450 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 this.adHocRouteWorkgroups = adHocRouteWorkgroups; 458 } 459 460 public void postProcessSave(KualiDocumentEvent event) { 461 // TODO Auto-generated method stub 462 463 } 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 } 473 474 public void validateBusinessRules(KualiDocumentEvent event) { 475 if (GlobalVariables.getMessageMap().hasErrors()) { 476 logErrors(); 477 throw new ValidationException("errors occured before business rule"); 478 } 479 480 // perform validation against rules engine 481 LOG.info("invoking rules engine on document " + getDocumentNumber()); 482 boolean isValid = true; 483 isValid = KRADServiceLocatorWeb.getKualiRuleService().applyRules(event); 484 485 // check to see if the br eval passed or failed 486 if (!isValid) { 487 logErrors(); 488 // TODO: better error handling at the lower level and a better error message are 489 // needed here 490 throw new ValidationException("business rule evaluation failed"); 491 } 492 else if (GlobalVariables.getMessageMap().hasErrors()) { 493 logErrors(); 494 throw new ValidationException("Unreported errors occured during business rule evaluation (rule developer needs to put meaningful error messages into global ErrorMap)"); 495 } 496 LOG.debug("validation completed"); 497 498 } 499 500 /** 501 * This method logs errors. 502 */ 503 protected void logErrors() { 504 if ( LOG.isInfoEnabled() ) { 505 if (GlobalVariables.getMessageMap().hasErrors()) { 506 507 for (Iterator<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> i = GlobalVariables.getMessageMap().getAllPropertiesAndErrors().iterator(); i.hasNext();) { 508 Map.Entry<String, AutoPopulatingList<ErrorMessage>> e = i.next(); 509 510 StringBuffer logMessage = new StringBuffer(); 511 logMessage.append("[" + e.getKey() + "] "); 512 boolean first = true; 513 514 AutoPopulatingList<ErrorMessage> errorList = e.getValue(); 515 for (Iterator<ErrorMessage> j = errorList.iterator(); j.hasNext();) { 516 ErrorMessage em = j.next(); 517 518 if (first) { 519 first = false; 520 } 521 else { 522 logMessage.append(";"); 523 } 524 logMessage.append(em); 525 } 526 527 LOG.info(logMessage); 528 } 529 } 530 } 531 } 532 533 /** 534 * Hook for override 535 * 536 * @see org.kuali.rice.krad.document.Document#generateSaveEvents() 537 */ 538 public List<KualiDocumentEvent> generateSaveEvents() { 539 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 } 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 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 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 if (note == null) { 587 throw new IllegalArgumentException("Note cannot be null."); 588 } 589 notes.add(note); 590 } 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 if (note == null) { 598 throw new IllegalArgumentException("Note cannot be null."); 599 } 600 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 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 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 if (notes == null) { 625 throw new IllegalArgumentException("List of notes must be non-null."); 626 } 627 this.notes = notes; 628 } 629 630 /** 631 * @see org.kuali.rice.krad.document.Document#getPessimisticLocks() 632 */ 633 public List<PessimisticLock> getPessimisticLocks() { 634 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 this.pessimisticLocks.clear(); 645 this.pessimisticLocks = KRADServiceLocatorWeb.getPessimisticLockService().getPessimisticLocksForDocument(this.documentNumber); 646 } 647 648 /** 649 * @param pessimisticLocks the PessimisticLock objects to set 650 */ 651 public void setPessimisticLocks(List<PessimisticLock> pessimisticLocks) { 652 this.pessimisticLocks = pessimisticLocks; 653 } 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 this.pessimisticLocks.add(lock); 660 } 661 662 /** 663 * @see org.kuali.rice.krad.document.Document#getLockClearningMethodNames() 664 */ 665 public List<String> getLockClearningMethodNames() { 666 List<String> methodToCalls = new ArrayList<String>(); 667 methodToCalls.add(KRADConstants.CLOSE_METHOD); 668 methodToCalls.add(KRADConstants.CANCEL_METHOD); 669 // methodToCalls.add(RiceConstants.BLANKET_APPROVE_METHOD); 670 methodToCalls.add(KRADConstants.ROUTE_METHOD); 671 methodToCalls.add(KRADConstants.APPROVE_METHOD); 672 methodToCalls.add(KRADConstants.DISAPPROVE_METHOD); 673 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 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.api.identity.Person) 691 */ 692 public String getCustomLockDescriptor(Person user) { 693 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 if ( attachmentService == null ) { 699 attachmentService = KRADServiceLocator.getAttachmentService(); 700 } 701 return attachmentService; 702 } 703 704 protected NoteService getNoteService() { 705 if ( noteService == null ) { 706 noteService = KRADServiceLocator.getNoteService(); 707 } 708 return noteService; 709 } 710 }