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