001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.krad.datadictionary; 017 018import java.util.ArrayList; 019import java.util.LinkedHashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.commons.lang.StringUtils; 024import org.kuali.rice.krad.datadictionary.exception.DuplicateEntryException; 025import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 026import org.kuali.rice.krad.datadictionary.validator.ValidationTrace; 027import org.kuali.rice.krad.document.Document; 028import org.kuali.rice.krad.document.DocumentAuthorizer; 029import org.kuali.rice.krad.document.DocumentAuthorizerBase; 030import org.kuali.rice.krad.document.DocumentPresentationController; 031import org.kuali.rice.krad.document.DocumentPresentationControllerBase; 032import org.kuali.rice.krad.keyvalues.KeyValuesFinder; 033import org.kuali.rice.krad.rules.rule.BusinessRule; 034 035/** 036 * A single Document entry in the DataDictionary, which contains information relating to the display, validation, and 037 * general maintenance of a Document (transactional or maintenance) and its attributes 038 * 039 * <p> 040 * The setters do validation to facilitate generating errors during the parsing process. 041 * </p> 042 * 043 * @author Kuali Rice Team (rice.collab@kuali.org) 044 */ 045public abstract class DocumentEntry extends DataDictionaryEntryBase { 046 private static final long serialVersionUID = 8231730871830055356L; 047 048 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentEntry.class); 049 050 protected String documentTypeName; 051 052 protected Class<? extends Document> documentClass; 053 protected Class<? extends Document> baseDocumentClass; 054 protected Class<? extends BusinessRule> businessRulesClass; 055 056 protected boolean allowsNoteAttachments = true; 057 protected boolean allowsNoteFYI = false; 058 protected Class<? extends KeyValuesFinder> attachmentTypesValuesFinderClass; 059 protected boolean displayTopicFieldInNotes = false; 060 protected boolean usePessimisticLocking = false; 061 protected boolean useWorkflowPessimisticLocking = false; 062 protected boolean encryptDocumentDataInPersistentSessionStorage = false; 063 064 protected boolean allowsCopy = false; 065 protected WorkflowProperties workflowProperties; 066 protected WorkflowAttributes workflowAttributes; 067 068 protected Class<? extends DocumentAuthorizer> documentAuthorizerClass; 069 protected Class<? extends DocumentPresentationController> documentPresentationControllerClass; 070 071 protected List<ReferenceDefinition> defaultExistenceChecks = new ArrayList<ReferenceDefinition>(); 072 protected Map<String, ReferenceDefinition> defaultExistenceCheckMap = 073 new LinkedHashMap<String, ReferenceDefinition>(); 074 075 public DocumentEntry() { 076 super(); 077 078 documentAuthorizerClass = DocumentAuthorizerBase.class; 079 documentPresentationControllerClass = DocumentPresentationControllerBase.class; 080 } 081 082 /** 083 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#getJstlKey() 084 */ 085 @Override 086 public String getJstlKey() { 087 return documentTypeName; 088 } 089 090 /** 091 * Setter for document class associated with the document 092 * 093 * @param documentClass - the document class associated with the document 094 */ 095 public void setDocumentClass(Class<? extends Document> documentClass) { 096 if (documentClass == null) { 097 throw new IllegalArgumentException("invalid (null) documentClass"); 098 } 099 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}