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