View Javadoc

1   /**
2    * Copyright 2005-2012 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.datadictionary;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.datadictionary.exception.DuplicateEntryException;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
22  import org.kuali.rice.krad.document.Document;
23  import org.kuali.rice.krad.document.DocumentAuthorizer;
24  import org.kuali.rice.krad.document.DocumentAuthorizerBase;
25  import org.kuali.rice.krad.document.DocumentPresentationController;
26  import org.kuali.rice.krad.document.DocumentPresentationControllerBase;
27  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
28  import org.kuali.rice.krad.rules.rule.BusinessRule;
29  
30  import java.util.ArrayList;
31  import java.util.LinkedHashMap;
32  import java.util.List;
33  import java.util.Map;
34  
35  /**
36   * A single Document entry in the DataDictionary, which contains information relating to the display, validation, and
37   * general maintenance of a Document (transactional or maintenance) and its attributes
38   *
39   * <p>
40   * The setters do validation to facilitate generating errors during the parsing process.
41   * </p>
42   *
43   * @author Kuali Rice Team (rice.collab@kuali.org)
44   */
45  public abstract class DocumentEntry extends DataDictionaryEntryBase {
46      private static final long serialVersionUID = 8231730871830055356L;
47  
48      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentEntry.class);
49  
50      protected String documentTypeName;
51  
52      protected Class<? extends Document> documentClass;
53      protected Class<? extends Document> baseDocumentClass;
54      protected Class<? extends BusinessRule> businessRulesClass;
55  
56      protected boolean allowsNoteAttachments = true;
57      protected boolean allowsNoteFYI = false;
58      protected Class<? extends KeyValuesFinder> attachmentTypesValuesFinderClass;
59      protected boolean displayTopicFieldInNotes = false;
60      protected boolean usePessimisticLocking = false;
61      protected boolean useWorkflowPessimisticLocking = false;
62      protected boolean encryptDocumentDataInPersistentSessionStorage = false;
63  
64      protected boolean allowsCopy = false;
65      protected WorkflowProperties workflowProperties;
66      protected WorkflowAttributes workflowAttributes;
67  
68      protected Class<? extends DocumentAuthorizer> documentAuthorizerClass;
69      protected Class<? extends DocumentPresentationController> documentPresentationControllerClass;
70  
71      protected List<ReferenceDefinition> defaultExistenceChecks = new ArrayList<ReferenceDefinition>();
72      protected Map<String, ReferenceDefinition> defaultExistenceCheckMap =
73              new LinkedHashMap<String, ReferenceDefinition>();
74  
75      public DocumentEntry() {
76          super();
77  
78          documentAuthorizerClass = DocumentAuthorizerBase.class;
79          documentPresentationControllerClass = DocumentPresentationControllerBase.class;
80      }
81  
82      /**
83       * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#getJstlKey()
84       */
85      public String getJstlKey() {
86          return documentTypeName;
87      }
88  
89      /**
90       * Setter for document class associated with the document
91       *
92       * @param documentClass - the document class associated with the document
93       */
94      public void setDocumentClass(Class<? extends Document> documentClass) {
95          if (documentClass == null) {
96              throw new IllegalArgumentException("invalid (null) documentClass");
97          }
98  
99          this.documentClass = documentClass;
100     }
101 
102     /**
103      * The {@link Document} subclass associated with the document
104      *
105      * @return Class<? extends Document>
106      */
107     @BeanTagAttribute(name = "documentClass")
108     public Class<? extends Document> getDocumentClass() {
109         return documentClass;
110     }
111 
112     /**
113      * The optional baseDocumentClass element is the name of the java base class
114      * associated with the document. This gives the data dictionary the ability
115      * to index by the base class in addition to the current class.
116      *
117      * @param baseDocumentClass - the superclass associated with the document
118      */
119     public void setBaseDocumentClass(Class<? extends Document> baseDocumentClass) {
120         this.baseDocumentClass = baseDocumentClass;
121     }
122 
123     /**
124      * The optional {@link Document} superclass associated with the document
125      *
126      * <p>
127      * This gives the data dictionary the ability to index by the superclass in addition to the current class.
128      * </p>
129      *
130      * @return Class<? extends Document>
131      */
132     @BeanTagAttribute(name = "getBaseDocumentClass")
133     public Class<? extends Document> getBaseDocumentClass() {
134         return baseDocumentClass;
135     }
136 
137     /**
138      * Setter for the {@link BusinessRule} to execute rules for the document
139      */
140     public void setBusinessRulesClass(Class<? extends BusinessRule> businessRulesClass) {
141         this.businessRulesClass = businessRulesClass;
142     }
143 
144     /**
145      * The {@link BusinessRule} that will be used to execute business rules for the document
146      *
147      * @return BusinessRule
148      */
149     @BeanTagAttribute(name = "businessRulesClass")
150     public Class<? extends BusinessRule> getBusinessRulesClass() {
151         return businessRulesClass;
152     }
153 
154     /**
155      * Setter for the name of the document as defined in the workflow system
156      *
157      * @param documentTypeName - name of the document in workflow
158      */
159     public void setDocumentTypeName(String documentTypeName) {
160         if (StringUtils.isBlank(documentTypeName)) {
161             throw new IllegalArgumentException("invalid (blank) documentTypeName");
162         }
163         this.documentTypeName = documentTypeName;
164     }
165 
166     /**
167      * The name of the document in the workflow system
168      *
169      * @return String
170      */
171     @BeanTagAttribute(name = "documentTypeName")
172     public String getDocumentTypeName() {
173         return this.documentTypeName;
174     }
175 
176     /**
177      * Directly validate simple fields
178      *
179      * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#completeValidation(org.kuali.rice.krad.datadictionary.validator.ValidationTrace)
180      */
181     public void completeValidation() {
182         super.completeValidation();
183 
184         if (workflowProperties != null && workflowAttributes != null) {
185             throw new DataDictionaryException(documentTypeName
186                     + ": workflowProperties and workflowAttributes cannot both be defined for a document");
187         }
188     }
189 
190     @Override
191     public void completeValidation(ValidationTrace tracer) {
192         tracer.addBean(this.getClass().getSimpleName(), getDocumentTypeName());
193 
194         if (workflowProperties != null && workflowAttributes != null) {
195             String currentValues[] = {"workflowProperties = " + getWorkflowProperties(),
196                     "workflowAttributes = " + getWorkflowAttributes()};
197             tracer.createError("WorkflowProperties and workflowAttributes cannot both be defined for a document",
198                     currentValues);
199         }
200 
201         super.completeValidation(tracer.getCopy());
202     }
203 
204     /**
205      * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#getFullClassName()
206      */
207     public String getFullClassName() {
208         if (getBaseDocumentClass() != null) {
209             return getBaseDocumentClass().getName();
210         }
211         if (getDocumentClass() != null) {
212             return getDocumentClass().getName();
213         }
214         return "";
215     }
216 
217     /**
218      * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase#getEntryClass()
219      */
220     public Class getEntryClass() {
221         return getDocumentClass();
222     }
223 
224     @Override
225     public String toString() {
226         return "DocumentEntry for documentType " + documentTypeName;
227     }
228 
229     /**
230      * Indicates whether the "Notes and Attachments" tab will render a column for a note topic
231      *
232      * @return boolean
233      */
234     @BeanTagAttribute(name = "displayTopicFieldInNotes")
235     public boolean getDisplayTopicFieldInNotes() {
236         return displayTopicFieldInNotes;
237     }
238 
239     /**
240      * Setter for the flag indicating whether the note topic field will be rendered in the notes tab
241      *
242      * @param displayTopicFieldInNotes
243      */
244     public void setDisplayTopicFieldInNotes(boolean displayTopicFieldInNotes) {
245         this.displayTopicFieldInNotes = displayTopicFieldInNotes;
246     }
247 
248     /**
249      * Accessor method for contained usePessimisticLocking
250      *
251      * @return usePessimisticLocking boolean
252      */
253     @BeanTagAttribute(name = "usePessimisticLocking")
254     public boolean getUsePessimisticLocking() {
255         return this.usePessimisticLocking;
256     }
257 
258     /**
259      * @param usePessimisticLocking
260      */
261     public void setUsePessimisticLocking(boolean usePessimisticLocking) {
262         if (LOG.isDebugEnabled()) {
263             LOG.debug("calling setUsePessimisticLocking '" + usePessimisticLocking + "'");
264         }
265 
266         this.usePessimisticLocking = usePessimisticLocking;
267     }
268 
269     /**
270      * Accessor method for contained useWorkflowPessimisticLocking
271      *
272      * @return useWorkflowPessimisticLocking boolean
273      */
274     @BeanTagAttribute(name = "useWorkflowPessimisticLocking")
275     public boolean getUseWorkflowPessimisticLocking() {
276         return this.useWorkflowPessimisticLocking;
277     }
278 
279     /**
280      * @param useWorkflowPessimisticLocking
281      */
282     public void setUseWorkflowPessimisticLocking(boolean useWorkflowPessimisticLocking) {
283         if (LOG.isDebugEnabled()) {
284             LOG.debug("calling setuseWorkflowPessimisticLocking '" + useWorkflowPessimisticLocking + "'");
285         }
286 
287         this.useWorkflowPessimisticLocking = useWorkflowPessimisticLocking;
288     }
289 
290     /**
291      * The attachmentTypesValuesFinderClass specifies the name of a values finder
292      * class. This is used to determine the set of file types that are allowed
293      * to be attached to the document.
294      */
295     public void setAttachmentTypesValuesFinderClass(Class<? extends KeyValuesFinder> attachmentTypesValuesFinderClass) {
296         if (attachmentTypesValuesFinderClass == null) {
297             throw new IllegalArgumentException("invalid (null) attachmentTypesValuesFinderClass");
298         }
299 
300         this.attachmentTypesValuesFinderClass = attachmentTypesValuesFinderClass;
301     }
302 
303     /**
304      * @see org.kuali.rice.krad.datadictionary.control.ControlDefinition#getValuesFinderClass()
305      */
306     @BeanTagAttribute(name = "attachmentTypesValuesFinderClass")
307     public Class<? extends KeyValuesFinder> getAttachmentTypesValuesFinderClass() {
308         return attachmentTypesValuesFinderClass;
309     }
310 
311     /**
312      * The allowsCopy element contains a true or false value.
313      * If true, then a user is allowed to make a copy of the
314      * record using the maintenance screen.
315      */
316     public void setAllowsCopy(boolean allowsCopy) {
317         this.allowsCopy = allowsCopy;
318     }
319 
320     @BeanTagAttribute(name = "allowsCopy")
321     public boolean getAllowsCopy() {
322         return allowsCopy;
323     }
324 
325     /**
326      * Indicates that a document screen allows notes with attachments
327      *
328      * <p>
329      * The add attachments section on notes will not be rendered when this is set to false.
330      * </p>
331      *
332      * @return boolean
333      */
334     @BeanTagAttribute(name = "allowsNoteAttachments")
335     public boolean getAllowsNoteAttachments() {
336         return this.allowsNoteAttachments;
337     }
338 
339     /**
340      * Setter for flag indicating that attacments can be added to notes
341      *
342      * @param allowsNoteAttachments
343      */
344     public void setAllowsNoteAttachments(boolean allowsNoteAttachments) {
345         this.allowsNoteAttachments = allowsNoteAttachments;
346     }
347 
348     /**
349      * Indicates whether to render the AdHoc FYI recipient box and Send FYI button
350      *
351      * @return boolean
352      */
353     @BeanTagAttribute(name = "allowsNoteFYI")
354     public boolean getAllowsNoteFYI() {
355         return allowsNoteFYI;
356     }
357 
358     /**
359      * Setter for the flag indicating whether to render the AdHoc FYI recipient box and Send FYI button
360      *
361      * @param allowsNoteFYI
362      */
363     public void setAllowsNoteFYI(boolean allowsNoteFYI) {
364         this.allowsNoteFYI = allowsNoteFYI;
365     }
366 
367     @BeanTagAttribute(name = "workflowProperties", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
368     public WorkflowProperties getWorkflowProperties() {
369         return this.workflowProperties;
370     }
371 
372     /**
373      * This element is used to define a set of workflowPropertyGroups, which are used to
374      * specify which document properties should be serialized during the document serialization
375      * process.
376      */
377     public void setWorkflowProperties(WorkflowProperties workflowProperties) {
378         this.workflowProperties = workflowProperties;
379     }
380 
381     @BeanTagAttribute(name = "workflowAttributes", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
382     public WorkflowAttributes getWorkflowAttributes() {
383         return this.workflowAttributes;
384     }
385 
386     public void setWorkflowAttributes(WorkflowAttributes workflowAttributes) {
387         this.workflowAttributes = workflowAttributes;
388     }
389 
390     /**
391      * Full class name for the {@link DocumentAuthorizer} that will authorize actions for this document
392      *
393      * @return class name for document authorizer
394      */
395     @BeanTagAttribute(name = "documentAuthorizerClass")
396     public Class<? extends DocumentAuthorizer> getDocumentAuthorizerClass() {
397         return documentAuthorizerClass;
398     }
399 
400     /**
401      * Setter for the document authorizer class name
402      *
403      * @param documentAuthorizerClass
404      */
405     public void setDocumentAuthorizerClass(Class<? extends DocumentAuthorizer> documentAuthorizerClass) {
406         this.documentAuthorizerClass = documentAuthorizerClass;
407     }
408 
409     /**
410      * Full class name for the {@link DocumentPresentationController} that will be invoked to implement presentation
411      * logic for the document
412      *
413      * @return class name for document presentation controller
414      */
415     @BeanTagAttribute(name = "documentPresentationControllerClass")
416     public Class<? extends DocumentPresentationController> getDocumentPresentationControllerClass() {
417         return documentPresentationControllerClass;
418     }
419 
420     /**
421      * Setter for the document presentation controller class name
422      *
423      * @param documentPresentationControllerClass
424      */
425     public void setDocumentPresentationControllerClass(
426             Class<? extends DocumentPresentationController> documentPresentationControllerClass) {
427         this.documentPresentationControllerClass = documentPresentationControllerClass;
428     }
429 
430     /**
431      * The defaultExistenceChecks element contains a list of reference object names which are required to exist when
432      * maintaining a BO
433      *
434      * <p>
435      * Optionally, the reference objects can be required to be active. The list keeps the order in which they were
436      * added. JSTL: defaultExistenceChecks is a Map of Reference elements, whose entries are keyed by attributeName.
437      * </p>
438      *
439      * @return
440      */
441     @BeanTagAttribute(name = "defaultExistenceChecks", type = BeanTagAttribute.AttributeType.LISTBEAN)
442     public List<ReferenceDefinition> getDefaultExistenceChecks() {
443         return defaultExistenceChecks;
444     }
445 
446     /**
447      * Setter for the list of all defaultExistenceCheck {@link ReferenceDefinition} associated with this
448      * {@link org.kuali.rice.krad.maintenance.MaintenanceDocument}
449      *
450      * @param defaultExistenceChecks
451      */
452     public void setDefaultExistenceChecks(List<ReferenceDefinition> defaultExistenceChecks) {
453         this.defaultExistenceChecks = defaultExistenceChecks;
454     }
455 
456     /**
457      * The {@code List} of all defaultExistenceCheck reference fieldNames associated with this MaintenanceDocument
458      *
459      * <p>
460      * The List keeps the order the items were added in.
461      * </p>
462      *
463      * @return List
464      */
465     public List<String> getDefaultExistenceCheckFieldNames() {
466         List<String> fieldNames = new ArrayList<String>();
467         fieldNames.addAll(this.defaultExistenceCheckMap.keySet());
468 
469         return fieldNames;
470     }
471 
472     /**
473      * Indicates that the document data should be encrypted when persisted
474      *
475      * @return boolean
476      */
477     @BeanTagAttribute(name = "encryptDocumentDataInPersistentSessionStorage")
478     public boolean isEncryptDocumentDataInPersistentSessionStorage() {
479         return this.encryptDocumentDataInPersistentSessionStorage;
480     }
481 
482     /**
483      * Setter for flag indicating that the document data should be encrypted when persisted
484      *
485      * @param encryptDocumentDataInPersistentSessionStorage
486      */
487     public void setEncryptDocumentDataInPersistentSessionStorage(
488             boolean encryptDocumentDataInPersistentSessionStorage) {
489         this.encryptDocumentDataInPersistentSessionStorage = encryptDocumentDataInPersistentSessionStorage;
490     }
491 
492     /**
493      * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase#afterPropertiesSet()
494      */
495     @Override
496     public void afterPropertiesSet() throws Exception {
497         super.afterPropertiesSet();
498         if (defaultExistenceChecks != null) {
499             defaultExistenceCheckMap.clear();
500             for (ReferenceDefinition reference : defaultExistenceChecks) {
501                 if (reference == null) {
502                     throw new IllegalArgumentException("invalid (null) defaultExistenceCheck");
503                 }
504 
505                 String keyName = reference.isCollectionReference() ?
506                         (reference.getCollection() + "." + reference.getAttributeName()) : reference.getAttributeName();
507                 if (defaultExistenceCheckMap.containsKey(keyName)) {
508                     throw new DuplicateEntryException(
509                             "duplicate defaultExistenceCheck entry for attribute '" + keyName + "'");
510                 }
511                 reference.setBusinessObjectClass(getEntryClass());
512                 defaultExistenceCheckMap.put(keyName, reference);
513             }
514         }
515     }
516 }