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 }