001/**
002 * Copyright 2005-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.xml;
017
018import org.apache.commons.lang.BooleanUtils;
019import org.apache.commons.lang.StringUtils;
020import org.jdom.Attribute;
021import org.jdom.Document;
022import org.jdom.Element;
023import org.jdom.JDOMException;
024import org.kuali.rice.core.api.delegation.DelegationType;
025import org.kuali.rice.core.api.util.RiceConstants;
026import org.kuali.rice.core.api.util.xml.XmlException;
027import org.kuali.rice.core.api.util.xml.XmlHelper;
028import org.kuali.rice.kew.rule.RuleBaseValues;
029import org.kuali.rice.kew.rule.RuleDelegationBo;
030import org.kuali.rice.kew.rule.RuleTemplateOptionBo;
031import org.kuali.rice.kew.rule.bo.RuleAttribute;
032import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
033import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
034import org.kuali.rice.kew.service.KEWServiceLocator;
035import org.kuali.rice.kew.api.KewApiConstants;
036import org.xml.sax.SAXException;
037
038import javax.xml.parsers.ParserConfigurationException;
039import java.io.IOException;
040import java.io.InputStream;
041import java.sql.Timestamp;
042import java.text.ParseException;
043import java.util.ArrayList;
044import java.util.Collection;
045import java.util.Iterator;
046import java.util.List;
047
048import static org.kuali.rice.core.api.impex.xml.XmlConstants.*;
049/**
050 * Parses {@link org.kuali.rice.kew.rule.bo.RuleTemplateBo}s from XML.
051 *
052 * @see org.kuali.rice.kew.rule.bo.RuleTemplateBo
053 *
054 * @author Kuali Rice Team (rice.collab@kuali.org)
055 */
056public class RuleTemplateXmlParser {
057
058    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RuleTemplateXmlParser.class);
059
060    /**
061     * By default make attributes defined without a <required> element
062     */
063    private static final boolean DEFAULT_ATTRIBUTE_REQUIRED = true;
064    private static final boolean DEFAULT_ATTRIBUTE_ACTIVE = true;
065
066    /**
067     * A dummy document type used in the default rule
068     */
069    private static final String DUMMY_DOCUMENT_TYPE = "dummyDocumentType";
070
071    /**
072     * Used to set the display order of attributes encountered in parsing runs during the lifetime of this object
073     */
074    private int templateAttributeCounter = 0;
075
076    public List<RuleTemplateBo> parseRuleTemplates(InputStream input) throws IOException, XmlException {
077
078        try {
079            Document doc = XmlHelper.trimSAXXml(input);
080            Element root = doc.getRootElement();
081            return parseRuleTemplates(root);
082        } catch (JDOMException e) {
083            throw new XmlException("Parse error.", e);
084        } catch (SAXException e) {
085            throw new XmlException("Parse error.", e);
086        } catch (ParserConfigurationException e) {
087            throw new XmlException("Parse error.", e);
088        }
089    }
090
091    public List<RuleTemplateBo> parseRuleTemplates(Element element) throws XmlException {
092        List<RuleTemplateBo> ruleTemplates = new ArrayList<RuleTemplateBo>();
093
094        // iterate over any RULE_TEMPLATES elements
095        Collection<Element> ruleTemplatesElements = XmlHelper.findElements(element, RULE_TEMPLATES);
096        Iterator ruleTemplatesIterator = ruleTemplatesElements.iterator();
097        while (ruleTemplatesIterator.hasNext()) {
098            Element ruleTemplatesElement = (Element) ruleTemplatesIterator.next();
099            Collection<Element> ruleTemplateElements = XmlHelper.findElements(ruleTemplatesElement, RULE_TEMPLATE);
100            for (Iterator iterator = ruleTemplateElements.iterator(); iterator.hasNext();) {
101                ruleTemplates.add(parseRuleTemplate((Element) iterator.next(), ruleTemplates));
102            }
103        }
104        return ruleTemplates;
105    }
106
107    private RuleTemplateBo parseRuleTemplate(Element element, List<RuleTemplateBo> ruleTemplates) throws XmlException {
108        String name = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
109        String description = element.getChildText(DESCRIPTION, RULE_TEMPLATE_NAMESPACE);
110        Attribute allowOverwriteAttrib = element.getAttribute("allowOverwrite");
111
112        boolean allowOverwrite = false;
113        if (allowOverwriteAttrib != null) {
114            allowOverwrite = Boolean.valueOf(allowOverwriteAttrib.getValue()).booleanValue();
115        }
116        if (org.apache.commons.lang.StringUtils.isEmpty(name)) {
117            throw new XmlException("RuleTemplate must have a name");
118        }
119        if (org.apache.commons.lang.StringUtils.isEmpty(description)) {
120            throw new XmlException("RuleTemplate must have a description");
121        }
122
123        // look up the rule template by name first
124        RuleTemplateBo ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(name);
125
126        if (ruleTemplate == null) {
127            // if it does not exist create a new one
128            ruleTemplate = new RuleTemplateBo();
129        } else {
130            // if it does exist, update it, only if allowOverwrite is set
131            if (!allowOverwrite) {
132                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            assert(name.equals(ruleTemplate.getName())) : "Existing template definition name does not match incoming definition name";
137        } 
138
139        // overwrite simple properties
140        ruleTemplate.setName(name);
141        ruleTemplate.setDescription(description);
142
143        // update the delegation template
144        updateDelegationTemplate(element, ruleTemplate, ruleTemplates);
145
146        // update the attribute relationships
147        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        KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);
152
153        // update the default options
154        updateRuleTemplateDefaultOptions(element, ruleTemplate);
155
156        KEWServiceLocator.getRuleTemplateService().save(ruleTemplate);
157
158        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        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        boolean isDelegation = updateRuleDefaults(defaultsElement, updatedRuleTemplate);
184
185        // update the rule template options
186        updateRuleTemplateOptions(defaultsElement, updatedRuleTemplate, isDelegation);
187
188    }
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        String defaultActionRequested = null;
200        Boolean supportsComplete = null;
201        Boolean supportsApprove = null;
202        Boolean supportsAcknowledge = null;
203        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        updatedRuleTemplate.removeNonDefaultOptions();
208        
209        // read in new settings
210        if (defaultsElement != null) {
211
212                defaultActionRequested = defaultsElement.getChildText(DEFAULT_ACTION_REQUESTED, RULE_TEMPLATE_NAMESPACE);
213            supportsComplete = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_COMPLETE, RULE_TEMPLATE_NAMESPACE));
214            supportsApprove = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_APPROVE, RULE_TEMPLATE_NAMESPACE));
215            supportsAcknowledge = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_ACKNOWLEDGE, RULE_TEMPLATE_NAMESPACE));
216            supportsFYI = BooleanUtils.toBooleanObject(defaultsElement.getChildText(SUPPORTS_FYI, RULE_TEMPLATE_NAMESPACE));
217        }
218
219        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            updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_DEFAULT_CD, defaultActionRequested);
230            updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, supportsApprove);
231            updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, supportsAcknowledge);
232            updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_FYI_REQ, supportsFYI);
233            updateOrDeleteRuleTemplateOption(updatedRuleTemplate, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, supportsComplete);
234        }
235
236    }
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        if (updatedRuleTemplate.getId() != null) {
249            RuleBaseValues ruleDefaults = KEWServiceLocator.getRuleService().findDefaultRuleByRuleTemplateId(updatedRuleTemplate.getId());
250            if (ruleDefaults != null) {
251                List ruleDelegationDefaults = KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(ruleDefaults.getId());
252                // delete the rule
253                KEWServiceLocator.getRuleService().delete(ruleDefaults.getId());
254                // delete the associated rule delegation defaults
255                for (Iterator iterator = ruleDelegationDefaults.iterator(); iterator.hasNext();) {
256                    RuleDelegationBo ruleDelegation = (RuleDelegationBo) iterator.next();
257                    KEWServiceLocator.getRuleDelegationService().delete(ruleDelegation.getRuleDelegationId());
258                }
259            }
260        }
261
262        boolean isDelegation = false;
263
264        if (defaultsElement != null) {
265            String delegationTypeCode = defaultsElement.getChildText(DELEGATION_TYPE, RULE_TEMPLATE_NAMESPACE);
266            DelegationType delegationType = null;
267            isDelegation = !org.apache.commons.lang.StringUtils.isEmpty(delegationTypeCode);
268
269            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            if (description == null) {
273                throw new XmlException("Description must be specified in rule defaults");
274            }
275            
276            String fromDate = defaultsElement.getChildText(FROM_DATE, RULE_TEMPLATE_NAMESPACE);
277            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            Boolean forceAction = BooleanUtils.toBooleanObject(defaultsElement.getChildText(FORCE_ACTION, RULE_TEMPLATE_NAMESPACE));
280            Boolean active = BooleanUtils.toBooleanObject(defaultsElement.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE));
281
282            if (isDelegation) {
283                delegationType = DelegationType.parseCode(delegationTypeCode);
284                if (delegationType == null) {
285                    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            RuleBaseValues ruleDefaults = new RuleBaseValues();
292    
293            // set simple values
294            ruleDefaults.setRuleTemplate(updatedRuleTemplate);
295            ruleDefaults.setDocTypeName(DUMMY_DOCUMENT_TYPE);
296            ruleDefaults.setTemplateRuleInd(Boolean.TRUE);
297            ruleDefaults.setCurrentInd(Boolean.TRUE);
298            ruleDefaults.setVersionNbr(new Integer(0));
299            ruleDefaults.setDescription(description);
300    
301            // these are non-nullable fields, so default them if they were not set in the defaults section
302            ruleDefaults.setForceAction(Boolean.valueOf(BooleanUtils.isTrue(forceAction)));
303            ruleDefaults.setActive(Boolean.valueOf(BooleanUtils.isTrue(active)));
304        
305            if (ruleDefaults.getActivationDate() == null) {
306                ruleDefaults.setActivationDate(new Timestamp(System.currentTimeMillis()));
307            }
308    
309            ruleDefaults.setFromDateValue(formatDate("fromDate", fromDate));
310            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            RuleDelegationBo ruleDelegationDefaults = null;
315            if (isDelegation) {
316                ruleDelegationDefaults = new RuleDelegationBo();
317                ruleDelegationDefaults.setDelegationRule(ruleDefaults);
318                ruleDelegationDefaults.setDelegationType(delegationType);
319                ruleDelegationDefaults.setResponsibilityId(KewApiConstants.ADHOC_REQUEST_RESPONSIBILITY_ID);
320            }
321
322            // explicitly save the new rule delegation defaults and default rule
323            KEWServiceLocator.getRuleTemplateService().saveRuleDefaults(ruleDelegationDefaults, ruleDefaults);
324        } else {
325            // do nothing, rule defaults will be deleted if ruleDefaults element is omitted
326        }
327        
328        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        if (value != null) {
340            // if the option exists and the incoming value is non-null (it's set), update it
341            RuleTemplateOptionBo option = updatedRuleTemplate.getRuleTemplateOption(key);
342            if (option != null) {
343                option.setValue(value.toString());
344            } else {
345                updatedRuleTemplate.getRuleTemplateOptions().add(new RuleTemplateOptionBo(key, value.toString()));
346            }
347        } else {
348            // otherwise if the incoming value IS null (not set), then explicitly remove the entry (if it exists)
349            Iterator<RuleTemplateOptionBo> options = updatedRuleTemplate.getRuleTemplateOptions().iterator();
350            while (options.hasNext()) {
351                RuleTemplateOptionBo opt = options.next();
352                if (key.equals(opt.getCode())) {
353                    options.remove();
354                    break;
355                }
356            }
357        }
358    }
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        String delegateTemplateName = ruleTemplateElement.getChildText(DELEGATION_TEMPLATE, RULE_TEMPLATE_NAMESPACE);
369
370        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            RuleTemplateBo delegateTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(delegateTemplateName);
374
375            // if not found, try the list of templates currently parsed
376            if (delegateTemplate == null) {
377                for (RuleTemplateBo rt: parsedRuleTemplates) {
378                    if (delegateTemplateName.equalsIgnoreCase(rt.getName())) {
379                        // set the expected next rule template id on the target delegateTemplate
380                        String ruleTemplateId = KEWServiceLocator.getRuleTemplateService().getNextRuleTemplateId();
381                        rt.setId(ruleTemplateId);
382                        delegateTemplate = rt;
383                        break;
384                    }
385                }
386            }
387
388            if (delegateTemplate == null) {
389                throw new XmlException("Cannot find delegation template " + delegateTemplateName);
390            }
391
392            updatedRuleTemplate.setDelegationTemplateId(delegateTemplate.getDelegationTemplateId());
393            updatedRuleTemplate.setDelegationTemplate(delegateTemplate);           
394        } else {
395            // the previously referenced template is left in the system
396        }
397    }
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        Element attributesElement = ruleTemplateElement.getChild(ATTRIBUTES, RULE_TEMPLATE_NAMESPACE);
412        List<RuleTemplateAttributeBo> incomingAttributes = new ArrayList<RuleTemplateAttributeBo>();
413        if (attributesElement != null) {
414            incomingAttributes.addAll(parseRuleTemplateAttributes(attributesElement, updatedRuleTemplate));
415        }
416
417        // inactivate all current attributes
418        for (RuleTemplateAttributeBo currentRuleTemplateAttribute: updatedRuleTemplate.getRuleTemplateAttributes()) {
419            String ruleAttributeName = (currentRuleTemplateAttribute.getRuleAttribute() != null) ? currentRuleTemplateAttribute.getRuleAttribute().getName() : "(null)";
420            LOG.debug("Inactivating rule template attribute with id " + currentRuleTemplateAttribute.getId() + " and rule attribute with name " + ruleAttributeName);
421            currentRuleTemplateAttribute.setActive(Boolean.FALSE);
422        }
423        // NOTE: attributes are deactivated, not removed
424
425        // add/update any new attributes
426        for (RuleTemplateAttributeBo ruleTemplateAttribute: incomingAttributes) {
427            RuleTemplateAttributeBo potentialExistingTemplateAttribute = updatedRuleTemplate.getRuleTemplateAttribute(ruleTemplateAttribute);
428            if (potentialExistingTemplateAttribute != null) {
429                // template attribute exists on rule template already; update the options
430                potentialExistingTemplateAttribute.setActive(ruleTemplateAttribute.getActive());
431                potentialExistingTemplateAttribute.setRequired(ruleTemplateAttribute.getRequired());
432            } else {
433                // template attribute does not yet exist on template so add it
434                updatedRuleTemplate.getRuleTemplateAttributes().add(ruleTemplateAttribute);
435            }
436        }
437    }
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        List<RuleTemplateAttributeBo> ruleTemplateAttributes = new ArrayList<RuleTemplateAttributeBo>();
448        Collection<Element> attributeElements = XmlHelper.findElements(attributesElement, ATTRIBUTE);
449        for (Iterator iterator = attributeElements.iterator(); iterator.hasNext();) {
450            ruleTemplateAttributes.add(parseRuleTemplateAttribute((Element) iterator.next(), ruleTemplate));
451        }
452        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        String attributeName = element.getChildText(NAME, RULE_TEMPLATE_NAMESPACE);
464        String requiredValue = element.getChildText(REQUIRED, RULE_TEMPLATE_NAMESPACE);
465        String activeValue = element.getChildText(ACTIVE, RULE_TEMPLATE_NAMESPACE);
466        if (org.apache.commons.lang.StringUtils.isEmpty(attributeName)) {
467            throw new XmlException("Attribute name must be non-empty");
468        }
469        boolean required = DEFAULT_ATTRIBUTE_REQUIRED;
470        if (requiredValue != null) {
471            required = Boolean.parseBoolean(requiredValue);
472        }
473        boolean active = DEFAULT_ATTRIBUTE_ACTIVE;
474        if (activeValue != null) {
475            active = Boolean.parseBoolean(activeValue);
476        }
477        RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(attributeName);
478        if (ruleAttribute == null) {
479            throw new XmlException("Could not locate rule attribute for name '" + attributeName + "'");
480        }
481        RuleTemplateAttributeBo templateAttribute = new RuleTemplateAttributeBo();
482        templateAttribute.setRuleAttribute(ruleAttribute);
483        templateAttribute.setRuleAttributeId(ruleAttribute.getId());
484        templateAttribute.setRuleTemplate(ruleTemplate);
485        templateAttribute.setRequired(Boolean.valueOf(required));
486        templateAttribute.setActive(Boolean.valueOf(active));
487        templateAttribute.setDisplayOrder(new Integer(templateAttributeCounter++));
488        return templateAttribute;
489    }
490    
491    public Timestamp formatDate(String dateLabel, String dateString) throws XmlException {
492        if (StringUtils.isBlank(dateString)) {
493                return null;
494        }
495        try {
496                return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
497        } catch (ParseException e) {
498                throw new XmlException(dateLabel + " is not in the proper format.  Should have been: " + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
499        }
500    }
501
502}