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