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