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