private RuleDelegationBo getDefaultDelegationValues(RuleBaseValues defaultRuleValues) {
   List ruleDelegations =
       KEWServiceLocator.getRuleDelegationService()
           .findByDelegateRuleId(defaultRuleValues.getId());
   if (ruleDelegations.size() > 1) {
     LOG.warn("The rule defaults has more than one associated delegation defaults.");
   }
   return (ruleDelegations.isEmpty() ? null : (RuleDelegationBo) ruleDelegations.get(0));
 }
  /**
   * Updates the attributes set on the RuleTemplate
   *
   * @param ruleTemplateElement the XML ruleTemplate element
   * @param updatedRuleTemplate the RuleTemplate being updated
   * @throws XmlException if there was a problem parsing the rule template attributes
   */
  protected void updateRuleTemplateAttributes(
      Element ruleTemplateElement, RuleTemplateBo updatedRuleTemplate) throws XmlException {
    // add any newly defined rule template attributes to the rule template,
    // update the active and required flags of any existing ones.
    // if this is an update of an existing rule template, related attribute objects will be present
    // in this rule template object,
    // otherwise none will be present (so they'll all be new)

    Element attributesElement = ruleTemplateElement.getChild(ATTRIBUTES, RULE_TEMPLATE_NAMESPACE);
    List<RuleTemplateAttributeBo> incomingAttributes = new ArrayList<RuleTemplateAttributeBo>();
    if (attributesElement != null) {
      incomingAttributes.addAll(
          parseRuleTemplateAttributes(attributesElement, updatedRuleTemplate));
    }

    // inactivate all current attributes
    for (RuleTemplateAttributeBo currentRuleTemplateAttribute :
        updatedRuleTemplate.getRuleTemplateAttributes()) {
      String ruleAttributeName =
          (currentRuleTemplateAttribute.getRuleAttribute() != null)
              ? currentRuleTemplateAttribute.getRuleAttribute().getName()
              : "(null)";
      LOG.debug(
          "Inactivating rule template attribute with id "
              + currentRuleTemplateAttribute.getId()
              + " and rule attribute with name "
              + ruleAttributeName);
      currentRuleTemplateAttribute.setActive(Boolean.FALSE);
    }
    // NOTE: attributes are deactivated, not removed

    // add/update any new attributes
    for (RuleTemplateAttributeBo ruleTemplateAttribute : incomingAttributes) {
      RuleTemplateAttributeBo potentialExistingTemplateAttribute =
          updatedRuleTemplate.getRuleTemplateAttribute(ruleTemplateAttribute);
      if (potentialExistingTemplateAttribute != null) {
        // template attribute exists on rule template already; update the options
        potentialExistingTemplateAttribute.setActive(ruleTemplateAttribute.getActive());
        potentialExistingTemplateAttribute.setRequired(ruleTemplateAttribute.getRequired());
      } else {
        // template attribute does not yet exist on template so add it
        ruleTemplateAttribute.setRuleTemplate(updatedRuleTemplate);
        updatedRuleTemplate.getRuleTemplateAttributes().add(ruleTemplateAttribute);
      }
    }
  }
/**
 * Exports {@link org.kuali.rice.kew.rule.bo.RuleTemplateBo}s to XML.
 *
 * @see org.kuali.rice.kew.rule.bo.RuleTemplateBo
 * @author Kuali Rice Team ([email protected])
 */
public class RuleTemplateXmlExporter implements XmlExporter {

  protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(getClass());

  private XmlRenderer renderer = new XmlRenderer(RULE_TEMPLATE_NAMESPACE);

  @Override
  public boolean supportPrettyPrint() {
    return true;
  }

