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