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 org.apache.commons.lang.BooleanUtils;
 20  
 import org.apache.commons.lang.StringUtils;
 21  
 import org.jdom.Attribute;
 22  
 import org.jdom.Document;
 23  
 import org.jdom.Element;
 24  
 import org.jdom.JDOMException;
 25  
 import org.kuali.rice.core.util.RiceConstants;
 26  
 import org.kuali.rice.core.util.xml.XmlException;
 27  
 import org.kuali.rice.core.util.xml.XmlHelper;
 28  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 29  
 import org.kuali.rice.kew.rule.RuleDelegation;
 30  
 import org.kuali.rice.kew.rule.RuleTemplateOption;
 31  
 import org.kuali.rice.kew.rule.bo.RuleAttribute;
 32  
 import org.kuali.rice.kew.rule.bo.RuleTemplate;
 33  
 import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
 34  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 35  
 import org.kuali.rice.kew.util.KEWConstants;
 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 RuleTemplate}s from XML.
 51  
  *
 52  
  * @see RuleTemplate
 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<RuleTemplate> 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<RuleTemplate> parseRuleTemplates(Element element) throws XmlException {
 92  0
         List<RuleTemplate> ruleTemplates = new ArrayList<RuleTemplate>();
 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 RuleTemplate parseRuleTemplate(Element element, List<RuleTemplate> 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
         RuleTemplate 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 RuleTemplate();
 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, RuleTemplate 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, RuleTemplate 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, KEWConstants.ACTION_REQUEST_DEFAULT_CD, defaultActionRequested);
 230  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_APPROVE_REQ, supportsApprove);
 231  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, supportsAcknowledge);
 232  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.ACTION_REQUEST_FYI_REQ, supportsFYI);
 233  0
             updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KEWConstants.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, RuleTemplate 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.getRuleTemplateId() != null) {
 249  0
             RuleBaseValues ruleDefaults = KEWServiceLocator.getRuleService().findDefaultRuleByRuleTemplateId(updatedRuleTemplate.getRuleTemplateId());
 250  0
             if (ruleDefaults != null) {
 251  0
                 List ruleDelegationDefaults = KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(ruleDefaults.getRuleBaseValuesId());
 252  
                 // delete the rule
 253  0
                 KEWServiceLocator.getRuleService().delete(ruleDefaults.getRuleBaseValuesId());
 254  
                 // delete the associated rule delegation defaults
 255  0
                 for (Iterator iterator = ruleDelegationDefaults.iterator(); iterator.hasNext();) {
 256  0
                     RuleDelegation ruleDelegation = (RuleDelegation) 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 delegationType = defaultsElement.getChildText(DELEGATION_TYPE, RULE_TEMPLATE_NAMESPACE);
 266  0
             isDelegation = !org.apache.commons.lang.StringUtils.isEmpty(delegationType);
 267  
 
 268  0
             String description = defaultsElement.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);
 269  
             
 270  
             // would normally be validated via schema but might not be present if invoking RuleXmlParser directly
 271  0
             if (description == null) {
 272  0
                 throw new XmlException("Description must be specified in rule defaults");
 273  
             }
 274  
             
 275  0
             String fromDate = defaultsElement.getChildText(FROM_DATE, RULE_TEMPLATE_NAMESPACE);
 276  0
             String toDate = defaultsElement.getChildText(TO_DATE, RULE_TEMPLATE_NAMESPACE);
 277  
             // toBooleanObject ensures that if the value is null (not set) that the Boolean object will likewise be null (will not default to a value)
 278  0
             Boolean forceAction = BooleanUtils.toBooleanObject(defaultsElement.getChildText(FORCE_ACTION, RULE_TEMPLATE_NAMESPACE));
 279  0
             Boolean active = BooleanUtils.toBooleanObject(defaultsElement.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE));
 280  
 
 281  0
             if (isDelegation && !KEWConstants.DELEGATION_PRIMARY.equals(delegationType) && !KEWConstants.DELEGATION_SECONDARY.equals(delegationType)) {
 282  0
                 throw new XmlException("Invalid delegation type '" + delegationType + "'." + "  Expected one of: "
 283  
                         + KEWConstants.DELEGATION_PRIMARY + "," + KEWConstants.DELEGATION_SECONDARY);
 284  
             }
 285  
     
 286  
             // create our "default rule" which encapsulates the defaults for the rule
 287  0
             RuleBaseValues ruleDefaults = new RuleBaseValues();
 288  
     
 289  
             // set simple values
 290  0
             ruleDefaults.setRuleTemplate(updatedRuleTemplate);
 291  0
             ruleDefaults.setDocTypeName(DUMMY_DOCUMENT_TYPE);
 292  0
             ruleDefaults.setTemplateRuleInd(Boolean.TRUE);
 293  0
             ruleDefaults.setCurrentInd(Boolean.TRUE);
 294  0
             ruleDefaults.setVersionNbr(new Integer(0));
 295  0
             ruleDefaults.setDescription(description);
 296  
     
 297  
             // these are non-nullable fields, so default them if they were not set in the defaults section
 298  0
             ruleDefaults.setForceAction(Boolean.valueOf(BooleanUtils.isTrue(forceAction)));
 299  0
             ruleDefaults.setActiveInd(Boolean.valueOf(BooleanUtils.isTrue(active)));
 300  
         
 301  0
             if (ruleDefaults.getActivationDate() == null) {
 302  0
                 ruleDefaults.setActivationDate(new Timestamp(System.currentTimeMillis()));
 303  
             }
 304  
     
 305  0
             ruleDefaults.setFromDate(formatDate("fromDate",fromDate));
 306  0
             ruleDefaults.setToDate(formatDate("toDate", toDate));
 307  
             
 308  
             // ok, if this is a "Delegate Template", then we need to set this other RuleDelegation object which contains
 309  
             // some delegation-related info
 310  0
             RuleDelegation ruleDelegationDefaults = null;
 311  0
             if (isDelegation) {
 312  0
                 ruleDelegationDefaults = new RuleDelegation();
 313  0
                 ruleDelegationDefaults.setDelegationRuleBaseValues(ruleDefaults);
 314  0
                 ruleDelegationDefaults.setDelegationType(delegationType);
 315  0
                 ruleDelegationDefaults.setResponsibilityId(new Long(-1));
 316  
             }
 317  
 
 318  
             // explicitly save the new rule delegation defaults and default rule
 319  0
             KEWServiceLocator.getRuleTemplateService().saveRuleDefaults(ruleDelegationDefaults, ruleDefaults);
 320  
         } else {
 321  
             // do nothing, rule defaults will be deleted if ruleDefaults element is omitted
 322  
         }
 323  
         
 324  0
         return isDelegation;
 325  
     }
 326  
 
 327  
 
 328  
     /**
 329  
      * Updates or deletes a specified rule template option on the rule template
 330  
      * @param updatedRuleTemplate the RuleTemplate being updated
 331  
      * @param key the option key
 332  
      * @param value the option value
 333  
      */
 334  
     protected void updateOrDeleteRuleTemplateOption(RuleTemplate updatedRuleTemplate, String key, Object value) {
 335  0
         if (value != null) {
 336  
             // if the option exists and the incoming value is non-null (it's set), update it
 337  0
             RuleTemplateOption option = updatedRuleTemplate.getRuleTemplateOption(key);
 338  0
             if (option != null) {
 339  0
                 option.setValue(value.toString());
 340  
             } else {
 341  0
                 updatedRuleTemplate.getRuleTemplateOptions().add(new RuleTemplateOption(key, value.toString()));
 342  
             }
 343  0
         } else {
 344  
             // otherwise if the incoming value IS null (not set), then explicitly remove the entry (if it exists)
 345  0
             Iterator<RuleTemplateOption> options = updatedRuleTemplate.getRuleTemplateOptions().iterator();
 346  0
             while (options.hasNext()) {
 347  0
                 RuleTemplateOption opt = options.next();
 348  0
                 if (key.equals(opt.getKey())) {
 349  0
                     options.remove();
 350  0
                     break;
 351  
                 }
 352  0
             }
 353  
         }
 354  0
     }
 355  
 
 356  
     /**
 357  
      * Updates the rule template delegation template with the one specified in the XML (if any)
 358  
      * @param ruleTemplateElement the XML ruleTemplate element
 359  
      * @param updatedRuleTemplate the rule template to update
 360  
      * @param parsedRuleTemplates the rule templates parsed in this parsing run
 361  
      * @throws XmlException if a delegation template was specified but could not be found
 362  
      */
 363  
     protected void updateDelegationTemplate(Element ruleTemplateElement, RuleTemplate updatedRuleTemplate, List<RuleTemplate> parsedRuleTemplates) throws XmlException {
 364  0
         String delegateTemplateName = ruleTemplateElement.getChildText(DELEGATION_TEMPLATE, RULE_TEMPLATE_NAMESPACE);
 365  
 
 366  0
         if (delegateTemplateName != null) {
 367  
             // if a delegateTemplate was set in the XML, then look it up and set it on the RuleTemplate object
 368  
             // first try looking up an existing delegateTemplate in the system
 369  0
             RuleTemplate delegateTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(delegateTemplateName);
 370  
 
 371  
             // if not found, try the list of templates currently parsed
 372  0
             if (delegateTemplate == null) {
 373  0
                 for (RuleTemplate rt: parsedRuleTemplates) {
 374  0
                     if (delegateTemplateName.equalsIgnoreCase(rt.getName())) {
 375  
                         // set the expected next rule template id on the target delegateTemplate
 376  0
                         Long ruleTemplateId = KEWServiceLocator.getRuleTemplateService().getNextRuleTemplateId();
 377  0
                         rt.setRuleTemplateId(ruleTemplateId);
 378  0
                         delegateTemplate = rt;
 379  0
                         break;
 380  
                     }
 381  
                 }
 382  
             }
 383  
 
 384  0
             if (delegateTemplate == null) {
 385  0
                 throw new XmlException("Cannot find delegation template " + delegateTemplateName);
 386  
             }
 387  
 
 388  0
             updatedRuleTemplate.setDelegationTemplateId(delegateTemplate.getDelegationTemplateId());
 389  0
             updatedRuleTemplate.setDelegationTemplate(delegateTemplate);           
 390  
         } else {
 391  
             // the previously referenced template is left in the system
 392  
         }
 393  0
     }
 394  
 
 395  
     /**
 396  
      * Updates the attributes set on the RuleTemplate
 397  
      * @param ruleTemplateElement the XML ruleTemplate element
 398  
      * @param updatedRuleTemplate the RuleTemplate being updated
 399  
      * @throws XmlException if there was a problem parsing the rule template attributes
 400  
      */
 401  
     protected void updateRuleTemplateAttributes(Element ruleTemplateElement, RuleTemplate updatedRuleTemplate) throws XmlException {
 402  
         // add any newly defined rule template attributes to the rule template,
 403  
         // update the active and required flags of any existing ones.
 404  
         // if this is an update of an existing rule template, related attribute objects will be present in this rule template object,
 405  
         // otherwise none will be present (so they'll all be new)
 406  
 
 407  0
         Element attributesElement = ruleTemplateElement.getChild(ATTRIBUTES, RULE_TEMPLATE_NAMESPACE);
 408  0
         List<RuleTemplateAttribute> incomingAttributes = new ArrayList<RuleTemplateAttribute>();
 409  0
         if (attributesElement != null) {
 410  0
             incomingAttributes.addAll(parseRuleTemplateAttributes(attributesElement, updatedRuleTemplate));
 411  
         }
 412  
 
 413  
         // inactivate all current attributes
 414  0
         for (RuleTemplateAttribute currentRuleTemplateAttribute: updatedRuleTemplate.getRuleTemplateAttributes()) {
 415  0
             String ruleAttributeName = (currentRuleTemplateAttribute.getRuleAttribute() != null) ? currentRuleTemplateAttribute.getRuleAttribute().getName() : "(null)";
 416  0
             LOG.debug("Inactivating rule template attribute with id " + currentRuleTemplateAttribute.getRuleTemplateAttributeId() + " and rule attribute with name " + ruleAttributeName);
 417  0
             currentRuleTemplateAttribute.setActive(Boolean.FALSE);
 418  0
         }
 419  
         // NOTE: attributes are deactivated, not removed
 420  
 
 421  
         // add/update any new attributes
 422  0
         for (RuleTemplateAttribute ruleTemplateAttribute: incomingAttributes) {
 423  0
             RuleTemplateAttribute potentialExistingTemplateAttribute = updatedRuleTemplate.getRuleTemplateAttribute(ruleTemplateAttribute);
 424  0
             if (potentialExistingTemplateAttribute != null) {
 425  
                 // template attribute exists on rule template already; update the options
 426  0
                 potentialExistingTemplateAttribute.setActive(ruleTemplateAttribute.getActive());
 427  0
                 potentialExistingTemplateAttribute.setRequired(ruleTemplateAttribute.getRequired());
 428  
             } else {
 429  
                 // template attribute does not yet exist on template so add it
 430  0
                 updatedRuleTemplate.getRuleTemplateAttributes().add(ruleTemplateAttribute);
 431  
             }
 432  0
         }
 433  0
     }
 434  
 
 435  
     /**
 436  
      * Parses the RuleTemplateAttributes defined on the rule template element
 437  
      * @param attributesElement the jdom Element object for the Rule Template attributes
 438  
      * @param ruleTemplate the RuleTemplate object
 439  
      * @return the RuleTemplateAttributes defined on the rule template element
 440  
      * @throws XmlException
 441  
      */
 442  
     private List<RuleTemplateAttribute> parseRuleTemplateAttributes(Element attributesElement, RuleTemplate ruleTemplate) throws XmlException {
 443  0
         List<RuleTemplateAttribute> ruleTemplateAttributes = new ArrayList<RuleTemplateAttribute>();
 444  0
         Collection<Element> attributeElements = XmlHelper.findElements(attributesElement, ATTRIBUTE);
 445  0
         for (Iterator iterator = attributeElements.iterator(); iterator.hasNext();) {
 446  0
             ruleTemplateAttributes.add(parseRuleTemplateAttribute((Element) iterator.next(), ruleTemplate));
 447  
         }
 448  0
         return ruleTemplateAttributes;
 449  
     }
 450  
 
 451  
     /**
 452  
      * Parses a rule template attribute
 453  
      * @param element the attribute XML element
 454  
      * @param ruleTemplate the ruleTemplate to update
 455  
      * @return a parsed rule template attribute
 456  
      * @throws XmlException if the attribute does not exist
 457  
      */
 458  
     private RuleTemplateAttribute parseRuleTemplateAttribute(Element element, RuleTemplate ruleTemplate) throws XmlException {
 459  0
         String attributeName = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
 460  0
         String requiredValue = element.getChildText(REQUIRED, RULE_TEMPLATE_NAMESPACE);
 461  0
         String activeValue = element.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE);
 462  0
         if (org.apache.commons.lang.StringUtils.isEmpty(attributeName)) {
 463  0
             throw new XmlException("Attribute name must be non-empty");
 464  
         }
 465  0
         boolean required = DEFAULT_ATTRIBUTE_REQUIRED;
 466  0
         if (requiredValue != null) {
 467  0
             required = Boolean.parseBoolean(requiredValue);
 468  
         }
 469  0
         boolean active = DEFAULT_ATTRIBUTE_ACTIVE;
 470  0
         if (activeValue != null) {
 471  0
             active = Boolean.parseBoolean(activeValue);
 472  
         }
 473  0
         RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(attributeName);
 474  0
         if (ruleAttribute == null) {
 475  0
             throw new XmlException("Could not locate rule attribute for name '" + attributeName + "'");
 476  
         }
 477  0
         RuleTemplateAttribute templateAttribute = new RuleTemplateAttribute();
 478  0
         templateAttribute.setRuleAttribute(ruleAttribute);
 479  0
         templateAttribute.setRuleAttributeId(ruleAttribute.getRuleAttributeId());
 480  0
         templateAttribute.setRuleTemplate(ruleTemplate);
 481  0
         templateAttribute.setRequired(Boolean.valueOf(required));
 482  0
         templateAttribute.setActive(Boolean.valueOf(active));
 483  0
         templateAttribute.setDisplayOrder(new Integer(templateAttributeCounter++));
 484  0
         return templateAttribute;
 485  
     }
 486  
     
 487  
     public Timestamp formatDate(String dateLabel, String dateString) throws XmlException {
 488  0
             if (StringUtils.isBlank(dateString)) {
 489  0
                     return null;
 490  
             }
 491  
             try {
 492  0
                     return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
 493  0
             } catch (ParseException e) {
 494  0
                     throw new XmlException(dateLabel + " is not in the proper format.  Should have been: " + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
 495  
             }
 496  
     }
 497  
 
 498  
 }