  public Element export(ExportDataSet exportDataSet) {
    KewExportDataSet dataSet = KewExportDataSet.fromExportDataSet(exportDataSet);
    if (!dataSet.getRuleTemplates().isEmpty()) {
      Element rootElement = renderer.renderElement(null, RULE_TEMPLATES);
      rootElement.setAttribute(
          SCHEMA_LOCATION_ATTR, RULE_TEMPLATE_SCHEMA_LOCATION, SCHEMA_NAMESPACE);
      for (Iterator iterator = dataSet.getRuleTemplates().iterator(); iterator.hasNext(); ) {
        RuleTemplateBo template = (RuleTemplateBo) iterator.next();
        exportRuleTemplate(rootElement, template);
      }
      return rootElement;
    }
    return null;
  }

  private void exportRuleTemplate(Element parent, RuleTemplateBo ruleTemplate) {
    Element templateElement = renderer.renderElement(parent, RULE_TEMPLATE);
    renderer.renderTextElement(templateElement, NAME, ruleTemplate.getName());
    renderer.renderTextElement(templateElement, DESCRIPTION, ruleTemplate.getDescription());
    if (ruleTemplate.getDelegationTemplate() != null) {
      renderer.renderTextElement(
          templateElement, DELEGATION_TEMPLATE, ruleTemplate.getDelegationTemplate().getName());
    }
    exportAttributes(templateElement, ruleTemplate.getActiveRuleTemplateAttributes());
    exportDefaults(templateElement, ruleTemplate);
  }

  private void exportAttributes(Element parent, List ruleTemplateAttributes) {
    if (!ruleTemplateAttributes.isEmpty()) {
      Element attributesElement = renderer.renderElement(parent, ATTRIBUTES);
      for (Iterator iterator = ruleTemplateAttributes.iterator(); iterator.hasNext(); ) {
        RuleTemplateAttributeBo attribute = (RuleTemplateAttributeBo) iterator.next();
        Element attributeElement = renderer.renderElement(attributesElement, ATTRIBUTE);
        renderer.renderTextElement(attributeElement, NAME, attribute.getRuleAttribute().getName());
        renderer.renderBooleanElement(attributeElement, REQUIRED, attribute.getRequired(), false);
      }
    }
  }

  private void exportDefaults(Element parent, RuleTemplateBo ruleTemplate) {
    RuleBaseValues defaultRuleValues =
        KEWServiceLocator.getRuleService().findDefaultRuleByRuleTemplateId(ruleTemplate.getId());
    if (defaultRuleValues != null) {
      RuleDelegationBo defaultDelegationValues = getDefaultDelegationValues(defaultRuleValues);
      Element defaultsElement = renderer.renderElement(parent, RULE_DEFAULTS);
      if (defaultDelegationValues != null) {
        renderer.renderTextElement(
            defaultsElement,
            DELEGATION_TYPE,
            defaultDelegationValues.getDelegationType().getCode());
      }
      renderer.renderTextElement(defaultsElement, DESCRIPTION, defaultRuleValues.getDescription());
      if (defaultRuleValues.getFromDateValue() != null) {
        renderer.renderDateElement(
            defaultsElement, FROM_DATE, defaultRuleValues.getFromDateValue());
      }
      if (defaultRuleValues.getToDateValue() != null) {
        renderer.renderDateElement(defaultsElement, TO_DATE, defaultRuleValues.getToDateValue());
      }
      renderer.renderBooleanElement(
          defaultsElement, FORCE_ACTION, defaultRuleValues.isForceAction(), false);
      renderer.renderBooleanElement(defaultsElement, ACTIVE, defaultRuleValues.isActive(), true);
      if (defaultDelegationValues == null) {
        RuleTemplateOptionBo defaultActionOption = ruleTemplate.getDefaultActionRequestValue();
        RuleTemplateOptionBo supportsComplete = ruleTemplate.getComplete();
        RuleTemplateOptionBo supportsApprove = ruleTemplate.getApprove();
        RuleTemplateOptionBo supportsAck = ruleTemplate.getAcknowledge();
        RuleTemplateOptionBo supportsFYI = ruleTemplate.getFyi();
        if (defaultActionOption != null) {
          String defaultActionValue =
              (defaultActionOption == null ? null : defaultActionOption.getValue());
          renderer.renderTextElement(defaultsElement, DEFAULT_ACTION_REQUESTED, defaultActionValue);
        }
        if (supportsComplete != null) {
          String supportsCompleteValue = supportsComplete.getValue();
          renderer.renderTextElement(defaultsElement, SUPPORTS_COMPLETE, supportsCompleteValue);
        }
        if (supportsApprove != null) {
          String supportsApproveValue = supportsApprove.getValue();
          renderer.renderTextElement(defaultsElement, SUPPORTS_APPROVE, supportsApproveValue);
        }
        if (supportsAck != null) {
          String supportsAckValue = supportsAck.getValue();
          renderer.renderTextElement(defaultsElement, SUPPORTS_ACKNOWLEDGE, supportsAckValue);
        }
        if (supportsFYI != null) {
          String supportsFYIValue = supportsFYI.getValue();
          renderer.renderTextElement(defaultsElement, SUPPORTS_FYI, supportsFYIValue);
        }
      }
    }
  }

