001    /**
002     * Copyright 2005-2011 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     */
016    package org.kuali.rice.kew.xml;
017    
018    import org.apache.commons.lang.BooleanUtils;
019    import org.apache.commons.lang.StringUtils;
020    import org.jdom.Attribute;
021    import org.jdom.Document;
022    import org.jdom.Element;
023    import org.jdom.JDOMException;
024    import org.kuali.rice.core.api.delegation.DelegationType;
025    import org.kuali.rice.core.api.util.RiceConstants;
026    import org.kuali.rice.core.api.util.xml.XmlException;
027    import org.kuali.rice.core.api.util.xml.XmlHelper;
028    import org.kuali.rice.kew.rule.RuleBaseValues;
029    import org.kuali.rice.kew.rule.RuleDelegationBo;
030    import org.kuali.rice.kew.rule.RuleTemplateOptionBo;
031    import org.kuali.rice.kew.rule.bo.RuleAttribute;
032    import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
033    import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
034    import org.kuali.rice.kew.service.KEWServiceLocator;
035    import org.kuali.rice.kew.api.KewApiConstants;
036    import org.xml.sax.SAXException;
037    
038    import javax.xml.parsers.ParserConfigurationException;
039    import java.io.IOException;
040    import java.io.InputStream;
041    import java.sql.Timestamp;
042    import java.text.ParseException;
043    import java.util.ArrayList;
044    import java.util.Collection;
045    import java.util.Iterator;
046    import java.util.List;
047    
048    import 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     */
056    public 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    }