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