  private RuleDelegationBo getDefaultDelegationValues(RuleBaseValues defaultRuleValues) {
    List ruleDelegations =
        KEWServiceLocator.getRuleDelegationService()
            .findByDelegateRuleId(defaultRuleValues.getId());
    if (ruleDelegations.size() > 1) {
      LOG.warn("The rule defaults has more than one associated delegation defaults.");
    }
    return (ruleDelegations.isEmpty() ? null : (RuleDelegationBo) ruleDelegations.get(0));
  }
}
/**
 * Parses {@link org.kuali.rice.kew.rule.bo.RuleTemplateBo}s from XML.
 *
 * @see org.kuali.rice.kew.rule.bo.RuleTemplateBo
 * @author Kuali Rice Team ([email protected])
 */
public class RuleTemplateXmlParser {

  private static final org.apache.log4j.Logger LOG =
      org.apache.log4j.Logger.getLogger(RuleTemplateXmlParser.class);

  /** By default make attributes defined without a &lt;required&gt; element */
  private static final boolean DEFAULT_ATTRIBUTE_REQUIRED = true;

  private static final boolean DEFAULT_ATTRIBUTE_ACTIVE = true;

  /** A dummy document type used in the default rule */
  private static final String DUMMY_DOCUMENT_TYPE = "dummyDocumentType";

  /**
   * Used to set the display order of attributes encountered in parsing runs during the lifetime of
   * this object
   */
  private int templateAttributeCounter = 0;

  public List<RuleTemplateBo> parseRuleTemplates(InputStream input)
      throws IOException, XmlException {

    try {
      Document doc = XmlHelper.trimSAXXml(input);
      Element root = doc.getRootElement();
      return parseRuleTemplates(root);
    } catch (JDOMException e) {
      throw new XmlException("Parse error.", e);
    } catch (SAXException e) {
      throw new XmlException("Parse error.", e);
    } catch (ParserConfigurationException e) {
      throw new XmlException("Parse error.", e);
    }
  }

  public List<RuleTemplateBo> parseRuleTemplates(Element element) throws XmlException {
    List<RuleTemplateBo> ruleTemplates = new ArrayList<RuleTemplateBo>();

    // iterate over any RULE_TEMPLATES elements
    Collection<Element> ruleTemplatesElements = XmlHelper.findElements(element, RULE_TEMPLATES);
    Iterator ruleTemplatesIterator = ruleTemplatesElements.iterator();
    while (ruleTemplatesIterator.hasNext()) {
      Element ruleTemplatesElement = (Element) ruleTemplatesIterator.next();
      Collection<Element> ruleTemplateElements =
          XmlHelper.findElements(ruleTemplatesElement, RULE_TEMPLATE);
      for (Iterator iterator = ruleTemplateElements.iterator(); iterator.hasNext(); ) {
        ruleTemplates.add(parseRuleTemplate((Element) iterator.next(), ruleTemplates));
      }
    }
    return ruleTemplates;
  }

  private RuleTemplateBo parseRuleTemplate(Element element, List<RuleTemplateBo> ruleTemplates)
      throws XmlException {
    String name = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
    String description = element.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);
    Attribute allowOverwriteAttrib = element.getAttribute("allowOverwrite");

