001/** 002 * Copyright 2005-2017 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.kew.doctype.bo; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.apache.commons.lang.StringUtils; 020import org.kuali.rice.core.api.config.CoreConfigHelper; 021import org.kuali.rice.core.api.config.property.ConfigContext; 022import org.kuali.rice.core.api.exception.RiceRemoteServiceConnectionException; 023import org.kuali.rice.core.api.mo.common.active.MutableInactivatable; 024import org.kuali.rice.core.api.reflect.ObjectDefinition; 025import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 026import org.kuali.rice.core.web.format.FormatException; 027import org.kuali.rice.kew.actionlist.CustomActionListAttribute; 028import org.kuali.rice.kew.api.KEWPropertyConstants; 029import org.kuali.rice.kew.api.KewApiConstants; 030import org.kuali.rice.kew.api.KewApiServiceLocator; 031import org.kuali.rice.kew.api.WorkflowRuntimeException; 032import org.kuali.rice.kew.api.doctype.DocumentTypeAttribute; 033import org.kuali.rice.kew.api.doctype.DocumentTypeAttributeContract; 034import org.kuali.rice.kew.api.doctype.DocumentTypeContract; 035import org.kuali.rice.kew.api.exception.ResourceUnavailableException; 036import org.kuali.rice.kew.api.extension.ExtensionDefinition; 037import org.kuali.rice.kew.api.extension.ExtensionUtils; 038import org.kuali.rice.kew.api.util.CodeTranslator; 039import org.kuali.rice.kew.doctype.*; 040import org.kuali.rice.kew.doctype.DocumentTypePolicy; 041import org.kuali.rice.kew.doctype.service.DocumentTypeService; 042import org.kuali.rice.kew.engine.node.ProcessDefinitionBo; 043import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute; 044import org.kuali.rice.kew.framework.postprocessor.PostProcessor; 045import org.kuali.rice.kew.mail.CustomEmailAttribute; 046import org.kuali.rice.kew.notes.CustomNoteAttribute; 047import org.kuali.rice.kew.postprocessor.DefaultPostProcessor; 048import org.kuali.rice.kew.rule.bo.RuleAttribute; 049import org.kuali.rice.kew.service.KEWServiceLocator; 050import org.kuali.rice.kew.util.Utilities; 051import org.kuali.rice.kim.api.group.Group; 052import org.kuali.rice.kim.api.group.GroupService; 053import org.kuali.rice.kim.api.services.KimApiServiceLocator; 054import org.kuali.rice.krad.bo.PersistableBusinessObjectBase; 055import org.kuali.rice.krad.data.DataObjectWrapper; 056import org.kuali.rice.krad.data.KradDataServiceLocator; 057import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator; 058import org.kuali.rice.krad.data.jpa.converters.Boolean01Converter; 059import org.kuali.rice.krad.util.KRADUtils; 060 061import javax.persistence.*; 062import java.lang.reflect.InvocationTargetException; 063import java.util.*; 064 065import static org.kuali.rice.kew.api.doctype.DocumentTypePolicy.*; 066 067/** 068 * Model bean mapped to ojb representing a document type. Provides component lookup behavior that 069 * can construct {@link ObjectDefinition} objects correctly to account for application id inheritance. 070 * Can also navigate parent hierarchy when getting data/components. 071 * 072 * @author Kuali Rice Team (rice.collab@kuali.org) 073 */ 074@Entity 075@Table(name = "KREW_DOC_TYP_T") 076@NamedQueries({ 077 @NamedQuery(name = "DocumentType.GetAppIdByDocumentId", query = "SELECT DT.actualApplicationId FROM DocumentType DT, " 078 + "DocumentRouteHeaderValue DH WHERE DH.documentTypeId=DT.documentTypeId AND DH.documentId = :documentId"), 079 @NamedQuery(name = "DocumentType.GetIdByName", query = "SELECT d.documentTypeId FROM DocumentType d WHERE "+ 080 "d.name = :docTypeName AND d.currentInd = true"), 081 @NamedQuery(name = "DocumentType.FindDocumentTypeNameById", query = "SELECT d.name FROM DocumentType d WHERE "+ 082 "d.documentTypeId = :documentTypeId AND d.currentInd = true"), 083 @NamedQuery(name = "DocumentType.GetMaxVersionNumber", query = "SELECT MAX(d.version) FROM DocumentType d WHERE "+ 084 "d.name = :docTypeName"), 085 @NamedQuery(name = "DocumentType.GetChildDocumentTypeIds", query = "SELECT d.documentTypeId FROM DocumentType d " 086 + "WHERE d.currentInd = true AND d.docTypeParentId = :parentDocumentTypeId"), 087 @NamedQuery(name = "DocumentType.GetDocumentTypeByDocumentId", query = "SELECT DT FROM DocumentType DT, " 088 + "DocumentRouteHeaderValue DH WHERE DH.documentTypeId=DT.documentTypeId AND DH.documentId = :documentId"), 089 @NamedQuery(name = "DocumentType.GetDocumentTypeByName", query = "SELECT d FROM DocumentType d " 090 + "WHERE d.currentInd = true AND d.name = :name"), 091 @NamedQuery(name = "DocumentType.QuickLinks.FindInitiatedDocumentTypesListByInitiatorWorkflowId", query = 092 "SELECT DISTINCT dt.name, dt.label FROM DocumentType dt, DocumentRouteHeaderValue drhv " + 093 "WHERE drhv.initiatorWorkflowId = :initiatorWorkflowId AND drhv.documentTypeId = dt.documentTypeId " 094 + "AND dt.active = true AND dt.currentInd = true " + 095 "ORDER BY UPPER(dt.label)"), 096 @NamedQuery(name = "DocumentType.parentNameByName", 097 query = "SELECT pdt.name FROM DocumentType dt, DocumentType pdt " + 098 "WHERE dt.docTypeParentId=pdt.documentTypeId AND dt.name = :docTypeName AND dt.currentInd = true") 099}) 100public class DocumentType extends PersistableBusinessObjectBase implements MutableInactivatable, DocumentTypeEBO, DocumentTypeContract { 101 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentType.class); 102 103 private static final long serialVersionUID = 1312830153583125069L; 104 105 @Id 106 @GeneratedValue(generator = "KREW_DOC_HDR_S") 107 @PortableSequenceGenerator(name = "KREW_DOC_HDR_S") 108 @Column(name = "DOC_TYP_ID", nullable = false) 109 private String documentTypeId; 110 111 @Column(name = "PARNT_ID") 112 private String docTypeParentId; 113 114 @Column(name = "DOC_TYP_NM") 115 private String name; 116 117 @Column(name = "DOC_TYP_VER_NBR") 118 private Integer version = new Integer(0); 119 120 @Column(name = "ACTV_IND") 121 @Convert(converter=Boolean01Converter.class) 122 private Boolean active; 123 124 @Column(name = "CUR_IND") 125 @Convert(converter=Boolean01Converter.class) 126 private Boolean currentInd; 127 128 @Column(name = "DOC_TYP_DESC") 129 private String description; 130 131 @Column(name = "LBL", nullable = false) 132 private String label; 133 134 @Column(name = "PREV_DOC_TYP_VER_NBR") 135 private String previousVersionId; 136 137 /** 138 * The id of the document which caused the last modification of this document type. 139 * Null if this doc type was never modified via a document routing (UI). 140 */ 141 @Column(name = "DOC_HDR_ID") 142 private String documentId; 143 144 @Column(name = "HELP_DEF_URL") 145 private String unresolvedHelpDefinitionUrl; 146 147 @Column(name = "DOC_SEARCH_HELP_URL") 148 private String unresolvedDocSearchHelpUrl; 149 150 @Column(name = "DOC_HDLR_URL") 151 private String unresolvedDocHandlerUrl; 152 153 @Column(name = "POST_PRCSR") 154 private String postProcessorName; 155 156 @Column(name = "GRP_ID") 157 private String workgroupId; 158 159 @Column(name = "BLNKT_APPR_GRP_ID") 160 private String blanketApproveWorkgroupId; 161 162 @Column(name = "BLNKT_APPR_PLCY") 163 private String blanketApprovePolicy; 164 165 @Column(name = "RPT_GRP_ID") 166 private String reportingWorkgroupId; 167 168 @Column(name = "APPL_ID") 169 private String actualApplicationId; 170 171 /** 172 * @since 2.1.3 173 */ 174 @Column(name = "AUTHORIZER") 175 private String authorizer; 176 177 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "documentType") 178 private Collection<DocumentTypePolicy> documentTypePolicies; 179 180 /* This property contains the list of valid ApplicationDocumentStatus values, 181 * if defined, for the document type. If these status values are defined, only these 182 * values may be assigned as the status. If not valid values are defined, the status may 183 * be set to any value by the client. 184 */ 185 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 186 @JoinColumn(name = "DOC_TYP_ID") 187 private List<ApplicationDocumentStatus> validApplicationStatuses; 188 189 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 190 @JoinColumn(name = "DOC_TYP_ID") 191 private List<ApplicationDocumentStatusCategory> applicationStatusCategories; 192 193 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "documentType") 194 @OrderBy("orderIndex ASC") 195 private List<DocumentTypeAttributeBo> documentTypeAttributes; 196 197 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "documentType") 198 private List<ProcessDefinitionBo> processes = new ArrayList<ProcessDefinitionBo>(); 199 200 @Column(name = "RTE_VER_NBR") 201 private String routingVersion = KewApiConstants.CURRENT_ROUTING_VERSION; 202 203 @Column(name = "NOTIFY_ADDR") 204 private String actualNotificationFromAddress; 205 206 @Lob 207 @Basic(fetch = FetchType.LAZY) 208 @Column(name = "SEC_XML") 209 private String documentTypeSecurityXml; 210 211 /* XSLT-based email message customization */ 212 @Column(name = "EMAIL_XSL") 213 private String customEmailStylesheet; 214 215 216 /* these two fields are for the web tier lookupable 217 * DocumentType is doing double-duty as a web/business tier object 218 */ 219 @Transient private String returnUrl; 220 @Transient private String actionsUrl; 221 @Transient private Boolean applyRetroactively = Boolean.FALSE; 222 223 /* The default exception workgroup to apply to nodes that lack an exception workgroup definition. 224 * Used at parse-time only; not stored in db. 225 */ 226 @Transient private Group defaultExceptionWorkgroup; 227 @Transient private Collection<DocumentType> childrenDocTypes; 228 @Transient private DocumentTypeSecurity documentTypeSecurity; 229 230 public DocumentType() { 231 documentTypeAttributes = new ArrayList<DocumentTypeAttributeBo>(); 232 documentTypePolicies = new ArrayList<DocumentTypePolicy>(); 233 version = new Integer(0); 234 label = null; 235 } 236 237 public void populateDataDictionaryEditableFields(Set<String> propertyNamesEditableViaUI, DocumentType dataDictionaryEditedType) { 238 DataObjectWrapper<DocumentType> wrapper = KradDataServiceLocator.getDataObjectService().wrap(dataDictionaryEditedType); 239 240 String currentPropertyName = ""; 241 try { 242 for (String propertyName : propertyNamesEditableViaUI) { 243 currentPropertyName = propertyName; 244 if (KEWPropertyConstants.PARENT_DOC_TYPE_NAME.equals(propertyName)) { 245 // this is trying to set the parent document type name so lets set the entire parent document 246 String parentDocumentTypeName = (String) wrapper.getPropertyValueNullSafe(propertyName); 247 if (StringUtils.isNotBlank(parentDocumentTypeName)) { 248 DocumentType parentDocType = KEWServiceLocator.getDocumentTypeService().findByName(parentDocumentTypeName); 249 if (parentDocType == null) { 250 throw new WorkflowRuntimeException("Could not find valid document type for document type name '" + parentDocumentTypeName + "' to set as Parent Document Type"); 251 } 252 setDocTypeParentId(parentDocType.getDocumentTypeId()); 253 } 254 } 255// else if (!FIELD_PROPERTY_NAME_DOCUMENT_TYPE_ID.equals(propertyName)) { 256 else { 257 LOG.info("*** COPYING PROPERTY NAME FROM OLD BO TO NEW BO: " + propertyName); 258 KRADUtils.setObjectProperty(this, propertyName, wrapper.getPropertyValueNullSafe(propertyName)); 259 } 260 } 261 } catch (FormatException e) { 262 throw new WorkflowRuntimeException("Error setting property '" + currentPropertyName + "' in Document Type", e); 263 } catch (IllegalAccessException e) { 264 throw new WorkflowRuntimeException("Error setting property '" + currentPropertyName + "' in Document Type", e); 265 } catch (InvocationTargetException e) { 266 throw new WorkflowRuntimeException("Error setting property '" + currentPropertyName + "' in Document Type", e); 267 } catch (NoSuchMethodException e) { 268 throw new WorkflowRuntimeException("Error setting property '" + currentPropertyName + "' in Document Type", e); 269 } catch (Exception e) { 270 throw new WorkflowRuntimeException("Error setting property '" + currentPropertyName + "' in Document Type", e); 271 } 272 } 273 274 public DocumentTypePolicy getAllowUnrequestedActionPolicy() { 275 return getPolicyByName(ALLOW_UNREQUESTED_ACTION.getCode(), Boolean.TRUE); 276 } 277 278 public DocumentTypePolicy getDefaultApprovePolicy() { 279 return getPolicyByName(DEFAULT_APPROVE.getCode(), Boolean.TRUE); 280 } 281 282 public DocumentTypePolicy getUseWorkflowSuperUserDocHandlerUrl() { 283 return getPolicyByName(USE_KEW_SUPERUSER_DOCHANDLER.getCode(), Boolean.TRUE); 284 } 285 286 public DocumentTypePolicy getInitiatorMustRoutePolicy() { 287 return getPolicyByName(INITIATOR_MUST_ROUTE.getCode(), Boolean.TRUE); 288 } 289 290 public DocumentTypePolicy getInitiatorMustSavePolicy() { 291 return getPolicyByName(INITIATOR_MUST_SAVE.getCode(), Boolean.TRUE); 292 } 293 294 public DocumentTypePolicy getInitiatorMustCancelPolicy() { 295 return getPolicyByName(INITIATOR_MUST_CANCEL.getCode(), Boolean.TRUE); 296 } 297 298 public DocumentTypePolicy getInitiatorMustBlanketApprovePolicy() { 299 return getPolicyByName(INITIATOR_MUST_BLANKET_APPROVE.getCode(), Boolean.TRUE); 300 } 301 302 public DocumentTypePolicy getLookIntoFuturePolicy() { 303 return getPolicyByName(LOOK_FUTURE.getCode(), Boolean.FALSE); 304 } 305 306 public DocumentTypePolicy getSuperUserApproveNotificationPolicy() { 307 return getPolicyByName(SEND_NOTIFICATION_ON_SU_APPROVE.getCode(), Boolean.FALSE); 308 } 309 310 public DocumentTypePolicy getSupportsQuickInitiatePolicy() { 311 return getPolicyByName(SUPPORTS_QUICK_INITIATE.getCode(), Boolean.TRUE); 312 } 313 314 public DocumentTypePolicy getNotifyOnSavePolicy() { 315 return getPolicyByName(NOTIFY_ON_SAVE.getCode(), Boolean.FALSE); 316 } 317 318 /** 319 * This method returns a DocumentTypePolicy object related to the DocumentStatusPolicy defined for this document type. 320 */ 321 public DocumentTypePolicy getDocumentStatusPolicy() { 322 return getPolicyByName(DOCUMENT_STATUS_POLICY.getCode(), KewApiConstants.DOCUMENT_STATUS_POLICY_KEW_STATUS); 323 } 324 325 /** 326 * This method returns a DocumentTypePolicy object related to the DocumentStatusPolicy defined for this document type. 327 */ 328 public DocumentTypePolicy getSuPostprocessorOverridePolicy() { 329 return getPolicyByName(ALLOW_SU_POSTPROCESSOR_OVERRIDE.getCode(), Boolean.TRUE); 330 } 331 332 public DocumentTypePolicy getFailOnInactiveGroup() { 333 return getPolicyByName(FAIL_ON_INACTIVE_GROUP.getCode(), Boolean.TRUE); 334 } 335 336 public DocumentTypePolicy getEnrouteErrorSuppression() { 337 return getPolicyByName(ENROUTE_ERROR_SUPPRESSION.getCode(), Boolean.FALSE); 338 } 339 340 public DocumentTypePolicy getRegenerateActionRequestsOnChange() { 341 return getPolicyByName(REGENERATE_ACTION_REQUESTS_ON_CHANGE.getCode(), Boolean.TRUE); 342 } 343 344 /** 345 * Returns the RECALL_NOTIFICATION policy on the document if defined, or 346 * the default value for this policy which is true. 347 * @return the RECALL_NOTIFICATION document type policy 348 * @since 2.1 349 */ 350 public DocumentTypePolicy getRecallNotification() { 351 return getPolicyByName(RECALL_NOTIFICATION.getCode(), (String) null); 352 } 353 354 /** 355 * Returns the SUPPRESS_IMMEDIATE_EMAILS_ON_SU_ACTION policy on the document if defined, or 356 * the default value for this policy which is false. 357 * @return the SUPPRESS_IMMEDIATE_EMAILS_ON_SU_ACTION document type policy 358 * @since 2.1.3 359 */ 360 public DocumentTypePolicy getSuppressImmediateEmailsOnSuActionPolicy() { 361 return getPolicyByName(SUPPRESS_IMMEDIATE_EMAILS_ON_SU_ACTION.getCode(), Boolean.FALSE); 362 } 363 364 /** 365 * Returns the ALLOW_SU_FINAL_APPROVAL policy on the document if defined, or 366 * the default value for this policy which is true. 367 * @return the ALLOW_SU_FINAL_APPROVAL document type policy 368 * @since 2.1.3 369 */ 370 public DocumentTypePolicy getAllowSuperUserFinalApprovalPolicy() { 371 return getPolicyByName(ALLOW_SU_FINAL_APPROVAL.getCode(), Boolean.TRUE); 372 } 373 374 /** 375 * Returns the DOC_SEARCH_TARGET policy on the document if defined 376 * @return the DOC_SEARCH_TARGET document type policy 377 * @since 2.5.0 378 */ 379 public DocumentTypePolicy getDocSearchTarget() { 380 return getPolicyByName(DOC_SEARCH_TARGET.getCode(), (String) null); 381 } 382 383 /** 384 * This method returns a boolean denoting whether the KEW Route Status is to be displayed. 385 * The KEW Route Status is updated by the workflow engine regardless of whether it is to be displayed or not. 386 * 387 * @return true - if the status is to be displayed (Policy is set to either use KEW (default) or both) 388 * false - if the KEW Route Status is not to be displayed 389 */ 390 public Boolean isKEWStatusInUse() { 391 if (isPolicyDefined(DOCUMENT_STATUS_POLICY)) { 392 String policyValue = getPolicyByName(DOCUMENT_STATUS_POLICY.getCode(), KewApiConstants.DOCUMENT_STATUS_POLICY_KEW_STATUS).getPolicyStringValue(); 393 return (policyValue == null || "".equals(policyValue) 394 || KewApiConstants.DOCUMENT_STATUS_POLICY_KEW_STATUS.equalsIgnoreCase(policyValue) 395 || KewApiConstants.DOCUMENT_STATUS_POLICY_BOTH.equalsIgnoreCase(policyValue)) ? Boolean.TRUE : Boolean.FALSE; 396 } else { 397 return Boolean.TRUE; 398 } 399 } 400 401 /** 402 * This method returns a boolean denoting whether the Application Document Status is to be used for this document type. 403 * 404 * @return true - if the status is to be displayed (Policy is set to either use the application document status or both) 405 * false - if only the KEW Route Status is to be displayed (default) 406 */ 407 public Boolean isAppDocStatusInUse() { 408 if (isPolicyDefined(DOCUMENT_STATUS_POLICY)) { 409 String policyValue = getPolicyByName(DOCUMENT_STATUS_POLICY.getCode(), KewApiConstants.DOCUMENT_STATUS_POLICY_KEW_STATUS).getPolicyStringValue(); 410 return (KewApiConstants.DOCUMENT_STATUS_POLICY_APP_DOC_STATUS.equalsIgnoreCase(policyValue) 411 || KewApiConstants.DOCUMENT_STATUS_POLICY_BOTH.equalsIgnoreCase(policyValue)) ? Boolean.TRUE : Boolean.FALSE; 412 } else { 413 return Boolean.FALSE; 414 } 415 } 416 417 /** 418 * This method returns a boolean denoting if both the KEW Route Status and the Application Document Status 419 * are to be used in displays. 420 * 421 * @return true - if both the KEW Route Status and Application Document Status are to be displayed. 422 * false - if only one status is to be displayed. 423 */ 424 public Boolean areBothStatusesInUse() { 425 if (isPolicyDefined(DOCUMENT_STATUS_POLICY)) { 426 String policyValue = getPolicyByName(DOCUMENT_STATUS_POLICY.getCode(), KewApiConstants.DOCUMENT_STATUS_POLICY_KEW_STATUS).getPolicyStringValue(); 427 return (KewApiConstants.DOCUMENT_STATUS_POLICY_BOTH.equalsIgnoreCase(policyValue)) ? Boolean.TRUE : Boolean.FALSE; 428 } else { 429 return Boolean.FALSE; 430 } 431 } 432 433 public String getUseWorkflowSuperUserDocHandlerUrlValue() { 434 if (getUseWorkflowSuperUserDocHandlerUrl() != null) { 435 return getUseWorkflowSuperUserDocHandlerUrl().getPolicyDisplayValue(); 436 } 437 return null; 438 } 439 440 public String getAllowUnrequestedActionPolicyDisplayValue() { 441 if (getAllowUnrequestedActionPolicy() != null) { 442 return getAllowUnrequestedActionPolicy().getPolicyDisplayValue(); 443 } 444 return null; 445 } 446 447 public String getDefaultApprovePolicyDisplayValue() { 448 if (getDefaultApprovePolicy() != null) { 449 return getDefaultApprovePolicy().getPolicyDisplayValue(); 450 } 451 return null; 452 } 453 454 public String getInitiatorMustRouteDisplayValue() { 455 if (getInitiatorMustRoutePolicy() != null) { 456 return getInitiatorMustRoutePolicy().getPolicyDisplayValue(); 457 } 458 return null; 459 } 460 461 public String getInitiatorMustSaveDisplayValue() { 462 if (getInitiatorMustSavePolicy() != null) { 463 return getInitiatorMustSavePolicy().getPolicyDisplayValue(); 464 } 465 return null; 466 } 467 468 public boolean isPolicyDefined(org.kuali.rice.kew.api.doctype.DocumentTypePolicy policyToCheck) { 469 Iterator<DocumentTypePolicy> policyIter = getDocumentTypePolicies().iterator(); 470 while (policyIter.hasNext()) { 471 DocumentTypePolicy policy = policyIter.next(); 472 if (policyToCheck.getCode().equals(policy.getPolicyName())) { 473 return true; 474 } 475 } 476 return getParentDocType() != null && getParentDocType().isPolicyDefined(policyToCheck); 477 } 478 479 public List<DocumentTypeAttributeBo> getDocumentTypeAttributes(String... attributeTypes) { 480 List<DocumentTypeAttributeBo> filteredAttributes = new ArrayList<DocumentTypeAttributeBo>(); 481 if (CollectionUtils.isNotEmpty(documentTypeAttributes)) { 482 if (attributeTypes == null) { 483 filteredAttributes.addAll(documentTypeAttributes); 484 } else { 485 List<String> attributeTypeList = Arrays.asList(attributeTypes); 486 for (DocumentTypeAttributeBo documentTypeAttribute : documentTypeAttributes) { 487 RuleAttribute ruleAttribute = documentTypeAttribute.getRuleAttribute(); 488 if (attributeTypeList.contains(ruleAttribute.getType())) { 489 filteredAttributes.add(documentTypeAttribute); 490 } 491 } 492 } 493 } 494 if (filteredAttributes.isEmpty() && getParentDocType() != null) { 495 return getParentDocType().getDocumentTypeAttributes(attributeTypes); 496 } 497 return Collections.unmodifiableList(filteredAttributes); 498 } 499 500 public boolean hasSearchableAttributes() { 501 return !getSearchableAttributes().isEmpty(); 502 } 503 504 public List<DocumentTypeAttributeBo> getSearchableAttributes() { 505 return getDocumentTypeAttributes(KewApiConstants.SEARCHABLE_ATTRIBUTE_TYPE, KewApiConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE); 506 } 507 508 public DocumentTypeAttributeBo getCustomizerAttribute() { 509 List<DocumentTypeAttributeBo> documentTypeAttributes = getDocumentTypeAttributes(KewApiConstants.DOCUMENT_SEARCH_CUSTOMIZER_ATTRIBUTE_TYPE); 510 if (documentTypeAttributes.size() > 1) { 511 throw new IllegalStateException("Encountered more than one DocumentSearchCustomizer attribute on this document type: " + getName()); 512 } 513 if (documentTypeAttributes.isEmpty()) { 514 return null; 515 } 516 return documentTypeAttributes.get(0); 517 } 518 519 /** 520 * Returns the RuleAttribute for the action list attribute for this DocumentType. Walks the document type hierarchy 521 * if none exists directly on this DocumentType. 522 * @return The RuleAttribute. May be null. 523 */ 524 public RuleAttribute getCustomActionListRuleAttribute() { 525 List<DocumentTypeAttributeBo> documentTypeAttributes = getDocumentTypeAttributes(KewApiConstants.ACTION_LIST_ATTRIBUTE_TYPE); 526 if (documentTypeAttributes.size() > 1) { 527 throw new IllegalStateException("Encountered more than one ActionListAttribute on this document type: " + getName()); 528 } 529 if (documentTypeAttributes.isEmpty()) { 530 return null; 531 } 532 return documentTypeAttributes.get(0).getRuleAttribute(); 533 } 534 535 public List<ExtensionHolder<SearchableAttribute>> loadSearchableAttributes() { 536 List<DocumentTypeAttributeBo> searchableAttributes = getSearchableAttributes(); 537 List<ExtensionHolder<SearchableAttribute>> loadedAttributes = new ArrayList<ExtensionHolder<SearchableAttribute>>(); 538 for (DocumentTypeAttributeBo documentTypeAttribute : searchableAttributes) { 539 RuleAttribute ruleAttribute = documentTypeAttribute.getRuleAttribute(); 540 try { 541 ExtensionDefinition extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService().getExtensionById(ruleAttribute.getId()); 542 SearchableAttribute attributeService = ExtensionUtils.loadExtension(extensionDefinition, getApplicationId()); 543 loadedAttributes.add(new ExtensionHolder<SearchableAttribute>(extensionDefinition, attributeService)); 544 } catch (RiceRemoteServiceConnectionException e) { 545 LOG.warn("Unable to connect to load searchable attribute for " + ruleAttribute, e); 546 } 547 } 548 return loadedAttributes; 549 } 550 551 public static final class ExtensionHolder<T> { 552 553 //private final RuleAttribute ruleAttribute; 554 private final ExtensionDefinition extensionDefinition; 555 private final T extension; 556 557 public ExtensionHolder(ExtensionDefinition extensionDefinition, T extension) { 558 //this.ruleAttribute = ruleAttribute; 559 this.extensionDefinition = extensionDefinition; 560 this.extension = extension; 561 } 562 563 /*public RuleAttribute getRuleAttribute() { 564 return ruleAttribute; 565 }*/ 566 567 public ExtensionDefinition getExtensionDefinition() { 568 return extensionDefinition; 569 } 570 571 public T getExtension() { 572 return extension; 573 } 574 } 575 576 public DocumentTypeAttributeBo getDocumentTypeAttribute(int index) { 577 while (getDocumentTypeAttributes().size() <= index) { 578 DocumentTypeAttributeBo attribute = new DocumentTypeAttributeBo(); 579 //attribute.setDocumentTypeId(this.documentTypeId); 580 getDocumentTypeAttributes().add(attribute); 581 } 582 return (DocumentTypeAttributeBo) getDocumentTypeAttributes().get(index); 583 } 584 585 public void setDocumentTypeAttribute(int index, DocumentTypeAttributeBo documentTypeAttribute) { 586 documentTypeAttributes.set(index, documentTypeAttribute); 587 } 588 589 public String getDocTypeActiveIndicatorDisplayValue() { 590 if (getActive() == null) { 591 return KewApiConstants.INACTIVE_LABEL_LOWER; 592 } 593 return CodeTranslator.getActiveIndicatorLabel(getActive()); 594 } 595 596 public Collection<DocumentType> getChildrenDocTypes() { 597 if (this.childrenDocTypes == null) { 598 this.childrenDocTypes = KEWServiceLocator.getDocumentTypeService().getChildDocumentTypes(getDocumentTypeId()); 599 } 600 return childrenDocTypes; 601 } 602 603 public String getDocTypeParentId() { 604 return docTypeParentId; 605 } 606 607 public void setDocTypeParentId(String docTypeParentId) { 608 this.docTypeParentId = docTypeParentId; 609 } 610 611 public DocumentType getParentDocType() { 612 return KEWServiceLocator.getDocumentTypeService().findById(this.docTypeParentId); 613 } 614 615 public Collection<DocumentTypePolicy> getDocumentTypePolicies() { 616 return documentTypePolicies; 617 } 618 619 public void setDocumentTypePolicies(Collection<DocumentTypePolicy> policies) { 620 this.documentTypePolicies = policies; 621 } 622 623 @Override 624 public Map<org.kuali.rice.kew.api.doctype.DocumentTypePolicy, String> getPolicies() { 625 Map<org.kuali.rice.kew.api.doctype.DocumentTypePolicy, String> policies = new HashMap<org.kuali.rice.kew.api.doctype.DocumentTypePolicy, String>(); 626 if (this.documentTypePolicies != null) { 627 for (DocumentTypePolicy policy : this.documentTypePolicies) { 628 policies.put(fromCode(policy.getPolicyName()), policy.getActualPolicyValue()); 629 } 630 } 631 return policies; 632 } 633 634 public List<ApplicationDocumentStatus> getValidApplicationStatuses() { 635 if((this.validApplicationStatuses == null || this.validApplicationStatuses.isEmpty()) 636 && getParentDocType() != null && isAppDocStatusInUse()) { 637 return getParentDocType().getValidApplicationStatuses(); 638 } 639 return this.validApplicationStatuses; 640 } 641 642 public void setValidApplicationStatuses( 643 List<ApplicationDocumentStatus> validApplicationStatuses) { 644 this.validApplicationStatuses = validApplicationStatuses; 645 } 646 647 /** 648 * Get the application document status categories for this document type 649 * 650 * @see ApplicationDocumentStatusCategory 651 * @return the application document status categories for this document type 652 */ 653 public List<ApplicationDocumentStatusCategory> getApplicationStatusCategories() { 654 if((this.validApplicationStatuses == null || this.validApplicationStatuses.isEmpty()) 655 && KRADUtils.isNotNull(getParentDocType()) && isAppDocStatusInUse()) { 656 return getParentDocType().getApplicationStatusCategories(); 657 } 658 return applicationStatusCategories; 659 } 660 661 /** 662 * Set the application document status categories for this document type 663 * @param applicationStatusCategories 664 */ 665 public void setApplicationStatusCategories(List<ApplicationDocumentStatusCategory> applicationStatusCategories) { 666 this.applicationStatusCategories = applicationStatusCategories; 667 } 668 669 public String getDocumentTypeSecurityXml() { 670 return documentTypeSecurityXml; 671 } 672 673 public void setDocumentTypeSecurityXml(String documentTypeSecurityXml) { 674 this.documentTypeSecurityXml = documentTypeSecurityXml; 675 if (StringUtils.isNotBlank(documentTypeSecurityXml)) { 676 this.documentTypeSecurity = new DocumentTypeSecurity(this.getApplicationId(), documentTypeSecurityXml); 677 } else { 678 this.documentTypeSecurity = null; 679 } 680 } 681 682 public DocumentTypeSecurity getDocumentTypeSecurity() { 683 if (this.documentTypeSecurity == null && 684 this.documentTypeSecurityXml != null && 685 !org.apache.commons.lang.StringUtils.isEmpty(documentTypeSecurityXml.trim())) { 686 this.documentTypeSecurity = new DocumentTypeSecurity(this.getApplicationId(), documentTypeSecurityXml); 687 } 688 if ((this.documentTypeSecurity == null) && (getParentDocType() != null)) { 689 return getParentDocType().getDocumentTypeSecurity(); 690 } 691 return this.documentTypeSecurity; 692 } 693 694 public String getActionsUrl() { 695 return actionsUrl; 696 } 697 698 public void setActionsUrl(String actions) { 699 this.actionsUrl = actions; 700 } 701 702 public Boolean getActive() { 703 return active; 704 } 705 706 public void setActive(java.lang.Boolean activeInd) { 707 this.active = activeInd; 708 } 709 710 public java.lang.Boolean getCurrentInd() { 711 return currentInd; 712 } 713 714 @Override 715 public boolean isCurrent() { 716 if (currentInd == null) { 717 return true; 718 } 719 return currentInd.booleanValue(); 720 } 721 722 public void setCurrentInd(java.lang.Boolean currentInd) { 723 this.currentInd = currentInd; 724 } 725 726 public java.lang.String getDescription() { 727 return description; 728 } 729 730 public void setDescription(java.lang.String description) { 731 this.description = description; 732 } 733 734 /** 735 * This method retrieves the unresolved document handler URL from this object 736 */ 737 /*public String getDocHandlerUrl() { 738 return getUnresolvedDocHandlerUrl(); 739 }*/ 740 741 /** 742 * This method gets the document handler url from this object or from a parent document type and resolves any 743 * potential variables that may be in use 744 */ 745 @Override 746 public String getResolvedDocumentHandlerUrl() { 747 return resolveDocHandlerUrl(getUnresolvedInheritedDocHandlerUrl(false)); 748 } 749 750 /** 751 * This method retrieves the unresolved document handler URL either from this object or from a parent document type 752 * object. If the forDisplayPurposes value is true the value returned will be invalid for system use. 753 * <p/> 754 * This method will first call the {@link #getUnresolvedDocHandlerUrl()} method to check for a value on this object. 755 * If none is found a parent document type must exist because the document handler URL is required and is used. The 756 * system will use inheritance to find the document handler url from a document type somewhere in the hierarchy. 757 * 758 * @param forDisplayPurposes - if true then the string returned will have a label explaining where the value came from 759 * @return the unresolved document handler URL value or a displayable value with sourcing information 760 */ 761 protected String getUnresolvedInheritedDocHandlerUrl(boolean forDisplayPurposes) { 762 if (StringUtils.isNotBlank(getUnresolvedDocHandlerUrl())) { 763 // this object has a direct value set, so return it 764 return getUnresolvedDocHandlerUrl(); 765 } 766 // check for a parent document to see if the doc handler url can be inherited 767 DocumentType docType = getParentDocType(); 768 if (KRADUtils.isNotNull(docType)) { 769 String parentValue = docType.getUnresolvedDocHandlerUrl(); 770 if (StringUtils.isNotBlank(parentValue)) { 771 // found a parent value set on the immediate parent object so return it 772 if (forDisplayPurposes) { 773 parentValue += " " + KewApiConstants.DOCUMENT_TYPE_INHERITED_VALUE_INDICATOR; 774 } 775 return parentValue; 776 } 777 // no valid value exists on the immediate parent, so check the hierarchy 778 return docType.getUnresolvedInheritedDocHandlerUrl(forDisplayPurposes); 779 } 780 return null; 781 } 782 783 /** 784 * Returns the same value as the {@link #getUnresolvedInheritedDocHandlerUrl(boolean)} method but will also have label 785 * information about whether the value returned came from this object or the parent document type associated with this object 786 */ 787 public String getDisplayableUnresolvedDocHandlerUrl() { 788 return getUnresolvedInheritedDocHandlerUrl(true); 789 } 790 791 /** 792 * EMPTY METHOD. Use {@link #setUnresolvedDocHandlerUrl(String)} instead. 793 * 794 * @deprecated 795 */ 796 public void setDisplayableUnresolvedDocHandlerUrl(String displayableUnresolvedDocHandlerUrl) { 797 // do nothing 798 } 799 800 /** 801 * @return the unresolvedDocHandlerUrl 802 */ 803 @Override 804 public String getUnresolvedDocHandlerUrl() { 805 return this.unresolvedDocHandlerUrl; 806 } 807 808 /** 809 * @param unresolvedDocHandlerUrl the unresolvedDocHandlerUrl to set 810 */ 811 public void setUnresolvedDocHandlerUrl(String unresolvedDocHandlerUrl) { 812 this.unresolvedDocHandlerUrl = unresolvedDocHandlerUrl; 813 } 814 815 /** 816 * If the doc handler URL has variables in it that need to be replaced, this will look up the values 817 * for those variables and replace them in the doc handler URL. 818 */ 819 protected String resolveDocHandlerUrl(String docHandlerUrl) { 820 if (StringUtils.isBlank(docHandlerUrl)) { 821 return ""; 822 } 823 return Utilities.substituteConfigParameters(getApplicationId(), docHandlerUrl); 824 } 825 826 /** 827 * Use {@link #setDocHandlerUrl(String)} to add a document handler url to this object. 828 * 829 * @deprecated 830 */ 831 public void setDocHandlerUrl(java.lang.String docHandlerUrl) { 832 setUnresolvedDocHandlerUrl(docHandlerUrl); 833 } 834 835 /** 836 * @return the unresolvedHelpDefinitionUrl 837 */ 838 public String getUnresolvedHelpDefinitionUrl() { 839 return this.unresolvedHelpDefinitionUrl; 840 } 841 842 /** 843 * @param unresolvedHelpDefinitionUrl the unresolvedHelpDefinitionUrl to set 844 */ 845 public void setUnresolvedHelpDefinitionUrl(String unresolvedHelpDefinitionUrl) { 846 this.unresolvedHelpDefinitionUrl = unresolvedHelpDefinitionUrl; 847 } 848 849 /** 850 * This method gets the help definition url from this object and resolves any 851 * potential variables that may be in use 852 */ 853 public String getHelpDefinitionUrl() { 854 return resolveHelpUrl(getUnresolvedHelpDefinitionUrl()); 855 } 856 857 /** 858 * If a help URL has variables in it that need to be replaced, this will look up the values 859 * for those variables and replace them. 860 */ 861 protected String resolveHelpUrl(String helpDefinitionUrl) { 862 if (StringUtils.isBlank(helpDefinitionUrl)) { 863 return ""; 864 } 865 return Utilities.substituteConfigParameters(helpDefinitionUrl); 866 } 867 868 /** 869 * @return the unresolvedDocSearchHelpUrl 870 */ 871 public String getUnresolvedDocSearchHelpUrl() { 872 return this.unresolvedDocSearchHelpUrl; 873 } 874 875 /** 876 * @param unresolvedDocSearchHelpUrl the unresolvedDocSearchHelpUrl to set 877 */ 878 public void setUnresolvedDocSearchHelpUrl(String unresolvedDocSearchHelpUrl) { 879 this.unresolvedDocSearchHelpUrl = unresolvedDocSearchHelpUrl; 880 } 881 882 /** 883 * This method gets the doc search help url from this object and resolves any 884 * potential variables that may be in use 885 */ 886 public String getDocSearchHelpUrl() { 887 return resolveHelpUrl(getUnresolvedDocSearchHelpUrl()); 888 } 889 890 public java.lang.String getLabel() { 891 return label; 892 } 893 894 public void setLabel(java.lang.String label) { 895 this.label = label; 896 } 897 898 public java.lang.String getName() { 899 return name; 900 } 901 902 public void setName(java.lang.String name) { 903 this.name = name; 904 } 905 906 public PostProcessor getPostProcessor() { 907 String pname = getPostProcessorName(); 908 909 if (StringUtils.equals(pname, KewApiConstants.POST_PROCESSOR_NON_DEFINED_VALUE)) { 910 return new DefaultPostProcessor(); 911 } 912 if (StringUtils.isBlank(pname)) { 913 if (getParentDocType() != null) { 914 return getParentDocType().getPostProcessor(); 915 } else { 916 return new DefaultPostProcessor(); 917 } 918 } 919 920 ObjectDefinition objDef = getObjectDefinition(pname); 921 Object postProcessor = GlobalResourceLoader.getObject(objDef); 922 923 if (postProcessor == null) { 924 throw new WorkflowRuntimeException("Could not locate PostProcessor in this JVM or at application id " + getApplicationId() + ": " + pname); 925 } 926 927 // TODO: KULRICE-5572 Determine whether it is safe to wrap all post processors in a fresh GlobalVariables context 928 //return (PostProcessor) Proxy.newProxyInstance(postProcessor.getClass().getClassLoader(), new Class[] { PostProcessor.class }, new GlobalVariablesContextInvocationHandler(postProcessor)); 929 return (PostProcessor) postProcessor; 930 } 931 932 /** 933 * This method gets the post processor class value. If the forDisplayPurposes value is true 934 * the value will be invalid for system use. 935 * <p/> 936 * This method will first call the {@link #getPostProcessorName()} method to check the value on this object. 937 * If none is found the system checks for a parent document type. If a valid parent type exists for this document type 938 * then the system will use inheritance from that parent document type as long as at least one document type in the 939 * hierarchy has a value set. If no value is set on any parent document type or if no parent document type exists the 940 * system will return null. 941 * 942 * @param forDisplayPurposes - if true then the string returned will have a label explaining where the value came from 943 * @return the post processor class value or a displayable value with sourcing information 944 */ 945 protected String getInheritedPostProcessorName(boolean forDisplayPurposes) { 946 if (StringUtils.isNotBlank(getPostProcessorName())) { 947 // this object has a post processor class so return it 948 return getPostProcessorName(); 949 } 950 if (KRADUtils.isNotNull(getParentDocType())) { 951 // direct parent document type exists 952 String parentValue = getParentDocType().getPostProcessorName(); 953 if (StringUtils.isNotBlank(parentValue)) { 954 // found a post processor class set on the immediate parent object so return it 955 if (forDisplayPurposes) { 956 parentValue += " " + KewApiConstants.DOCUMENT_TYPE_INHERITED_VALUE_INDICATOR; 957 } 958 return parentValue; 959 } 960 // did not find a valid value on the immediate parent, so use hierarchy 961 return getParentDocType().getInheritedPostProcessorName(forDisplayPurposes); 962 } 963 return null; 964 } 965 966 public java.lang.String getPostProcessorName() { 967 return postProcessorName; 968 } 969 970 public void setPostProcessorName(java.lang.String postProcessorName) { 971 this.postProcessorName = postProcessorName; 972 } 973 974 public String getDisplayablePostProcessorName() { 975 return getInheritedPostProcessorName(true); 976 } 977 978 /** 979 * EMPTY METHOD. Use {@link #setPostProcessorName(String)} instead. 980 * 981 * @deprecated 982 */ 983 public void setDisplayablePostProcessorName(String displayablePostProcessorName) { 984 // do nothing 985 } 986 987 public String getPreviousVersionId() { 988 return previousVersionId; 989 } 990 991 public void setPreviousVersionId(String previousVersionId) { 992 this.previousVersionId = previousVersionId; 993 } 994 995 public java.lang.String getDocumentId() { 996 return documentId; 997 } 998 999 public void setDocumentId(java.lang.String documentId) { 1000 this.documentId = documentId; 1001 } 1002 1003 public java.lang.Integer getVersion() { 1004 return version; 1005 } 1006 1007 public void setVersion(java.lang.Integer version) { 1008 this.version = version; 1009 } 1010 1011 public String getDocumentTypeId() { 1012 return documentTypeId; 1013 } 1014 1015 public void setDocumentTypeId(String docTypeGrpId) { 1016 this.documentTypeId = docTypeGrpId; 1017 } 1018 1019 @Override 1020 public String getId() { 1021 return getDocumentTypeId(); 1022 } 1023 1024 public java.lang.String getReturnUrl() { 1025 return returnUrl; 1026 } 1027 1028 public void setReturnUrl(java.lang.String returnUrl) { 1029 this.returnUrl = returnUrl; 1030 } 1031 1032 /** 1033 * Returns the policy value of the specified policy, consulting parent document type definitions 1034 * if not defined on the immediate DocumentType. If not found, a policy with the specified default 1035 * value is returned. If policy is found on parent but boolean value is undefined, TRUE is used. 1036 * @param policyName the policy name to look up 1037 * @param defaultValue the default boolean value to return if policy is not found 1038 * @return DocumenTypePolicy defined on immediate or parent document types, or new instance initialized with 1039 * specified default boolean value 1040 */ 1041 public DocumentTypePolicy getPolicyByName(String policyName, Boolean defaultValue) { 1042 1043 Iterator policyIter = getDocumentTypePolicies().iterator(); 1044 while (policyIter.hasNext()) { 1045 DocumentTypePolicy policy = (DocumentTypePolicy) policyIter.next(); 1046 if (policyName.equals(policy.getPolicyName())) { 1047 policy.setInheritedFlag(Boolean.FALSE); 1048 return policy; 1049 } 1050 } 1051 1052 if (getParentDocType() != null) { 1053 DocumentTypePolicy policy = getParentDocType().getPolicyByName(policyName, defaultValue); 1054 policy.setInheritedFlag(Boolean.TRUE); 1055 if (policy.getPolicyValue() == null) { 1056 policy.setPolicyValue(Boolean.TRUE); 1057 } 1058 return policy; 1059 } 1060 DocumentTypePolicy policy = new DocumentTypePolicy(); 1061 policy.setPolicyName(policyName); 1062 policy.setInheritedFlag(Boolean.FALSE); 1063 policy.setPolicyValue(defaultValue); 1064 return policy; 1065 } 1066 1067 /** 1068 * Returns the policy value of the specified policy, consulting parent document type definitions 1069 * if not defined on the immediate DocumentType. If not found, a policy with a boolean value of True 1070 * and a string value of the specified default value is returned. 1071 * If policy is found on parent but boolean value is undefined, TRUE is used. 1072 * @param policyName the policy name to look up 1073 * @param defaultValue the default string value to return if policy is not found 1074 * @return DocumenTypePolicy defined on immediate or parent document types, or new instance initialized with 1075 * specified default string value 1076 */ 1077 public DocumentTypePolicy getPolicyByName(String policyName, String defaultValue) { 1078 1079 Iterator policyIter = getDocumentTypePolicies().iterator(); 1080 while (policyIter.hasNext()) { 1081 DocumentTypePolicy policy = (DocumentTypePolicy) policyIter.next(); 1082 if (policyName.equals(policy.getPolicyName())) { 1083 policy.setInheritedFlag(Boolean.FALSE); 1084 return policy; 1085 } 1086 } 1087 1088 if (getParentDocType() != null) { 1089 DocumentTypePolicy policy = getParentDocType().getPolicyByName(policyName, defaultValue); 1090 policy.setInheritedFlag(Boolean.TRUE); 1091 if (policy.getPolicyValue() == null) { 1092 policy.setPolicyValue(Boolean.TRUE); 1093 } 1094 return policy; 1095 } 1096 DocumentTypePolicy policy = new DocumentTypePolicy(); 1097 policy.setPolicyName(policyName); 1098 policy.setInheritedFlag(Boolean.FALSE); 1099 policy.setPolicyValue(Boolean.TRUE); 1100 policy.setPolicyStringValue(defaultValue); 1101 return policy; 1102 } 1103 1104 private DocumentTypeService getDocumentTypeService() { 1105 return (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE); 1106 } 1107 1108 public Group getSuperUserWorkgroup() { 1109 Group superUserWorkgroup = getSuperUserWorkgroupNoInheritence(); 1110 if (superUserWorkgroup == null && getParentDocType() != null) { 1111 return getParentDocType().getSuperUserWorkgroup(); 1112 } 1113 return superUserWorkgroup; 1114 } 1115 1116 public Group getSuperUserWorkgroupNoInheritence() { 1117 if (workgroupId == null) { 1118 return null; 1119 } 1120 return getGroupService().getGroup(this.workgroupId); 1121 } 1122 1123 public void setSuperUserWorkgroupNoInheritence(Group suWorkgroup) { 1124 this.workgroupId = null; 1125 if (KRADUtils.isNotNull(suWorkgroup)) { 1126 this.workgroupId = suWorkgroup.getId(); 1127 } 1128 } 1129 1130 /** 1131 * Set the immediate super user workgroup id field 1132 * @param suWorkgroupId the super user workgroup id 1133 */ 1134 public void setSuperUserWorkgroupIdNoInheritence(String suWorkgroupId) { 1135 this.workgroupId = suWorkgroupId; 1136 } 1137 1138 /** 1139 * Returns true if this DocumentType has a super user group defined. 1140 */ 1141 public boolean isSuperUserGroupDefined() { 1142 if (this.workgroupId == null) { 1143 return getParentDocType() != null && getParentDocType().isSuperUserGroupDefined(); 1144 } 1145 return true; 1146 } 1147 1148 public DocumentType getPreviousVersion() { 1149 return getDocumentTypeService().findById(previousVersionId); 1150 } 1151 1152 public Group getBlanketApproveWorkgroup() { 1153 if (StringUtils.isBlank(blanketApproveWorkgroupId)) { 1154 return null; 1155 } 1156 return getGroupService().getGroup(blanketApproveWorkgroupId); 1157 } 1158 1159 public void setBlanketApproveWorkgroup(Group blanketApproveWorkgroup) { 1160 this.blanketApproveWorkgroupId = null; 1161 if (KRADUtils.isNotNull(blanketApproveWorkgroup)) { 1162 this.blanketApproveWorkgroupId = blanketApproveWorkgroup.getId(); 1163 } 1164 } 1165 1166 public String getBlanketApprovePolicy() { 1167 return this.blanketApprovePolicy; 1168 } 1169 1170 public void setBlanketApprovePolicy(String blanketApprovePolicy) { 1171 this.blanketApprovePolicy = blanketApprovePolicy; 1172 } 1173 1174 public Group getBlanketApproveWorkgroupWithInheritance() { 1175 if (getParentDocType() != null && this.blanketApproveWorkgroupId == null) { 1176 return getParentDocType().getBlanketApproveWorkgroupWithInheritance(); 1177 } else if(this.blanketApproveWorkgroupId != null) { 1178 return getGroupService().getGroup(blanketApproveWorkgroupId); 1179 } 1180 return null; 1181 } 1182 1183 public boolean isBlanketApprover(String principalId) { 1184 if (KewApiConstants.DOCUMENT_TYPE_BLANKET_APPROVE_POLICY_NONE.equalsIgnoreCase(getBlanketApprovePolicy())) { 1185 // no one can blanket approve this doc type 1186 return false; 1187 } else if (KewApiConstants.DOCUMENT_TYPE_BLANKET_APPROVE_POLICY_ANY.equalsIgnoreCase(getBlanketApprovePolicy())) { 1188 // anyone can blanket approve this doc type 1189 return true; 1190 } 1191 if (blanketApproveWorkgroupId != null) { 1192 return getGroupService().isMemberOfGroup(principalId, blanketApproveWorkgroupId); 1193 } 1194 DocumentType parentDoc = getParentDocType(); 1195 if (parentDoc != null) { 1196 // found parent doc so try to get blanket approver info from it 1197 return parentDoc.isBlanketApprover(principalId); 1198 } 1199 return false; 1200 } 1201 1202 /** 1203 * Returns true if either a blanket approve group or blanket approve policy is defined 1204 * on this Document Type. 1205 */ 1206 public boolean isBlanketApproveGroupDefined() { 1207 if (StringUtils.isBlank(getBlanketApprovePolicy()) && this.blanketApproveWorkgroupId == null) { 1208 return getParentDocType() != null && getParentDocType().isBlanketApproveGroupDefined(); 1209 } 1210 return true; 1211 } 1212 1213 /** 1214 * @return the reportingWorkgroupId 1215 */ 1216 public String getReportingWorkgroupId() { 1217 return this.reportingWorkgroupId; 1218 } 1219 1220 /** 1221 * @param reportingWorkgroupId the reportingWorkgroupId to set 1222 */ 1223 public void setReportingWorkgroupId(String reportingWorkgroupId) { 1224 this.reportingWorkgroupId = reportingWorkgroupId; 1225 } 1226 1227 public Group getReportingWorkgroup() { 1228 if (StringUtils.isBlank(this.reportingWorkgroupId)) { 1229 return null; 1230 } 1231 return getGroupService().getGroup(this.reportingWorkgroupId); 1232 } 1233 1234 public void setReportingWorkgroup(Group reportingWorkgroup) { 1235 this.reportingWorkgroupId = null; 1236 if (KRADUtils.isNotNull(reportingWorkgroup)) { 1237 this.reportingWorkgroupId = reportingWorkgroup.getId(); 1238 } 1239 } 1240 1241 public Group getDefaultExceptionWorkgroup() { 1242 return defaultExceptionWorkgroup; 1243 } 1244 1245 public void setDefaultExceptionWorkgroup(Group defaultExceptionWorkgroup) { 1246 this.defaultExceptionWorkgroup = defaultExceptionWorkgroup; 1247 } 1248 1249 public CustomActionListAttribute getCustomActionListAttribute() throws ResourceUnavailableException { 1250 CustomActionListAttribute result = null; 1251 RuleAttribute customActionListRuleAttribute = getCustomActionListRuleAttribute(); 1252 1253 if (customActionListRuleAttribute != null) { 1254 try { 1255 ExtensionDefinition extensionDefinition = 1256 KewApiServiceLocator.getExtensionRepositoryService().getExtensionById(customActionListRuleAttribute.getId()); 1257 1258 if (extensionDefinition != null) { 1259 result = ExtensionUtils.loadExtension(extensionDefinition, customActionListRuleAttribute.getApplicationId()); 1260 } else { 1261 LOG.warn("Could not load ExtensionDefinition for " + customActionListRuleAttribute); 1262 } 1263 1264 } catch (RiceRemoteServiceConnectionException e) { 1265 LOG.warn("Unable to connect to load custom action list attribute for " + customActionListRuleAttribute, e); 1266 } 1267 } 1268 1269 return result; 1270 } 1271 1272 public CustomEmailAttribute getCustomEmailAttribute() throws ResourceUnavailableException { 1273 ObjectDefinition objDef = getAttributeObjectDefinition(KewApiConstants.EMAIL_ATTRIBUTE_TYPE); 1274 if (objDef == null) { 1275 return null; 1276 } 1277 return (CustomEmailAttribute) GlobalResourceLoader.getObject(objDef); 1278 } 1279 1280 public ObjectDefinition getAttributeObjectDefinition(String typeCode) { 1281 for (Iterator iter = getDocumentTypeAttributes().iterator(); iter.hasNext();) { 1282 RuleAttribute attribute = ((DocumentTypeAttributeBo) iter.next()).getRuleAttribute(); 1283 if (attribute.getType().equals(typeCode)) { 1284 return getAttributeObjectDefinition(attribute); 1285 } 1286 } 1287 if (getParentDocType() != null) { 1288 return getParentDocType().getAttributeObjectDefinition(typeCode); 1289 } 1290 return null; 1291 } 1292 1293 public ObjectDefinition getAttributeObjectDefinition(RuleAttribute ruleAttribute) { 1294 if (ruleAttribute.getApplicationId() == null) { 1295 return new ObjectDefinition(ruleAttribute.getResourceDescriptor(), this.getApplicationId()); 1296 } else { 1297 return new ObjectDefinition(ruleAttribute.getResourceDescriptor(), ruleAttribute.getApplicationId()); 1298 } 1299 } 1300 1301 public CustomNoteAttribute getCustomNoteAttribute() throws ResourceUnavailableException { 1302 ObjectDefinition objDef = getAttributeObjectDefinition(KewApiConstants.NOTE_ATTRIBUTE_TYPE); 1303 if (objDef == null) { 1304 String defaultNoteClass = ConfigContext.getCurrentContextConfig().getDefaultKewNoteClass(); 1305 if (defaultNoteClass == null) { 1306 // attempt to use deprecated parameter 1307 defaultNoteClass = ConfigContext.getCurrentContextConfig().getDefaultKewNoteClass(); 1308 if (defaultNoteClass == null) { 1309 return null; 1310 } 1311 } 1312 objDef = new ObjectDefinition(defaultNoteClass); 1313 } 1314 return (CustomNoteAttribute) GlobalResourceLoader.getObject(objDef); 1315 } 1316 1317 public ObjectDefinition getObjectDefinition(String objectName) { 1318 return new ObjectDefinition(objectName, getApplicationId()); 1319 } 1320 1321 /** 1322 * Returns true if this document type defines it's own routing, false if it inherits its routing 1323 * from a parent document type. 1324 */ 1325 public boolean isRouteInherited() { 1326 return processes.isEmpty() && getParentDocType() != null; 1327 } 1328 1329 /** 1330 * Returns the DocumentType which defines the route for this document. This is the DocumentType 1331 * from which we inherit our Processes which define our routing. 1332 */ 1333 public DocumentType getRouteDefiningDocumentType() { 1334 if (isRouteInherited()) { 1335 return getParentDocType().getRouteDefiningDocumentType(); 1336 } 1337 return this; 1338 } 1339 1340 public boolean isDocTypeActive() { 1341 if (!getActive().booleanValue()) { 1342 return false; 1343 } 1344 if (getParentDocType() != null) { 1345 if (!getParentActiveInd(getParentDocType())) { 1346 return false; 1347 } 1348 } 1349 return true; 1350 } 1351 1352 private boolean getParentActiveInd(DocumentType parentDocType) { 1353 if (parentDocType.getActive() == null || parentDocType.getActive().booleanValue()) { 1354 if (parentDocType.getParentDocType() != null) { 1355 return getParentActiveInd(parentDocType.getParentDocType()); 1356 } 1357 return true; 1358 } else { 1359 return false; 1360 } 1361 } 1362 1363 /** 1364 * @param documentTypeAttributes The documentTypeAttributes to set. 1365 */ 1366 public void setDocumentTypeAttributes(List<DocumentTypeAttributeBo> documentTypeAttributes) { 1367 this.documentTypeAttributes = documentTypeAttributes; 1368 } 1369 1370 /** 1371 * @return Returns the documentTypeAttributes. 1372 */ 1373 public List<DocumentTypeAttributeBo> getDocumentTypeAttributes() { 1374 return documentTypeAttributes; 1375 } 1376 1377 public void addProcess(ProcessDefinitionBo process) { 1378 processes.add(process); 1379 } 1380 1381 /** 1382 * Gets the processes of this document by checking locally for processes, and if none are 1383 * present, retrieves them from it's parent document type. The list returned is an immutable 1384 * list. To add processes to a document type, use the addProcess method. 1385 * <p/> 1386 * NOTE: Since OJB uses direct field access, this will not interfere with the proper 1387 * mapping of the processes field. 1388 * 1389 * @return 1390 */ 1391 public List getProcesses() { 1392 if (processes.isEmpty() && getParentDocType() != null) { 1393 return getParentProcesses(getParentDocType()); 1394 } 1395 return Collections.unmodifiableList(processes); 1396 } 1397 1398 public void setProcesses(List routeNodes) { 1399 this.processes = routeNodes; 1400 } 1401 1402 private List getParentProcesses(DocumentType parent) { 1403 List parentProcesses = parent.getProcesses(); 1404 if (parentProcesses == null) { 1405 parentProcesses = getParentProcesses(parent.getParentDocType()); 1406 } 1407 return parentProcesses; 1408 } 1409 1410 public ProcessDefinitionBo getPrimaryProcess() { 1411 for (Iterator iterator = getProcesses().iterator(); iterator.hasNext();) { 1412 ProcessDefinitionBo process = (ProcessDefinitionBo) iterator.next(); 1413 if (process.isInitial()) { 1414 return process; 1415 } 1416 } 1417 return null; 1418 } 1419 1420 public ProcessDefinitionBo getNamedProcess(String name) { 1421 for (Iterator iterator = getProcesses().iterator(); iterator.hasNext();) { 1422 ProcessDefinitionBo process = (ProcessDefinitionBo) iterator.next(); 1423 if (org.apache.commons.lang.ObjectUtils.equals(name, process.getName())) { 1424 return process; 1425 } 1426 } 1427 return null; 1428 } 1429 1430 public String getRoutingVersion() { 1431 return routingVersion; 1432 } 1433 1434 public void setRoutingVersion(String routingVersion) { 1435 this.routingVersion = routingVersion; 1436 } 1437 1438 /** 1439 * @return the actualNotificationFromAddress 1440 */ 1441 public String getActualNotificationFromAddress() { 1442 return this.actualNotificationFromAddress; 1443 } 1444 1445 /** 1446 * @param actualNotificationFromAddress the actualNotificationFromAddress to set 1447 */ 1448 public void setActualNotificationFromAddress(String actualNotificationFromAddress) { 1449 this.actualNotificationFromAddress = actualNotificationFromAddress; 1450 } 1451 1452 /** 1453 * Returns the same value as the {@link #getNotificationFromAddress()} method but will also have label information if 1454 * the value is inherited from a parent document type 1455 */ 1456 public String getDisplayableNotificationFromAddress() { 1457 return getNotificationFromAddress(true); 1458 } 1459 1460 /** 1461 * EMPTY METHOD. Use {@link #setActualNotificationFromAddress(String)} instead. 1462 * 1463 * @deprecated 1464 */ 1465 public void setDisplayableNotificationFromAddress(String displayableNotificationFromAddress) { 1466 // do nothing 1467 } 1468 1469 public String getNotificationFromAddress() { 1470 return getNotificationFromAddress(false); 1471 } 1472 1473 /** 1474 * This method gets the notification from address value. If the forDisplayPurposes value is true 1475 * the notification from address value will be invalid for system use 1476 * <p/> 1477 * This method will first call the {@link #getActualNotificationFromAddress()} method to check the value on this object. 1478 * If none is found the system checks for a parent document type. If a valid parent type exists for this document type 1479 * then the system will use inheritance from that parent document type as long as at least one document type in the 1480 * hierarchy has a value set. If no value is set on any parent document type or if no parent document type exists the 1481 * system will return null 1482 * 1483 * @param forDisplayPurposes - if true then the string returned will have a label explaining where the value came from 1484 * @return the notification from address value or a displayable value with sourcing information 1485 */ 1486 protected String getNotificationFromAddress(boolean forDisplayPurposes) { 1487 if (StringUtils.isNotBlank(getActualNotificationFromAddress())) { 1488 // this object has an address so return it 1489 return getActualNotificationFromAddress(); 1490 } 1491 if (KRADUtils.isNotNull(getParentDocType())) { 1492 // direct parent document type exists 1493 String parentNotificationFromAddress = getParentDocType().getActualNotificationFromAddress(); 1494 if (StringUtils.isNotBlank(parentNotificationFromAddress)) { 1495 // found an address set on the immediate parent object so return it 1496 if (forDisplayPurposes) { 1497 parentNotificationFromAddress += " " + KewApiConstants.DOCUMENT_TYPE_INHERITED_VALUE_INDICATOR; 1498 } 1499 return parentNotificationFromAddress; 1500 } 1501 // did not find a valid address on the immediate parent to use hierarchy 1502 return getParentDocType().getNotificationFromAddress(forDisplayPurposes); 1503 } 1504 return null; 1505 } 1506 1507 /** 1508 * Use {@link #setActualNotificationFromAddress(String)} instead 1509 * 1510 * @deprecated 1511 */ 1512 public void setNotificationFromAddress(String notificationFromAddress) { 1513 setActualNotificationFromAddress(notificationFromAddress); 1514 } 1515 1516 public boolean isParentOf(DocumentType documentType) { 1517 // this is a depth-first search which works for our needs 1518 for (Iterator iterator = getChildrenDocTypes().iterator(); iterator.hasNext();) { 1519 DocumentType child = (DocumentType) iterator.next(); 1520 if (child.getName().equals(documentType.getName()) || child.isParentOf(documentType)) { 1521 return true; 1522 } 1523 } 1524 return false; 1525 } 1526 1527 /** 1528 * this exists because the lookup wants to make a call on a bean method when displaying results and those calls are 1529 * entered programatically into the framework by method name 1530 * 1531 * @return 1532 */ 1533 public String getLookupParentName() { 1534 DocumentType parent = getParentDocType(); 1535 if (parent == null) { 1536 return "Root"; 1537 } 1538 return parent.getName(); 1539 } 1540 1541 public boolean isSuperUser(String principalId) { 1542 Group workgroup = getSuperUserWorkgroup(); 1543 if (workgroup == null) { 1544 return false; 1545 } 1546 return getGroupService().isMemberOfGroup(principalId, workgroup.getId()); 1547 } 1548 1549 public boolean hasPreviousVersion() { 1550 if (this.documentTypeId == null) { 1551 return false; 1552 } 1553 return !this.documentTypeId.equals(this.previousVersionId); 1554 } 1555 1556 /** 1557 * @return the actual application id 1558 */ 1559 public String getActualApplicationId() { 1560 return this.actualApplicationId; 1561 } 1562 1563 /** 1564 * @param actualApplicationId the actualApplicationId to set 1565 */ 1566 public void setActualApplicationId(String actualApplicationId) { 1567 this.actualApplicationId = actualApplicationId; 1568 } 1569 1570 /** 1571 * Returns the application id for this DocumentType which can be specified on the document type itself, 1572 * inherited from the parent, or defaulted to the configured application id of the application. 1573 */ 1574 public String getApplicationId() { 1575 return getApplicationId(false); 1576 } 1577 1578 /** 1579 * This method gets the string for the application id value. If the forDisplayPurposes value is true 1580 * the application id value will be invalid for system use. 1581 * <p/> 1582 * This method will first call the {@link #getActualApplicationId()} method to check for a value on this object. If 1583 * none is found a parent document type is used. If a valid parent type exists for this document type then the system 1584 * will use inheritance from that parent document type as long as at least one document type in the hierarchy has a 1585 * value set. If no value is set on any parent document type or if no parent document type exists for this object the 1586 * system default is used: {@link CoreConfigHelper#getApplicationId()} 1587 * 1588 * @param forDisplayPurposes - if true then the string returned will have a label explaining where the value came from 1589 * @return the application id value or a displayable value with sourcing information 1590 */ 1591 protected String getApplicationId(boolean forDisplayPurposes) { 1592 if (StringUtils.isNotBlank(getActualApplicationId())) { 1593 // this object has a application id set, so return it 1594 return getActualApplicationId(); 1595 } 1596 // this object has no application id... check for a parent document type 1597 if (KRADUtils.isNotNull(getParentDocType())) { 1598 // direct parent document type exists 1599 String parentValue = getParentDocType().getActualApplicationId(); 1600 if (StringUtils.isNotBlank(parentValue)) { 1601 // found a parent value set on the immediate parent object so return it 1602 if (forDisplayPurposes) { 1603 parentValue += " " + KewApiConstants.DOCUMENT_TYPE_INHERITED_VALUE_INDICATOR; 1604 } 1605 return parentValue; 1606 } 1607 // no valid application id on direct parent, so use hierarchy to find correct value 1608 return getParentDocType().getApplicationId(forDisplayPurposes); 1609 } 1610 String defaultValue = CoreConfigHelper.getApplicationId(); 1611 if (forDisplayPurposes) { 1612 defaultValue += " " + KewApiConstants.DOCUMENT_TYPE_SYSTEM_DEFAULT_INDICATOR; 1613 } 1614 return defaultValue; 1615 } 1616 1617 /** 1618 * Returns the same value as the {@link #getApplicationId()} method but will also have label information about 1619 * where the application id came from (ie: inherited from the parent document type) 1620 */ 1621 public String getDisplayableApplicationId() { 1622 return getApplicationId(true); 1623 } 1624 1625 /** 1626 * Gets the name of the custom email stylesheet to use to render email (if any has been set, null otherwise) 1627 * 1628 * @return name of the custom email stylesheet to use to render email (if any has been set, null otherwise) 1629 */ 1630 public String getCustomEmailStylesheet() { 1631 return customEmailStylesheet; 1632 } 1633 1634 /** 1635 * Sets the name of the custom email stylesheet to use to render email 1636 * 1637 * @return name of the custom email stylesheet to use to render email 1638 */ 1639 public void setCustomEmailStylesheet(String customEmailStylesheet) { 1640 this.customEmailStylesheet = customEmailStylesheet; 1641 } 1642 1643 /** 1644 * @return the blanketApproveWorkgroupId 1645 */ 1646 public String getBlanketApproveWorkgroupId() { 1647 return this.blanketApproveWorkgroupId; 1648 } 1649 1650 1651 /** 1652 * @param blanketApproveWorkgroupId the blanketApproveWorkgroupId to set 1653 */ 1654 public void setBlanketApproveWorkgroupId(String blanketApproveWorkgroupId) { 1655 this.blanketApproveWorkgroupId = blanketApproveWorkgroupId; 1656 } 1657 1658 /** 1659 * @return the applyRetroactively 1660 */ 1661 public Boolean getApplyRetroactively() { 1662 return this.applyRetroactively; 1663 } 1664 1665 /** 1666 * @param applyRetroactively the applyRetroactively to set 1667 */ 1668 public void setApplyRetroactively(Boolean applyRetroactively) { 1669 this.applyRetroactively = applyRetroactively; 1670 } 1671 1672 private GroupService getGroupService() { 1673 return KimApiServiceLocator.getGroupService(); 1674 } 1675 1676 /** 1677 * @see org.kuali.rice.core.api.mo.common.active.MutableInactivatable#isActive() 1678 */ 1679 public boolean isActive() { 1680 boolean bRet = false; 1681 1682 if (active != null) { 1683 bRet = active.booleanValue(); 1684 } 1685 1686 return bRet; 1687 } 1688 1689 /** 1690 * @see org.kuali.rice.core.api.mo.common.active.MutableInactivatable#setActive(boolean) 1691 */ 1692 public void setActive(boolean active) { 1693 this.active = Boolean.valueOf(active); 1694 } 1695 1696 @Override 1697 public Integer getDocumentTypeVersion() { 1698 return version; 1699 } 1700 1701 @Override 1702 public String getParentId() { 1703 return docTypeParentId; 1704 } 1705 1706 @Override 1707 public String getBlanketApproveGroupId() { 1708 return blanketApproveWorkgroupId; 1709 } 1710 1711 @Override 1712 public String getSuperUserGroupId() { 1713 return workgroupId; 1714 } 1715 1716 @Override 1717 public String getAuthorizer() { 1718 String result = authorizer; 1719 1720 if (StringUtils.isBlank(result)) { 1721 if (getParentDocType() != null) { 1722 return getParentDocType().getAuthorizer(); 1723 } 1724 } 1725 1726 return result; 1727 } 1728 1729 public void setAuthorizer(String authorizer) { 1730 this.authorizer = authorizer; 1731 } 1732 1733 public static org.kuali.rice.kew.api.doctype.DocumentType to(DocumentType documentTypeBo) { 1734 if (documentTypeBo == null) { 1735 return null; 1736 } 1737 org.kuali.rice.kew.api.doctype.DocumentType.Builder builder = org.kuali.rice.kew.api.doctype.DocumentType.Builder.create(documentTypeBo); 1738 builder.setApplicationId(documentTypeBo.getActualApplicationId()); 1739 return builder.build(); 1740 } 1741 1742 public static DocumentType from(org.kuali.rice.kew.api.doctype.DocumentTypeContract dt) { 1743 if (dt == null) return null; 1744 1745 // DocumentType BO and DTO are not symmetric 1746 // set what fields we can 1747 DocumentType ebo = new DocumentType(); 1748 //ebo.setActionsUrl(); 1749 ebo.setDocumentTypeId(dt.getId()); 1750 ebo.setActive(dt.isActive()); 1751 ebo.setActualApplicationId(dt.getApplicationId()); 1752 //ebo.setActualNotificationFromAddress(); 1753 ebo.setBlanketApproveWorkgroupId(dt.getBlanketApproveGroupId()); 1754 ebo.setCurrentInd(dt.isCurrent()); 1755 ebo.setDescription(dt.getDescription()); 1756 ebo.setVersionNumber(dt.getVersionNumber()); 1757 ebo.setVersion(dt.getDocumentTypeVersion()); 1758 ebo.setUnresolvedDocHandlerUrl(dt.getUnresolvedDocHandlerUrl()); 1759 ebo.setUnresolvedDocSearchHelpUrl(dt.getDocSearchHelpUrl()); 1760 ebo.setUnresolvedHelpDefinitionUrl(dt.getHelpDefinitionUrl()); 1761 ebo.setLabel(dt.getLabel()); 1762 ebo.setName(dt.getName()); 1763 ebo.setDocTypeParentId(dt.getParentId()); 1764 ebo.setPostProcessorName(dt.getPostProcessorName()); 1765 ebo.setSuperUserWorkgroupIdNoInheritence(dt.getSuperUserGroupId()); 1766 List<DocumentTypePolicy> policies = new ArrayList<DocumentTypePolicy>(); 1767 if (dt.getPolicies() != null) { 1768 for (Map.Entry<org.kuali.rice.kew.api.doctype.DocumentTypePolicy, String> entry: dt.getPolicies().entrySet()) { 1769 // NOTE: The policy value is actually a boolean field stored to a Decimal(1) column (although the db column is named PLCY_NM) 1770 // I'm not sure what the string value should be but the BO is simply toString'ing the Boolean value 1771 // so I am assuming here that "true"/"false" are the acceptable values 1772 policies.add(new DocumentTypePolicy(dt.getId(), entry.getKey().getCode(), Boolean.TRUE.toString().equals( 1773 entry.getValue()))); 1774 } 1775 } 1776 if (CollectionUtils.isNotEmpty(dt.getDocumentTypeAttributes())) { 1777 List<DocumentTypeAttributeBo> attributes = new ArrayList<DocumentTypeAttributeBo>(); 1778 for (DocumentTypeAttributeContract attr : dt.getDocumentTypeAttributes()) { 1779 attributes.add(DocumentTypeAttributeBo.from(DocumentTypeAttribute.Builder.create(attr).build())); 1780 } 1781 1782 } 1783 ebo.setDocumentTypePolicies(policies); 1784 ebo.setAuthorizer(dt.getAuthorizer()); 1785 return ebo; 1786 } 1787 1788 public String getWorkgroupId() { 1789 return workgroupId; 1790 } 1791 1792 public void setWorkgroupId(String workgroupId) { 1793 this.workgroupId = workgroupId; 1794 } 1795 1796 @Override 1797 public void refresh() { 1798 // do nothing - this is an EBO - and this method is not safe to call on EBO-extending JPA-bytecode-weaved objects 1799 // See org.kuali.rice.krad.service.impl.PersistenceServiceImpl.retrieveNonKeyFields(Object) 1800 } 1801}