001 /**
002 * Copyright 2005-2013 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.datadictionary;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.rice.krad.datadictionary.exception.ClassValidationException;
020 import org.kuali.rice.krad.datadictionary.exception.DuplicateEntryException;
021 import org.kuali.rice.krad.document.Document;
022 import org.kuali.rice.krad.document.DocumentAuthorizer;
023 import org.kuali.rice.krad.document.DocumentAuthorizerBase;
024 import org.kuali.rice.krad.document.DocumentPresentationController;
025 import org.kuali.rice.krad.document.DocumentPresentationControllerBase;
026 import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
027 import org.kuali.rice.krad.rules.rule.BusinessRule;
028
029 import java.util.ArrayList;
030 import java.util.LinkedHashMap;
031 import java.util.List;
032 import java.util.Map;
033
034 /**
035 * A single Document entry in the DataDictionary, which contains information relating to the display, validation, and
036 * general maintenance of a Document (transactional or maintenance) and its attributes
037 *
038 * <p>
039 * Note: the setters do copious amounts of validation, to facilitate generating errors during the parsing process
040 * </p>
041 *
042 * @author Kuali Rice Team (rice.collab@kuali.org)
043 */
044 public abstract class DocumentEntry extends DataDictionaryEntryBase {
045 private static final long serialVersionUID = 8231730871830055356L;
046
047 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentEntry.class);
048
049 protected String documentTypeName;
050
051 protected Class<? extends Document> documentClass;
052 protected Class<? extends Document> baseDocumentClass;
053 protected Class<? extends BusinessRule> businessRulesClass;
054
055 protected boolean allowsNoteAttachments = true;
056 protected boolean allowsNoteFYI = false;
057 protected Class<? extends KeyValuesFinder> attachmentTypesValuesFinderClass;
058 protected boolean displayTopicFieldInNotes = false;
059 protected boolean usePessimisticLocking = false;
060 protected boolean useWorkflowPessimisticLocking = false;
061 protected boolean encryptDocumentDataInPersistentSessionStorage = false;
062
063 protected boolean allowsCopy = false;
064 protected WorkflowProperties workflowProperties;
065 protected WorkflowAttributes workflowAttributes;
066
067 protected Class<? extends DocumentAuthorizer> documentAuthorizerClass;
068 protected Class<? extends DocumentPresentationController> documentPresentationControllerClass;
069
070 protected List<ReferenceDefinition> defaultExistenceChecks = new ArrayList<ReferenceDefinition>();
071 protected Map<String, ReferenceDefinition> defaultExistenceCheckMap =
072 new LinkedHashMap<String, ReferenceDefinition>();
073
074 public DocumentEntry() {
075 super();
076
077 documentAuthorizerClass = DocumentAuthorizerBase.class;
078 documentPresentationControllerClass = DocumentPresentationControllerBase.class;
079 }
080
081 /**
082 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#getJstlKey()
083 */
084 public String getJstlKey() {
085 return documentTypeName;
086 }
087
088 /**
089 * The documentClass element is the name of the java class
090 * associated with the document.
091 */
092 public void setDocumentClass(Class<? extends Document> documentClass) {
093 if (documentClass == null) {
094 throw new IllegalArgumentException("invalid (null) documentClass");
095 }
096
097 this.documentClass = documentClass;
098 }
099
100 public Class<? extends Document> getDocumentClass() {
101 return documentClass;
102 }
103
104 /**
105 * The optional baseDocumentClass element is the name of the java base class
106 * associated with the document. This gives the data dictionary the ability
107 * to index by the base class in addition to the current class.
108 */
109 public void setBaseDocumentClass(Class<? extends Document> baseDocumentClass) {
110 this.baseDocumentClass = baseDocumentClass;
111 }
112
113 public Class<? extends Document> getBaseDocumentClass() {
114 return baseDocumentClass;
115 }
116
117 /**
118 * The businessRulesClass element is the full class name of the java
119 * class which contains the business rules for a document.
120 */
121 public void setBusinessRulesClass(Class<? extends BusinessRule> businessRulesClass) {
122 this.businessRulesClass = businessRulesClass;
123 }
124
125 public Class<? extends BusinessRule> getBusinessRulesClass() {
126 return businessRulesClass;
127 }
128
129 /**
130 * The documentTypeName element is the name of the document
131 * as defined in the workflow system.
132 * Example: "AddressTypeMaintenanceDocument"
133 */
134 public void setDocumentTypeName(String documentTypeName) {
135 if (StringUtils.isBlank(documentTypeName)) {
136 throw new IllegalArgumentException("invalid (blank) documentTypeName");
137 }
138 this.documentTypeName = documentTypeName;
139 }
140
141 public String getDocumentTypeName() {
142 return this.documentTypeName;
143 }
144
145 /**
146 * Validate common fields for subclass' benefit.
147 *
148 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#completeValidation()
149 */
150 public void completeValidation() {
151 super.completeValidation();
152
153 if (workflowProperties != null && workflowAttributes != null) {
154 throw new DataDictionaryException(documentTypeName +
155 ": workflowProperties and workflowAttributes cannot both be defined for a document");
156 }
157 }
158
159 /**
160 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#getFullClassName()
161 */
162 public String getFullClassName() {
163 if (getBaseDocumentClass() != null) {
164 return getBaseDocumentClass().getName();
165 }
166 if (getDocumentClass() != null) {
167 return getDocumentClass().getName();
168 }
169 return "";
170 }
171
172 /**
173 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase#getEntryClass()
174 */
175 public Class getEntryClass() {
176 return getDocumentClass();
177 }
178
179 public String toString() {
180 return "DocumentEntry for documentType " + documentTypeName;
181 }
182
183 /**
184 * Accessor method for contained displayTopicFieldInNotes
185 *
186 * @return displayTopicFieldInNotes boolean
187 */
188 public boolean getDisplayTopicFieldInNotes() {
189 return displayTopicFieldInNotes;
190 }
191
192 /**
193 * This field contains a value of true or false.
194 * If true, then the "Notes and Attachments" tab will render a column for a note topic.
195 */
196 public void setDisplayTopicFieldInNotes(boolean displayTopicFieldInNotes) {
197 this.displayTopicFieldInNotes = displayTopicFieldInNotes;
198 }
199
200 /**
201 * Accessor method for contained usePessimisticLocking
202 *
203 * @return usePessimisticLocking boolean
204 */
205 public boolean getUsePessimisticLocking() {
206 return this.usePessimisticLocking;
207 }
208
209 /**
210 * @param usePessimisticLocking
211 */
212 public void setUsePessimisticLocking(boolean usePessimisticLocking) {
213 if (LOG.isDebugEnabled()) {
214 LOG.debug("calling setUsePessimisticLocking '" + usePessimisticLocking + "'");
215 }
216
217 this.usePessimisticLocking = usePessimisticLocking;
218 }
219
220 /**
221 * Accessor method for contained useWorkflowPessimisticLocking
222 *
223 * @return useWorkflowPessimisticLocking boolean
224 */
225 public boolean getUseWorkflowPessimisticLocking() {
226 return this.useWorkflowPessimisticLocking;
227 }
228
229 /**
230 * @param useWorkflowPessimisticLocking
231 */
232 public void setUseWorkflowPessimisticLocking(boolean useWorkflowPessimisticLocking) {
233 if (LOG.isDebugEnabled()) {
234 LOG.debug("calling setuseWorkflowPessimisticLocking '" + useWorkflowPessimisticLocking + "'");
235 }
236
237 this.useWorkflowPessimisticLocking = useWorkflowPessimisticLocking;
238 }
239
240 /**
241 * The attachmentTypesValuesFinderClass specifies the name of a values finder
242 * class. This is used to determine the set of file types that are allowed
243 * to be attached to the document.
244 */
245 public void setAttachmentTypesValuesFinderClass(Class<? extends KeyValuesFinder> attachmentTypesValuesFinderClass) {
246 if (attachmentTypesValuesFinderClass == null) {
247 throw new IllegalArgumentException("invalid (null) attachmentTypesValuesFinderClass");
248 }
249
250 this.attachmentTypesValuesFinderClass = attachmentTypesValuesFinderClass;
251 }
252
253 /**
254 * @see org.kuali.rice.krad.datadictionary.control.ControlDefinition#getKeyValuesFinder()
255 */
256 public Class<? extends KeyValuesFinder> getAttachmentTypesValuesFinderClass() {
257 return attachmentTypesValuesFinderClass;
258 }
259
260 /**
261 * The allowsCopy element contains a true or false value.
262 * If true, then a user is allowed to make a copy of the
263 * record using the maintenance screen.
264 */
265 public void setAllowsCopy(boolean allowsCopy) {
266 this.allowsCopy = allowsCopy;
267 }
268
269 public boolean getAllowsCopy() {
270 return allowsCopy;
271 }
272
273 /**
274 * @return the allowsNoteAttachments
275 */
276 public boolean getAllowsNoteAttachments() {
277 return this.allowsNoteAttachments;
278 }
279
280 /**
281 * The allowsNoteAttachments element contains a true or false value.
282 * If true, then a document screen includes notes with attachments. Otherwise,
283 * only notes is displayed.
284 */
285 public void setAllowsNoteAttachments(boolean allowsNoteAttachments) {
286 this.allowsNoteAttachments = allowsNoteAttachments;
287 }
288
289 /**
290 * @return the allowsNoteFYI
291 */
292 public boolean getAllowsNoteFYI() {
293 return allowsNoteFYI;
294 }
295
296 /**
297 * This is an indicator for determining whether to render the AdHoc FYI recipient box and Send FYI button.
298 */
299 public void setAllowsNoteFYI(boolean allowsNoteFYI) {
300 this.allowsNoteFYI = allowsNoteFYI;
301 }
302
303 public WorkflowProperties getWorkflowProperties() {
304 return this.workflowProperties;
305 }
306
307 /**
308 * This element is used to define a set of workflowPropertyGroups, which are used to
309 * specify which document properties should be serialized during the document serialization
310 * process.
311 */
312 public void setWorkflowProperties(WorkflowProperties workflowProperties) {
313 this.workflowProperties = workflowProperties;
314 }
315
316 public WorkflowAttributes getWorkflowAttributes() {
317 return this.workflowAttributes;
318 }
319
320 public void setWorkflowAttributes(WorkflowAttributes workflowAttributes) {
321 this.workflowAttributes = workflowAttributes;
322 }
323
324 /**
325 * Full class name for the {@link DocumentAuthorizer} that will authorize actions for this document
326 *
327 * @return class name for document authorizer
328 */
329 public Class<? extends DocumentAuthorizer> getDocumentAuthorizerClass() {
330 return documentAuthorizerClass;
331 }
332
333 /**
334 * Setter for the document authorizer class name
335 *
336 * @param documentAuthorizerClass
337 */
338 public void setDocumentAuthorizerClass(Class<? extends DocumentAuthorizer> documentAuthorizerClass) {
339 this.documentAuthorizerClass = documentAuthorizerClass;
340 }
341
342 /**
343 * Full class name for the {@link DocumentPresentationController} that will be invoked to implement presentation
344 * logic for the document
345 *
346 * @return class name for document presentation controller
347 */
348 public Class<? extends DocumentPresentationController> getDocumentPresentationControllerClass() {
349 return documentPresentationControllerClass;
350 }
351
352 /**
353 * Setter for the document presentation controller class name
354 *
355 * @param documentPresentationControllerClass
356 */
357 public void setDocumentPresentationControllerClass(
358 Class<? extends DocumentPresentationController> documentPresentationControllerClass) {
359 this.documentPresentationControllerClass = documentPresentationControllerClass;
360 }
361
362 /**
363 * @return List of all defaultExistenceCheck ReferenceDefinitions associated with this MaintenanceDocument, in the
364 * order in
365 * which they were added
366 */
367 public List<ReferenceDefinition> getDefaultExistenceChecks() {
368 return defaultExistenceChecks;
369 }
370
371 /*
372 The defaultExistenceChecks element contains a list of
373 reference object names which are required to exist when maintaining a BO.
374 Optionally, the reference objects can be required to be active.
375
376 JSTL: defaultExistenceChecks is a Map of Reference elements,
377 whose entries are keyed by attributeName
378 */
379 public void setDefaultExistenceChecks(List<ReferenceDefinition> defaultExistenceChecks) {
380 this.defaultExistenceChecks = defaultExistenceChecks;
381 }
382
383 /**
384 * @return List of all defaultExistenceCheck reference fieldNames associated with this MaintenanceDocument, in the
385 * order in
386 * which they were added
387 */
388 public List<String> getDefaultExistenceCheckFieldNames() {
389 List<String> fieldNames = new ArrayList<String>();
390 fieldNames.addAll(this.defaultExistenceCheckMap.keySet());
391
392 return fieldNames;
393 }
394
395 public boolean isEncryptDocumentDataInPersistentSessionStorage() {
396 return this.encryptDocumentDataInPersistentSessionStorage;
397 }
398
399 public void setEncryptDocumentDataInPersistentSessionStorage(
400 boolean encryptDocumentDataInPersistentSessionStorage) {
401 this.encryptDocumentDataInPersistentSessionStorage = encryptDocumentDataInPersistentSessionStorage;
402 }
403
404 /**
405 * This overridden method ...
406 *
407 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase#afterPropertiesSet()
408 */
409 @Override
410 public void afterPropertiesSet() throws Exception {
411 super.afterPropertiesSet();
412 if (defaultExistenceChecks != null) {
413 defaultExistenceCheckMap.clear();
414 for (ReferenceDefinition reference : defaultExistenceChecks) {
415 if (reference == null) {
416 throw new IllegalArgumentException("invalid (null) defaultExistenceCheck");
417 }
418
419 String keyName = reference.isCollectionReference() ?
420 (reference.getCollection() + "." + reference.getAttributeName()) : reference.getAttributeName();
421 if (defaultExistenceCheckMap.containsKey(keyName)) {
422 throw new DuplicateEntryException(
423 "duplicate defaultExistenceCheck entry for attribute '" + keyName + "'");
424 }
425 reference.setBusinessObjectClass(getEntryClass());
426 defaultExistenceCheckMap.put(keyName, reference);
427 }
428 }
429 }
430 }