    boolean allowOverwrite = false;
    if (allowOverwriteAttrib != null) {
      allowOverwrite = Boolean.valueOf(allowOverwriteAttrib.getValue()).booleanValue();
    }
    if (org.apache.commons.lang.StringUtils.isEmpty(name)) {
      throw new XmlException("RuleTemplate must have a name");
    }
    if (org.apache.commons.lang.StringUtils.isEmpty(description)) {
      throw new XmlException("RuleTemplate must have a description");
    }

    // look up the rule template by name first
    RuleTemplateBo ruleTemplate =
        KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(name);

    if (ruleTemplate == null) {
      // if it does not exist create a new one
      ruleTemplate = new RuleTemplateBo();
    } else {
      // if it does exist, update it, only if allowOverwrite is set
      if (!allowOverwrite) {
        throw new RuntimeException(
            "Attempting to overwrite template " + name + " without allowOverwrite set");
      }

      // the name should be equal if one was actually found
      assert (name.equals(ruleTemplate.getName()))
          : "Existing template definition name does not match incoming definition name";
    }

    // overwrite simple properties
    ruleTemplate.setName(name);
    ruleTemplate.setDescription(description);

    // update the delegation template
    updateDelegationTemplate(element, ruleTemplate, ruleTemplates);

    // update the attribute relationships
    updateRuleTemplateAttributes(element, ruleTemplate);

