Coverage Report - org.kuali.rice.kew.xml.RuleTemplateXmlParser
 
Classes in this File Line Coverage Branch Coverage Complexity
RuleTemplateXmlParser
0%
0/190
0%
0/84
5.833
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  *
 4  
  *
 5  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.opensource.org/licenses/ecl2.php
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.kuali.rice.kew.xml;
 18  
 
 19  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.ACTIVE;
 20  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.ATTRIBUTE;
 21  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.ATTRIBUTES;
 22  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.DEFAULT_ACTION_REQUESTED;
 23  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.DELEGATION_TEMPLATE;
 24  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.DELEGATION_TYPE;
 25  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.DESCRIPTION;
 26  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.FORCE_ACTION;
 27  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.FROM_DATE;
 28  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.NAME;
 29  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.REQUIRED;
 30  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.RULE_DEFAULTS;
 31  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.RULE_TEMPLATE;
 32  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.RULE_TEMPLATES;
 33  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.RULE_TEMPLATE_NAMESPACE;
 34  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.SUPPORTS_ACKNOWLEDGE;
 35  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.SUPPORTS_APPROVE;
 36  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.SUPPORTS_COMPLETE;
 37  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.SUPPORTS_FYI;
 38  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.TO_DATE;
 39  
 
 40  
 import java.io.IOException;
 41  
 import java.io.InputStream;
 42  
 import java.sql.Timestamp;
 43  
 import java.text.ParseException;
 44  
 import java.util.ArrayList;
 45  
 import java.util.Collection;
 46  
 import java.util.Iterator;
 47  
 import java.util.List;
 48  
 
 49  
 import javax.xml.parsers.ParserConfigurationException;
 50  
 
 51  
 import org.apache.commons.lang.BooleanUtils;
 52  
 import org.apache.commons.lang.StringUtils;
 53  
 import org.jdom.Attribute;
 54  
 import org.jdom.Document;
 55  
 import org.jdom.Element;
 56  
 import org.jdom.JDOMException;
 57  
 import org.kuali.rice.core.util.RiceConstants;
 58  
 import org.kuali.rice.core.util.xml.XmlException;
 59  
 import org.kuali.rice.core.util.xml.XmlHelper;
 60  
 import org.kuali.rice.kew.api.action.DelegationType;
 61  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 62  
 import org.kuali.rice.kew.rule.RuleDelegation;
 63  
 import org.kuali.rice.kew.rule.RuleTemplateOption;
 64  
 import org.kuali.rice.kew.rule.bo.RuleAttribute;
 65  
 import org.kuali.rice.kew.rule.bo.RuleTemplate;
 66  
 import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
 67  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 68  
 import org.kuali.rice.kew.util.KEWConstants;
 69  
 import org.xml.sax.SAXException;
 70  
 /**
 71  
  * Parses {@link RuleTemplate}s from XML.
 72  
  *
 73  
  * @see RuleTemplate
 74  
  *
 75  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 76  
  */
 77  0
 public class RuleTemplateXmlParser {
 78  
 
 79  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RuleTemplateXmlParser.class);
 80  
 
 81  
     /**
 82  
      * By default make attributes defined without a <required> element
 83  
      */
 84  
     private static final boolean DEFAULT_ATTRIBUTE_REQUIRED = true;
 85  
     private static final boolean DEFAULT_ATTRIBUTE_ACTIVE = true;
 86  
 
 87  
     /**
 88  
      * A dummy document type used in the default rule
 89  
      */
 90  
     private static final String DUMMY_DOCUMENT_TYPE = "dummyDocumentType";
 91  
 
 92  
     /**
 93  
      * Used to set the display order of attributes encountered in parsing runs during the lifetime of this object
 94  
      */
 95  0
     private int templateAttributeCounter = 0;
 96  
 
 97  
     public List<RuleTemplate> parseRuleTemplates(InputStream input) throws IOException, XmlException {
 98  
 
 99  
         try {
 100  0
             Document doc = XmlHelper.trimSAXXml(input);
 101  0
             Element root = doc.getRootElement();
 102  0
             return parseRuleTemplates(root);
 103  0
         } catch (JDOMException e) {
 104  0
             throw new XmlException("Parse error.", e);
 105  0
         } catch (SAXException e) {
 106  0
             throw new XmlException("Parse error.", e);
 107  0
         } catch (ParserConfigurationException e) {
 108  0
             throw new XmlException("Parse error.", e);
 109  
         }
 110  
     }
 111  
 
 112  
     public List<RuleTemplate> parseRuleTemplates(Element element) throws XmlException {
 113  0
         List<RuleTemplate> ruleTemplates = new ArrayList<RuleTemplate>();
 114  
 
 115  
         // iterate over any RULE_TEMPLATES elements
 116  0
         Collection<Element> ruleTemplatesElements = XmlHelper.findElements(element, RULE_TEMPLATES);
 117  0
         Iterator ruleTemplatesIterator = ruleTemplatesElements.iterator();
 118  0
         while (ruleTemplatesIterator.hasNext()) {
 119  0
             Element ruleTemplatesElement = (Element) ruleTemplatesIterator.next();
 120  0
             Collection<Element> ruleTemplateElements = XmlHelper.findElements(ruleTemplatesElement, RULE_TEMPLATE);
 121  0
             for (Iterator iterator = ruleTemplateElements.iterator(); iterator.hasNext();) {
 122  0
                 ruleTemplates.add(parseRuleTemplate((Element) iterator.next(), ruleTemplates));
 123  
             }
 124  0
         }
 125  0
         return ruleTemplates;
 126  
     }
 127  
 
 128  
     private RuleTemplate parseRuleTemplate(Element element, List<RuleTemplate> ruleTemplates) throws XmlException {
 129  0
         String name = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
 130  0
         String description = element.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);
 131  0
         Attribute allowOverwriteAttrib = element.getAttribute("allowOverwrite");
 132  
 
 133  0
         boolean allowOverwrite = false;
 134  0
         if (allowOverwriteAttrib != null) {
 135  0
             allowOverwrite = Boolean.valueOf(allowOverwriteAttrib.getValue()).booleanValue();
 136  
         }
 137  0
         if (org.apache.commons.lang.StringUtils.isEmpty(name)) {
 138  0
             throw new XmlException("RuleTemplate must have a name");
 139  
         }
 140  0
         if (org.apache.commons.lang.StringUtils.isEmpty(description)) {
 141  0
             throw new XmlException("RuleTemplate must have a description");
 142  
         }
 143  
 
 144  
         // look up the rule template by name first
 145  0
         RuleTemplate ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(name);
 146  
 
 147  0
         if (ruleTemplate == null) {
 148  
             // if it does not exist create a new one
 149  0
             ruleTemplate = new RuleTemplate();
 150  
         } else {
 151  
             // if it does exist, update it, only if allowOverwrite is set
 152  0
             if (!allowOverwrite) {
 153  0
                 throw new RuntimeException("Attempting to overwrite template " + name + " without allowOverwrite set");
 154  
             }
 155  
 
 156  
             // the name should be equal if one was actually found
 157  0
             assert(name.equals(ruleTemplate.getName())) : "Existing template definition name does not match incoming definition name";
 158  
         } 
 159  
 
 160  
         // overwrite simple properties
 161  0
         ruleTemplate.setName(name);
 162  0
         ruleTemplate.setDescription(description);
 163  
 
 164  
         // update the delegation template
 165  0
         updateDelegationTemplate(element, ruleTemplate, ruleTemplates);
 166  
 
 167  
         // update the attribute relationships
 168  0
         updateRuleTemplateAttributes(element, ruleTemplate);
 169  
 
 170  
         // save the rule template first so that the default/template rule that is generated
 171  
         // in the process of setting defaults is associated properly with this rule template
 172  0
         KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);
 173  
 
 174  
         // update the default options
 175  0
         updateRuleTemplateDefaultOptions(element, ruleTemplate);
 176  
 
 177  0
         KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);
 178  
 
 179  0
         return ruleTemplate;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Updates the rule template default options.  Updates any existing options, removes any omitted ones.
 184  
      * @param ruleTemplateElement the rule template XML element
 185  
      * @param updatedRuleTemplate the RuleTemplate being updated
 186  
      * @throws XmlException
 187  
      */
 188  
     /*
 189  
      <element name="description" type="c:LongStringType"/>
 190  
      <element name="fromDate" type="c:ShortStringType" minOccurs="0"/>
 191  
      <element name="toDate" type="c:ShortStringType" minOccurs="0"/>
 192  
      <element name="forceAction" type="boolean"/>
 193  
      <element name="active" type="boolean"/>
 194  
      <element name="defaultActionRequested" type="c:ShortStringType"/>
 195  
      <element name="supportsComplete" type="boolean" default="true"/>
 196  
      <element name="supportsApprove" type="boolean" default="true"/>
 197  
      <element name="supportsAcknowledge" type="boolean" default="true"/>
 198  
      <element name="supportsFYI" type="boolean" default="true"/>
 199  
     */
 200  
     protected void updateRuleTemplateDefaultOptions(Element ruleTemplateElement, RuleTemplate updatedRuleTemplate) throws XmlException {
 201  0
         Element defaultsElement = ruleTemplateElement.getChild(RULE_DEFAULTS, RULE_TEMPLATE_NAMESPACE);
 202  
 
 203  
         // update the rule defaults; this yields whether or not this is a delegation rule template
 204  0
         boolean isDelegation = updateRuleDefaults(defaultsElement, updatedRuleTemplate);
 205  
 
 206  
         // update the rule template options
 207  0
         updateRuleTemplateOptions(defaultsElement, updatedRuleTemplate, isDelegation);
 208  
 
 209  0
     }
 210  
 
 211  
     /**
 212  
      * Updates the rule template defaults options with those in the defaults element
 213  
      * @param defaultsElement the ruleDefaults element
 214  
      * @param updatedRuleTemplate the Rule Template being updated
 215  
      */
 216  
     protected void updateRuleTemplateOptions(Element defaultsElement, RuleTemplate updatedRuleTemplate, boolean isDelegation) throws XmlException {
 217  
         // the possible defaults options
 218  
         // NOTE: the current implementation will remove any existing RuleTemplateOption records for any values which are null, i.e. not set in the incoming XML.
 219  
         // to pro-actively set default values for omitted options, simply set those values here, and records will be added if not present
 220  0
         String defaultActionRequested = null;
 221  0
         Boolean supportsComplete = null;
 222  0
         Boolean supportsApprove = null;
 223  0
         Boolean supportsAcknowledge = null;
 224  0
         Boolean supportsFYI = null;
 225  
         
 226  
         // remove any RuleTemplateOptions the template may have but that we know we aren't going to update/reset
 227  
         // (not sure if this case even exists...does anything else set rule template options?)
 228  0
         updatedRuleTemplate.removeNonDefaultOptions();
 229  
         
 230  
         // read in new settings
 231  0
         if (defaultsElement != null) {
 232  
 
 233  0
                 defaultActionRequested = defaultsElement.getChildText(DEFAULT_ACTION_REQUESTED, RULE_TEMPLATE_NAMESPACE);
 234  0
             supportsComplete = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_COMPLETE, RULE_TEMPLATE_NAMESPACE));
 235  0
             supportsApprove = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_APPROVE, RULE_TEMPLATE_NAMESPACE));
 236  0
             supportsAcknowledge = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_ACKNOWLEDGE, RULE_TEMPLATE_NAMESPACE));
 237  0
             supportsFYI = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_FYI, RULE_TEMPLATE_NAMESPACE));
 238  
         }
 239  
 
 240  0
         if (!isDelegation) {
 241  
             // if this is not a delegation template, store the template options that govern rule action constraints
 242  
             // in the RuleTemplateOptions of the template
 243  
             // we have two options for this behavior:
 244  
             // 1) conditionally parse above, and then unconditionally set/unset the properties; this will have the effect of REMOVING
 245  
             //    any of these previously specified rule template options (and is arguably the right thing to do)
 246  
             // 2) unconditionally parse above, and then conditionally set/unset the properties; this will have the effect of PRESERVING
 247  
             //    the existing rule template options on this template if it is a delegation template (which of course will be overwritten
 248  
             //    by this very same code if they subsequently upload without the delegation flag)
 249  
             // This is a minor point, but the second implementation is chosen as it preserved the current behavior
 250  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_DEFAULT_CD, defaultActionRequested);
 251  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_APPROVE_REQ, supportsApprove);
 252  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, supportsAcknowledge);
 253  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_FYI_REQ, supportsFYI);
 254  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_COMPLETE_REQ, supportsComplete);
 255  
         }
 256  
 
 257  0
     }
 258  
     
 259  
     /**
 260  
      * 
 261  
      * Updates the default/template rule options with those in the defaults element
 262  
      * @param defaultsElement the ruleDefaults element
 263  
      * @param updatedRuleTemplate the Rule Template being updated
 264  
      * @return whether this is a delegation rule template
 265  
      */
 266  
     protected boolean updateRuleDefaults(Element defaultsElement, RuleTemplate updatedRuleTemplate) throws XmlException {
 267  
         // NOTE: implementation detail: in contrast with the other options, the delegate template, and the rule attributes,
 268  
         // we unconditionally blow away the default rule and re-create it (we don't update the existing one, if there is one)
 269  0
         if (updatedRuleTemplate.getRuleTemplateId() != null) {
 270  0
             RuleBaseValues ruleDefaults = KEWServiceLocator.getRuleService().findDefaultRuleByRuleTemplateId(updatedRuleTemplate.getRuleTemplateId());
 271  0
             if (ruleDefaults != null) {
 272  0
                 List ruleDelegationDefaults = KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(ruleDefaults.getRuleBaseValuesId());
 273  
                 // delete the rule
 274  0
                 KEWServiceLocator.getRuleService().delete(ruleDefaults.getRuleBaseValuesId());
 275  
                 // delete the associated rule delegation defaults
 276  0
                 for (Iterator iterator = ruleDelegationDefaults.iterator(); iterator.hasNext();) {
 277  0
                     RuleDelegation ruleDelegation = (RuleDelegation) iterator.next();
 278  0
                     KEWServiceLocator.getRuleDelegationService().delete(ruleDelegation.getRuleDelegationId());
 279  0
                 }
 280  
             }
 281  
         }
 282  
 
 283  0
         boolean isDelegation = false;
 284  
 
 285  0
         if (defaultsElement != null) {
 286  0
             String delegationType = defaultsElement.getChildText(DELEGATION_TYPE, RULE_TEMPLATE_NAMESPACE);
 287  0
             isDelegation = !org.apache.commons.lang.StringUtils.isEmpty(delegationType);
 288  
 
 289  0
             String description = defaultsElement.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);
 290  
             
 291  
             // would normally be validated via schema but might not be present if invoking RuleXmlParser directly
 292  0
             if (description == null) {
 293  0
                 throw new XmlException("Description must be specified in rule defaults");
 294  
             }
 295  
             
 296  0
             String fromDate = defaultsElement.getChildText(FROM_DATE, RULE_TEMPLATE_NAMESPACE);
 297  0
             String toDate = defaultsElement.getChildText(TO_DATE, RULE_TEMPLATE_NAMESPACE);
 298  
             // toBooleanObject ensures that if the value is null (not set) that the Boolean object will likewise be null (will not default to a value)
 299  0
             Boolean forceAction = BooleanUtils.toBooleanObject(defaultsElement.getChildText(FORCE_ACTION, RULE_TEMPLATE_NAMESPACE));
 300  0
             Boolean active = BooleanUtils.toBooleanObject(defaultsElement.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE));
 301  
 
 302  0
             if (isDelegation && !DelegationType.PRIMARY.getCode().equals(delegationType) && !DelegationType.SECONDARY.getCode().equals(delegationType)) {
 303  0
                 throw new XmlException("Invalid delegation type '" + delegationType + "'." + "  Expected one of: "
 304  
                         + DelegationType.PRIMARY.getCode() + "," + DelegationType.SECONDARY.getCode());
 305  
             }
 306  
     
 307  
             // create our "default rule" which encapsulates the defaults for the rule
 308  0
             RuleBaseValues ruleDefaults = new RuleBaseValues();
 309  
     
 310  
             // set simple values
 311  0
             ruleDefaults.setRuleTemplate(updatedRuleTemplate);
 312  0
             ruleDefaults.setDocTypeName(DUMMY_DOCUMENT_TYPE);
 313  0
             ruleDefaults.setTemplateRuleInd(Boolean.TRUE);
 314  0
             ruleDefaults.setCurrentInd(Boolean.TRUE);
 315  0
             ruleDefaults.setVersionNbr(new Integer(0));
 316  0
             ruleDefaults.setDescription(description);
 317  
     
 318  
             // these are non-nullable fields, so default them if they were not set in the defaults section
 319  0
             ruleDefaults.setForceAction(Boolean.valueOf(BooleanUtils.isTrue(forceAction)));
 320  0
             ruleDefaults.setActiveInd(Boolean.valueOf(BooleanUtils.isTrue(active)));
 321  
         
 322  0
             if (ruleDefaults.getActivationDate() == null) {
 323  0
                 ruleDefaults.setActivationDate(new Timestamp(System.currentTimeMillis()));
 324  
             }
 325  
     
 326  0
             ruleDefaults.setFromDate(formatDate("fromDate",fromDate));
 327  0
             ruleDefaults.setToDate(formatDate("toDate", toDate));
 328  
             
 329  
             // ok, if this is a "Delegate Template", then we need to set this other RuleDelegation object which contains
 330  
             // some delegation-related info
 331  0
             RuleDelegation ruleDelegationDefaults = null;
 332  0
             if (isDelegation) {
 333  0
                 ruleDelegationDefaults = new RuleDelegation();
 334  0
                 ruleDelegationDefaults.setDelegationRuleBaseValues(ruleDefaults);
 335  0
                 ruleDelegationDefaults.setDelegationType(delegationType);
 336  0
                 ruleDelegationDefaults.setResponsibilityId(KEWConstants.ADHOC_REQUEST_RESPONSIBILITY_ID);
 337  
             }
 338  
 
 339  
             // explicitly save the new rule delegation defaults and default rule
 340  0
             KEWServiceLocator.getRuleTemplateService().saveRuleDefaults(ruleDelegationDefaults, ruleDefaults);
 341  
         } else {
 342  
             // do nothing, rule defaults will be deleted if ruleDefaults element is omitted
 343  
         }
 344  
         
 345  0
         return isDelegation;
 346  
     }
 347  
 
 348  
 
 349  
     /**
 350  
      * Updates or deletes a specified rule template option on the rule template
 351  
      * @param updatedRuleTemplate the RuleTemplate being updated
 352  
      * @param key the option key
 353  
      * @param value the option value
 354  
      */
 355  
     protected void updateOrDeleteRuleTemplateOption(RuleTemplate updatedRuleTemplate, String key, Object value) {
 356  0
         if (value != null) {
 357  
             // if the option exists and the incoming value is non-null (it's set), update it
 358  0
             RuleTemplateOption option = updatedRuleTemplate.getRuleTemplateOption(key);
 359  0
             if (option != null) {
 360  0
                 option.setValue(value.toString());
 361  
             } else {
 362  0
                 updatedRuleTemplate.getRuleTemplateOptions().add(new RuleTemplateOption(key, value.toString()));
 363  
             }
 364  0
         } else {
 365  
             // otherwise if the incoming value IS null (not set), then explicitly remove the entry (if it exists)
 366  0
             Iterator<RuleTemplateOption> options = updatedRuleTemplate.getRuleTemplateOptions().iterator();
 367  0
             while (options.hasNext()) {
 368  0
                 RuleTemplateOption opt = options.next();
 369  0
                 if (key.equals(opt.getKey())) {
 370  0
                     options.remove();
 371  0
                     break;
 372  
                 }
 373  0
             }
 374  
         }
 375  0
     }
 376  
 
 377  
     /**
 378  
      * Updates the rule template delegation template with the one specified in the XML (if any)
 379  
      * @param ruleTemplateElement the XML ruleTemplate element
 380  
      * @param updatedRuleTemplate the rule template to update
 381  
      * @param parsedRuleTemplates the rule templates parsed in this parsing run
 382  
      * @throws XmlException if a delegation template was specified but could not be found
 383  
      */
 384  
     protected void updateDelegationTemplate(Element ruleTemplateElement, RuleTemplate updatedRuleTemplate, List<RuleTemplate> parsedRuleTemplates) throws XmlException {
 385  0
         String delegateTemplateName = ruleTemplateElement.getChildText(DELEGATION_TEMPLATE, RULE_TEMPLATE_NAMESPACE);
 386  
 
 387  0
         if (delegateTemplateName != null) {
 388  
             // if a delegateTemplate was set in the XML, then look it up and set it on the RuleTemplate object
 389  
             // first try looking up an existing delegateTemplate in the system
 390  0
             RuleTemplate delegateTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(delegateTemplateName);
 391  
 
 392  
             // if not found, try the list of templates currently parsed
 393  0
             if (delegateTemplate == null) {
 394  0
                 for (RuleTemplate rt: parsedRuleTemplates) {
 395  0
                     if (delegateTemplateName.equalsIgnoreCase(rt.getName())) {
 396  
                         // set the expected next rule template id on the target delegateTemplate
 397  0
                             String ruleTemplateId = KEWServiceLocator.getRuleTemplateService().getNextRuleTemplateId();
 398  0
                         rt.setRuleTemplateId(ruleTemplateId);
 399  0
                         delegateTemplate = rt;
 400  0
                         break;
 401  
                     }
 402  
                 }
 403  
             }
 404  
 
 405  0
             if (delegateTemplate == null) {
 406  0
                 throw new XmlException("Cannot find delegation template " + delegateTemplateName);
 407  
             }
 408  
 
 409  0
             updatedRuleTemplate.setDelegationTemplateId(delegateTemplate.getDelegationTemplateId());
 410  0
             updatedRuleTemplate.setDelegationTemplate(delegateTemplate);           
 411  
         } else {
 412  
             // the previously referenced template is left in the system
 413  
         }
 414  0
     }
 415  
 
 416  
     /**
 417  
      * Updates the attributes set on the RuleTemplate
 418  
      * @param ruleTemplateElement the XML ruleTemplate element
 419  
      * @param updatedRuleTemplate the RuleTemplate being updated
 420  
      * @throws XmlException if there was a problem parsing the rule template attributes
 421  
      */
 422  
     protected void updateRuleTemplateAttributes(Element ruleTemplateElement, RuleTemplate updatedRuleTemplate) throws XmlException {
 423  
         // add any newly defined rule template attributes to the rule template,
 424  
         // update the active and required flags of any existing ones.
 425  
         // if this is an update of an existing rule template, related attribute objects will be present in this rule template object,
 426  
         // otherwise none will be present (so they'll all be new)
 427  
 
 428  0
         Element attributesElement = ruleTemplateElement.getChild(ATTRIBUTES, RULE_TEMPLATE_NAMESPACE);
 429  0
         List<RuleTemplateAttribute> incomingAttributes = new ArrayList<RuleTemplateAttribute>();
 430  0
         if (attributesElement != null) {
 431  0
             incomingAttributes.addAll(parseRuleTemplateAttributes(attributesElement, updatedRuleTemplate));
 432  
         }
 433  
 
 434  
         // inactivate all current attributes
 435  0
         for (RuleTemplateAttribute currentRuleTemplateAttribute: updatedRuleTemplate.getRuleTemplateAttributes()) {
 436  0
             String ruleAttributeName = (currentRuleTemplateAttribute.getRuleAttribute() != null) ? currentRuleTemplateAttribute.getRuleAttribute().getName() : "(null)";
 437  0
             LOG.debug("Inactivating rule template attribute with id " + currentRuleTemplateAttribute.getRuleTemplateAttributeId() + " and rule attribute with name " + ruleAttributeName);
 438  0
             currentRuleTemplateAttribute.setActive(Boolean.FALSE);
 439  0
         }
 440  
         // NOTE: attributes are deactivated, not removed
 441  
 
 442  
         // add/update any new attributes
 443  0
         for (RuleTemplateAttribute ruleTemplateAttribute: incomingAttributes) {
 444  0
             RuleTemplateAttribute potentialExistingTemplateAttribute = updatedRuleTemplate.getRuleTemplateAttribute(ruleTemplateAttribute);
 445  0
             if (potentialExistingTemplateAttribute != null) {
 446  
                 // template attribute exists on rule template already; update the options
 447  0
                 potentialExistingTemplateAttribute.setActive(ruleTemplateAttribute.getActive());
 448  0
                 potentialExistingTemplateAttribute.setRequired(ruleTemplateAttribute.getRequired());
 449  
             } else {
 450  
                 // template attribute does not yet exist on template so add it
 451  0
                 updatedRuleTemplate.getRuleTemplateAttributes().add(ruleTemplateAttribute);
 452  
             }
 453  0
         }
 454  0
     }
 455  
 
 456  
     /**
 457  
      * Parses the RuleTemplateAttributes defined on the rule template element
 458  
      * @param attributesElement the jdom Element object for the Rule Template attributes
 459  
      * @param ruleTemplate the RuleTemplate object
 460  
      * @return the RuleTemplateAttributes defined on the rule template element
 461  
      * @throws XmlException
 462  
      */
 463  
     private List<RuleTemplateAttribute> parseRuleTemplateAttributes(Element attributesElement, RuleTemplate ruleTemplate) throws XmlException {
 464  0
         List<RuleTemplateAttribute> ruleTemplateAttributes = new ArrayList<RuleTemplateAttribute>();
 465  0
         Collection<Element> attributeElements = XmlHelper.findElements(attributesElement, ATTRIBUTE);
 466  0
         for (Iterator iterator = attributeElements.iterator(); iterator.hasNext();) {
 467  0
             ruleTemplateAttributes.add(parseRuleTemplateAttribute((Element) iterator.next(), ruleTemplate));
 468  
         }
 469  0
         return ruleTemplateAttributes;
 470  
     }
 471  
 
 472  
     /**
 473  
      * Parses a rule template attribute
 474  
      * @param element the attribute XML element
 475  
      * @param ruleTemplate the ruleTemplate to update
 476  
      * @return a parsed rule template attribute
 477  
      * @throws XmlException if the attribute does not exist
 478  
      */
 479  
     private RuleTemplateAttribute parseRuleTemplateAttribute(Element element, RuleTemplate ruleTemplate) throws XmlException {
 480  0
         String attributeName = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
 481  0
         String requiredValue = element.getChildText(REQUIRED, RULE_TEMPLATE_NAMESPACE);
 482  0
         String activeValue = element.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE);
 483  0
         if (org.apache.commons.lang.StringUtils.isEmpty(attributeName)) {
 484  0
             throw new XmlException("Attribute name must be non-empty");
 485  
         }
 486  0
         boolean required = DEFAULT_ATTRIBUTE_REQUIRED;
 487  0
         if (requiredValue != null) {
 488  0
             required = Boolean.parseBoolean(requiredValue);
 489  
         }
 490  0
         boolean active = DEFAULT_ATTRIBUTE_ACTIVE;
 491  0
         if (activeValue != null) {
 492  0
             active = Boolean.parseBoolean(activeValue);
 493  
         }
 494  0
         RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(attributeName);
 495  0
         if (ruleAttribute == null) {
 496  0
             throw new XmlException("Could not locate rule attribute for name '" + attributeName + "'");
 497  
         }
 498  0
         RuleTemplateAttribute templateAttribute = new RuleTemplateAttribute();
 499  0
         templateAttribute.setRuleAttribute(ruleAttribute);
 500  0
         templateAttribute.setRuleAttributeId(ruleAttribute.getRuleAttributeId());
 501  0
         templateAttribute.setRuleTemplate(ruleTemplate);
 502  0
         templateAttribute.setRequired(Boolean.valueOf(required));
 503  0
         templateAttribute.setActive(Boolean.valueOf(active));
 504  0
         templateAttribute.setDisplayOrder(new Integer(templateAttributeCounter++));
 505  0
         return templateAttribute;
 506  
     }
 507  
     
 508  
     public Timestamp formatDate(String dateLabel, String dateString) throws XmlException {
 509  0
             if (StringUtils.isBlank(dateString)) {
 510  0
                     return null;
 511  
             }
 512  
             try {
 513  0
                     return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
 514  0
             } catch (ParseException e) {
 515  0
                     throw new XmlException(dateLabel + " is not in the proper format.  Should have been: " + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
 516  
             }
 517  
     }
 518  
 
 519  
 }