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 }