    // save the rule template first so that the default/template rule that is generated
    // in the process of setting defaults is associated properly with this rule template
    ruleTemplate = KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);

    // update the default options
    updateRuleTemplateDefaultOptions(element, ruleTemplate);

    ruleTemplate = KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);

    return ruleTemplate;
  }

  /**
   * Updates the rule template default options. Updates any existing options, removes any omitted
   * ones.
   *
   * @param ruleTemplateElement the rule template XML element
   * @param updatedRuleTemplate the RuleTemplate being updated
   * @throws XmlException
   */
  /*
   <element name="description" type="c:LongStringType"/>
   <element name="fromDate" type="c:ShortStringType" minOccurs="0"/>
   <element name="toDate" type="c:ShortStringType" minOccurs="0"/>
   <element name="forceAction" type="boolean"/>
   <element name="active" type="boolean"/>
   <element name="defaultActionRequested" type="c:ShortStringType"/>
   <element name="supportsComplete" type="boolean" default="true"/>
   <element name="supportsApprove" type="boolean" default="true"/>
   <element name="supportsAcknowledge" type="boolean" default="true"/>
   <element name="supportsFYI" type="boolean" default="true"/>
  */
  protected void updateRuleTemplateDefaultOptions(
      Element ruleTemplateElement, RuleTemplateBo updatedRuleTemplate) throws XmlException {
    Element defaultsElement = ruleTemplateElement.getChild(RULE_DEFAULTS, RULE_TEMPLATE_NAMESPACE);

    // update the rule defaults; this yields whether or not this is a delegation rule template
    boolean isDelegation = updateRuleDefaults(defaultsElement, updatedRuleTemplate);

    // update the rule template options
    updateRuleTemplateOptions(defaultsElement, updatedRuleTemplate, isDelegation);
  }

  /**
   * Updates the rule template defaults options with those in the defaults element
   *
   * @param defaultsElement the ruleDefaults element
   * @param updatedRuleTemplate the Rule Template being updated
   */
  protected void updateRuleTemplateOptions(
      Element defaultsElement, RuleTemplateBo updatedRuleTemplate, boolean isDelegation)
      throws XmlException {
    // the possible defaults options
    // NOTE: the current implementation will remove any existing RuleTemplateOption records for any
    // values which are null, i.e. not set in the incoming XML.
    // to pro-actively set default values for omitted options, simply set those values here, and
    // records will be added if not present
    String defaultActionRequested = null;
    Boolean supportsComplete = null;
    Boolean supportsApprove = null;
    Boolean supportsAcknowledge = null;
    Boolean supportsFYI = null;

    // remove any RuleTemplateOptions the template may have but that we know we aren't going to
    // update/reset
    // (not sure if this case even exists...does anything else set rule template options?)
    updatedRuleTemplate.removeNonDefaultOptions();

    // read in new settings
    if (defaultsElement != null) {

      defaultActionRequested =
          defaultsElement.getChildText(DEFAULT_ACTION_REQUESTED, RULE_TEMPLATE_NAMESPACE);
      supportsComplete =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(SUPPORTS_COMPLETE, RULE_TEMPLATE_NAMESPACE));
      supportsApprove =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(SUPPORTS_APPROVE, RULE_TEMPLATE_NAMESPACE));
      supportsAcknowledge =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(SUPPORTS_ACKNOWLEDGE, RULE_TEMPLATE_NAMESPACE));
      supportsFYI =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(SUPPORTS_FYI, RULE_TEMPLATE_NAMESPACE));
    }

    if (!isDelegation) {
      // if this is not a delegation template, store the template options that govern rule action
      // constraints
      // in the RuleTemplateOptions of the template
      // we have two options for this behavior:
      // 1) conditionally parse above, and then unconditionally set/unset the properties; this will
      // have the effect of REMOVING
      //    any of these previously specified rule template options (and is arguably the right thing
      // to do)
      // 2) unconditionally parse above, and then conditionally set/unset the properties; this will
      // have the effect of PRESERVING
      //    the existing rule template options on this template if it is a delegation template
      // (which of course will be overwritten
      //    by this very same code if they subsequently upload without the delegation flag)
      // This is a minor point, but the second implementation is chosen as it preserved the current
      // behavior
      updateOrDeleteRuleTemplateOption(
          updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_DEFAULT_CD, defaultActionRequested);
      updateOrDeleteRuleTemplateOption(
          updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, supportsApprove);
      updateOrDeleteRuleTemplateOption(
          updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, supportsAcknowledge);
      updateOrDeleteRuleTemplateOption(
          updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_FYI_REQ, supportsFYI);
      updateOrDeleteRuleTemplateOption(
          updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, supportsComplete);
    }
  }

  /**
   * Updates the default/template rule options with those in the defaults element
   *
   * @param defaultsElement the ruleDefaults element
   * @param updatedRuleTemplate the Rule Template being updated
   * @return whether this is a delegation rule template
   */
  protected boolean updateRuleDefaults(Element defaultsElement, RuleTemplateBo updatedRuleTemplate)
      throws XmlException {
    // NOTE: implementation detail: in contrast with the other options, the delegate template, and
    // the rule attributes,
    // we unconditionally blow away the default rule and re-create it (we don't update the existing
    // one, if there is one)
    if (updatedRuleTemplate.getId() != null) {
      RuleBaseValues ruleDefaults =
          KEWServiceLocator.getRuleService()
              .findDefaultRuleByRuleTemplateId(updatedRuleTemplate.getId());
      if (ruleDefaults != null) {
        List ruleDelegationDefaults =
            KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(ruleDefaults.getId());
        // delete the rule
        KEWServiceLocator.getRuleService().delete(ruleDefaults.getId());
        // delete the associated rule delegation defaults
        for (Iterator iterator = ruleDelegationDefaults.iterator(); iterator.hasNext(); ) {
          RuleDelegationBo ruleDelegation = (RuleDelegationBo) iterator.next();
          KEWServiceLocator.getRuleDelegationService().delete(ruleDelegation.getRuleDelegationId());
        }
      }
    }

    boolean isDelegation = false;

    if (defaultsElement != null) {
      String delegationTypeCode =
          defaultsElement.getChildText(DELEGATION_TYPE, RULE_TEMPLATE_NAMESPACE);
      DelegationType delegationType = null;
      isDelegation = !org.apache.commons.lang.StringUtils.isEmpty(delegationTypeCode);

      String description = defaultsElement.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);

      // would normally be validated via schema but might not be present if invoking RuleXmlParser
      // directly
      if (description == null) {
        throw new XmlException("Description must be specified in rule defaults");
      }

      String fromDate = defaultsElement.getChildText(FROM_DATE, RULE_TEMPLATE_NAMESPACE);
      String toDate = defaultsElement.getChildText(TO_DATE, RULE_TEMPLATE_NAMESPACE);
      // toBooleanObject ensures that if the value is null (not set) that the Boolean object will
      // likewise be null (will not default to a value)
      Boolean forceAction =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(FORCE_ACTION, RULE_TEMPLATE_NAMESPACE));
      Boolean active =
          BooleanUtils.toBooleanObject(
              defaultsElement.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE));

      if (isDelegation) {
        delegationType = DelegationType.parseCode(delegationTypeCode);
        if (delegationType == null) {
          throw new XmlException(
              "Invalid delegation type '"
                  + delegationType
                  + "'."
                  + "  Expected one of: "
                  + DelegationType.PRIMARY.getCode()
                  + ","
                  + DelegationType.SECONDARY.getCode());
        }
      }

      // create our "default rule" which encapsulates the defaults for the rule
      RuleBaseValues ruleDefaults = new RuleBaseValues();

      // set simple values
      ruleDefaults.setRuleTemplate(updatedRuleTemplate);
      ruleDefaults.setRuleTemplateId(updatedRuleTemplate.getId());
      ruleDefaults.setDocTypeName(DUMMY_DOCUMENT_TYPE);
      ruleDefaults.setTemplateRuleInd(Boolean.TRUE);
      ruleDefaults.setCurrentInd(Boolean.TRUE);
      ruleDefaults.setVersionNbr(new Integer(0));
      ruleDefaults.setDescription(description);

      // these are non-nullable fields, so default them if they were not set in the defaults section
      ruleDefaults.setForceAction(Boolean.valueOf(BooleanUtils.isTrue(forceAction)));
      ruleDefaults.setActive(Boolean.valueOf(BooleanUtils.isTrue(active)));

      if (ruleDefaults.getActivationDate() == null) {
        ruleDefaults.setActivationDate(new Timestamp(System.currentTimeMillis()));
      }

      ruleDefaults.setFromDateValue(formatDate("fromDate", fromDate));
      ruleDefaults.setToDateValue(formatDate("toDate", toDate));

      // ok, if this is a "Delegate Template", then we need to set this other RuleDelegation object
      // which contains
      // some delegation-related info
      RuleDelegationBo ruleDelegationDefaults = null;
      if (isDelegation) {
        ruleDelegationDefaults = new RuleDelegationBo();
        ruleDelegationDefaults.setDelegationRule(ruleDefaults);
        ruleDelegationDefaults.setDelegationType(delegationType);
        ruleDelegationDefaults.setResponsibilityId(KewApiConstants.ADHOC_REQUEST_RESPONSIBILITY_ID);
      }

      // explicitly save the new rule delegation defaults and default rule
      KEWServiceLocator.getRuleTemplateService()
          .saveRuleDefaults(ruleDelegationDefaults, ruleDefaults);
    } else {
      // do nothing, rule defaults will be deleted if ruleDefaults element is omitted
    }

    return isDelegation;
  }

  /**
   * Updates or deletes a specified rule template option on the rule template
   *
   * @param updatedRuleTemplate the RuleTemplate being updated
   * @param key the option key
   * @param value the option value
   */
  protected void updateOrDeleteRuleTemplateOption(
      RuleTemplateBo updatedRuleTemplate, String key, Object value) {
    if (value != null) {
      // if the option exists and the incoming value is non-null (it's set), update it
      RuleTemplateOptionBo option = updatedRuleTemplate.getRuleTemplateOption(key);
      if (option != null) {
        option.setValue(value.toString());
      } else {
        updatedRuleTemplate
            .getRuleTemplateOptions()
            .add(new RuleTemplateOptionBo(key, value.toString()));
      }
    } else {
      // otherwise if the incoming value IS null (not set), then explicitly remove the entry (if it
      // exists)
      Iterator<RuleTemplateOptionBo> options =
          updatedRuleTemplate.getRuleTemplateOptions().iterator();
      while (options.hasNext()) {
        RuleTemplateOptionBo opt = options.next();
        if (key.equals(opt.getCode())) {
          options.remove();
          break;
        }
      }
    }
  }

  /**
   * Updates the rule template delegation template with the one specified in the XML (if any)
   *
   * @param ruleTemplateElement the XML ruleTemplate element
   * @param updatedRuleTemplate the rule template to update
   * @param parsedRuleTemplates the rule templates parsed in this parsing run
   * @throws XmlException if a delegation template was specified but could not be found
   */
  protected void updateDelegationTemplate(
      Element ruleTemplateElement,
      RuleTemplateBo updatedRuleTemplate,
      List<RuleTemplateBo> parsedRuleTemplates)
      throws XmlException {
    String delegateTemplateName =
        ruleTemplateElement.getChildText(DELEGATION_TEMPLATE, RULE_TEMPLATE_NAMESPACE);

    if (delegateTemplateName != null) {
      // if a delegateTemplate was set in the XML, then look it up and set it on the RuleTemplate
      // object
      // first try looking up an existing delegateTemplate in the system
      RuleTemplateBo delegateTemplate =
          KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(delegateTemplateName);

      // if not found, try the list of templates currently parsed
      if (delegateTemplate == null) {
        for (RuleTemplateBo rt : parsedRuleTemplates) {
          if (delegateTemplateName.equalsIgnoreCase(rt.getName())) {
            // set the expected next rule template id on the target delegateTemplate
            String ruleTemplateId =
                KEWServiceLocator.getRuleTemplateService().getNextRuleTemplateId();
            rt.setId(ruleTemplateId);
            delegateTemplate = rt;
            break;
          }
        }
      }

      if (delegateTemplate == null) {
        throw new XmlException("Cannot find delegation template " + delegateTemplateName);
      }

      updatedRuleTemplate.setDelegationTemplateId(delegateTemplate.getDelegationTemplateId());
      updatedRuleTemplate.setDelegationTemplate(delegateTemplate);
    } else {
      // the previously referenced template is left in the system
    }
  }

  /**
   * Updates the attributes set on the RuleTemplate
   *
   * @param ruleTemplateElement the XML ruleTemplate element
   * @param updatedRuleTemplate the RuleTemplate being updated
   * @throws XmlException if there was a problem parsing the rule template attributes
   */
  protected void updateRuleTemplateAttributes(
      Element ruleTemplateElement, RuleTemplateBo updatedRuleTemplate) throws XmlException {
    // add any newly defined rule template attributes to the rule template,
    // update the active and required flags of any existing ones.
    // if this is an update of an existing rule template, related attribute objects will be present
    // in this rule template object,
    // otherwise none will be present (so they'll all be new)

    Element attributesElement = ruleTemplateElement.getChild(ATTRIBUTES, RULE_TEMPLATE_NAMESPACE);
    List<RuleTemplateAttributeBo> incomingAttributes = new ArrayList<RuleTemplateAttributeBo>();
    if (attributesElement != null) {
      incomingAttributes.addAll(
          parseRuleTemplateAttributes(attributesElement, updatedRuleTemplate));
    }

    // inactivate all current attributes
    for (RuleTemplateAttributeBo currentRuleTemplateAttribute :
        updatedRuleTemplate.getRuleTemplateAttributes()) {
      String ruleAttributeName =
          (currentRuleTemplateAttribute.getRuleAttribute() != null)
              ? currentRuleTemplateAttribute.getRuleAttribute().getName()
              : "(null)";
      LOG.debug(
          "Inactivating rule template attribute with id "
              + currentRuleTemplateAttribute.getId()
              + " and rule attribute with name "
              + ruleAttributeName);
      currentRuleTemplateAttribute.setActive(Boolean.FALSE);
    }
    // NOTE: attributes are deactivated, not removed

    // add/update any new attributes
    for (RuleTemplateAttributeBo ruleTemplateAttribute : incomingAttributes) {
      RuleTemplateAttributeBo potentialExistingTemplateAttribute =
          updatedRuleTemplate.getRuleTemplateAttribute(ruleTemplateAttribute);
      if (potentialExistingTemplateAttribute != null) {
        // template attribute exists on rule template already; update the options
        potentialExistingTemplateAttribute.setActive(ruleTemplateAttribute.getActive());
        potentialExistingTemplateAttribute.setRequired(ruleTemplateAttribute.getRequired());
      } else {
        // template attribute does not yet exist on template so add it
        ruleTemplateAttribute.setRuleTemplate(updatedRuleTemplate);
        updatedRuleTemplate.getRuleTemplateAttributes().add(ruleTemplateAttribute);
      }
    }
  }

  /**
   * Parses the RuleTemplateAttributes defined on the rule template element
   *
   * @param attributesElement the jdom Element object for the Rule Template attributes
   * @param ruleTemplate the RuleTemplate object
   * @return the RuleTemplateAttributes defined on the rule template element
   * @throws XmlException
   */
  private List<RuleTemplateAttributeBo> parseRuleTemplateAttributes(
      Element attributesElement, RuleTemplateBo ruleTemplate) throws XmlException {
    List<RuleTemplateAttributeBo> ruleTemplateAttributes = new ArrayList<RuleTemplateAttributeBo>();
    Collection<Element> attributeElements = XmlHelper.findElements(attributesElement, ATTRIBUTE);
    for (Iterator iterator = attributeElements.iterator(); iterator.hasNext(); ) {
      ruleTemplateAttributes.add(
          parseRuleTemplateAttribute((Element) iterator.next(), ruleTemplate));
    }
    return ruleTemplateAttributes;
  }

  /**
   * Parses a rule template attribute
   *
   * @param element the attribute XML element
   * @param ruleTemplate the ruleTemplate to update
   * @return a parsed rule template attribute
   * @throws XmlException if the attribute does not exist
   */
  private RuleTemplateAttributeBo parseRuleTemplateAttribute(
      Element element, RuleTemplateBo ruleTemplate) throws XmlException {
    String attributeName = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
    String requiredValue = element.getChildText(REQUIRED, RULE_TEMPLATE_NAMESPACE);
    String activeValue = element.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE);
    if (org.apache.commons.lang.StringUtils.isEmpty(attributeName)) {
      throw new XmlException("Attribute name must be non-empty");
    }
    boolean required = DEFAULT_ATTRIBUTE_REQUIRED;
    if (requiredValue != null) {
      required = Boolean.parseBoolean(requiredValue);
    }
    boolean active = DEFAULT_ATTRIBUTE_ACTIVE;
    if (activeValue != null) {
      active = Boolean.parseBoolean(activeValue);
    }
    RuleAttribute ruleAttribute =
        KEWServiceLocator.getRuleAttributeService().findByName(attributeName);
    if (ruleAttribute == null) {
      throw new XmlException("Could not locate rule attribute for name '" + attributeName + "'");
    }
    RuleTemplateAttributeBo templateAttribute = new RuleTemplateAttributeBo();
    templateAttribute.setRuleAttribute(ruleAttribute);
    templateAttribute.setRuleAttributeId(ruleAttribute.getId());
    templateAttribute.setRuleTemplate(ruleTemplate);
    templateAttribute.setRequired(Boolean.valueOf(required));
    templateAttribute.setActive(Boolean.valueOf(active));
    templateAttribute.setDisplayOrder(new Integer(templateAttributeCounter++));
    return templateAttribute;
  }

  public Timestamp formatDate(String dateLabel, String dateString) throws XmlException {
    if (StringUtils.isBlank(dateString)) {
      return null;
    }
    try {
      return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
    } catch (ParseException e) {
      throw new XmlException(
          dateLabel
              + " is not in the proper format.  Should have been: "
              + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
    }
  }
}