Coverage Report - org.kuali.rice.kew.xml.RuleXmlParser
 
Classes in this File Line Coverage Branch Coverage Complexity
RuleXmlParser
0%
0/295
0%
0/152
7.45
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kew.xml;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.jdom.Document;
 20  
 import org.jdom.Element;
 21  
 import org.jdom.JDOMException;
 22  
 import org.kuali.rice.core.api.delegation.DelegationType;
 23  
 import org.kuali.rice.core.api.util.RiceConstants;
 24  
 import org.kuali.rice.core.api.util.xml.XmlException;
 25  
 import org.kuali.rice.core.api.util.xml.XmlHelper;
 26  
 import org.kuali.rice.kew.api.action.ActionRequestPolicy;
 27  
 import org.kuali.rice.kew.api.rule.RoleName;
 28  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 29  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 30  
 import org.kuali.rice.kew.rule.RuleDelegationBo;
 31  
 import org.kuali.rice.kew.rule.RuleExpressionDef;
 32  
 import org.kuali.rice.kew.rule.RuleResponsibilityBo;
 33  
 import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
 34  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 35  
 import org.kuali.rice.kew.api.KewApiConstants;
 36  
 import org.kuali.rice.kew.util.Utilities;
 37  
 import org.kuali.rice.kim.api.group.Group;
 38  
 import org.kuali.rice.kim.api.identity.principal.Principal;
 39  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 40  
 import org.xml.sax.SAXException;
 41  
 
 42  
 import javax.xml.parsers.ParserConfigurationException;
 43  
 import java.io.IOException;
 44  
 import java.io.InputStream;
 45  
 import java.sql.Timestamp;
 46  
 import java.text.ParseException;
 47  
 import java.util.ArrayList;
 48  
 import java.util.Iterator;
 49  
 import java.util.List;
 50  
 
 51  
 import static org.kuali.rice.core.api.impex.xml.XmlConstants.*;
 52  
 
 53  
 /**
 54  
  * Parses rules from XML.
 55  
  *
 56  
  * @see RuleBaseValues
 57  
  *
 58  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 59  
  */
 60  0
 public class RuleXmlParser {
 61  
 
 62  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RuleXmlParser.class);
 63  
 
 64  
     /**
 65  
      * Priority to use if rule responsibility omits priority
 66  
      */
 67  
     private static final int DEFAULT_RULE_PRIORITY = 1;
 68  
     /**
 69  
      * Value of Force Action flag if omitted; default to false, we will NOT force action for approvals
 70  
      */
 71  
     private static final boolean DEFAULT_FORCE_ACTION = false;
 72  
     /**
 73  
      * Default approve policy, if omitted; defaults to FIRST_APPROVE, the request will be satisfied by the first approval
 74  
      */
 75  0
     private static final String DEFAULT_APPROVE_POLICY = ActionRequestPolicy.FIRST.getCode();
 76  
     /**
 77  
      * Default action requested, if omitted; defaults to "A"pprove
 78  
      */
 79  
     private static final String DEFAULT_ACTION_REQUESTED = KewApiConstants.ACTION_REQUEST_APPROVE_REQ;
 80  
 
 81  
     public List<RuleDelegationBo> parseRuleDelegations(InputStream input) throws IOException, XmlException {
 82  
             try {
 83  0
             Document doc = XmlHelper.trimSAXXml(input);
 84  0
             Element root = doc.getRootElement();
 85  0
             return parseRuleDelegations(root);
 86  0
         } catch (JDOMException e) {
 87  0
             throw new XmlException("Parse error.", e);
 88  0
         } catch (SAXException e){
 89  0
             throw new XmlException("Parse error.",e);
 90  0
         } catch(ParserConfigurationException e){
 91  0
             throw new XmlException("Parse error.",e);
 92  
         }
 93  
     }
 94  
     
 95  
     public List<RuleBaseValues> parseRules(InputStream input) throws IOException, XmlException {
 96  
         try {
 97  0
             Document doc = XmlHelper.trimSAXXml(input);
 98  0
             Element root = doc.getRootElement();
 99  0
             return parseRules(root);
 100  0
         } catch (JDOMException e) {
 101  0
             throw new XmlException("Parse error.", e);
 102  0
         } catch (SAXException e){
 103  0
             throw new XmlException("Parse error.",e);
 104  0
         } catch(ParserConfigurationException e){
 105  0
             throw new XmlException("Parse error.",e);
 106  
         }
 107  
     }
 108  
 
 109  
     /**
 110  
      * Parses and saves rules
 111  
      * @param element top-level 'data' element which should contain a <rules> child element
 112  
      * @throws XmlException
 113  
      */
 114  
     public List<RuleBaseValues> parseRules(Element element) throws XmlException {
 115  0
             List<RuleBaseValues> rulesToSave = new ArrayList<RuleBaseValues>();
 116  0
         for (Element rulesElement: (List<Element>) element.getChildren(RULES, RULE_NAMESPACE)) {
 117  0
             for (Element ruleElement: (List<Element>) rulesElement.getChildren(RULE, RULE_NAMESPACE)) {
 118  0
                 RuleBaseValues rule = parseRule(ruleElement);
 119  0
                 rulesToSave.add(rule);
 120  0
             }
 121  
         }
 122  0
         checkForDuplicateRules(rulesToSave);
 123  0
         return KEWServiceLocator.getRuleService().saveRules(rulesToSave, false);
 124  
     }
 125  
     
 126  
     /**
 127  
      * Parses and saves rule delegations
 128  
      * @param element top-level 'data' element which should contain a <rules> child element
 129  
      * @throws XmlException
 130  
      */
 131  
     public List<RuleDelegationBo> parseRuleDelegations(Element element) throws XmlException {
 132  0
             List<RuleDelegationBo> ruleDelegationsToSave = new ArrayList<RuleDelegationBo>();
 133  0
         for (Element ruleDelegationsElement: (List<Element>) element.getChildren(RULE_DELEGATIONS, RULE_NAMESPACE)) {
 134  0
             for (Element ruleDelegationElement: (List<Element>) ruleDelegationsElement.getChildren(RULE_DELEGATION, RULE_NAMESPACE)) {
 135  0
                 RuleDelegationBo ruleDelegation = parseRuleDelegation(ruleDelegationElement);
 136  0
                 ruleDelegationsToSave.add(ruleDelegation);
 137  0
             }
 138  
         }
 139  
         //checkForDuplicateRuleDelegations(ruleDelegationsToSave);
 140  0
         return KEWServiceLocator.getRuleService().saveRuleDelegations(ruleDelegationsToSave, false);
 141  
     }
 142  
     
 143  
     /**
 144  
      * Checks for rules in the List that duplicate other Rules already in the system 
 145  
      */
 146  
     private void checkForDuplicateRules(List<RuleBaseValues> rules) throws XmlException {
 147  0
             for (RuleBaseValues rule : rules) {
 148  0
                     if (StringUtils.isBlank(rule.getName())) {
 149  0
                             LOG.debug("Checking for rule duplication on an anonymous rule.");
 150  0
                             checkRuleForDuplicate(rule);
 151  
                     }
 152  
             }
 153  0
     }
 154  
     
 155  
     /**
 156  
      * Checks for rule delegations in the List that duplicate other Rules already in the system 
 157  
      */
 158  
     private void checkForDuplicateRuleDelegations(List<RuleDelegationBo> ruleDelegations) throws XmlException {
 159  0
             for (RuleDelegationBo ruleDelegation : ruleDelegations) {
 160  0
                     if (StringUtils.isBlank(ruleDelegation.getDelegationRule().getName())) {
 161  0
                             LOG.debug("Checking for rule duplication on an anonymous rule delegation.");
 162  0
                             checkRuleDelegationForDuplicate(ruleDelegation);
 163  
                     }
 164  
             }
 165  0
     }
 166  
 
 167  
     private RuleDelegationBo parseRuleDelegation(Element element) throws XmlException {
 168  0
             RuleDelegationBo ruleDelegation = new RuleDelegationBo();
 169  0
             Element parentResponsibilityElement = element.getChild(PARENT_RESPONSIBILITY, element.getNamespace());
 170  0
             if (parentResponsibilityElement == null) {
 171  0
                     throw new XmlException("parent responsibility was not defined");
 172  
             }
 173  0
             String parentResponsibilityId = parseParentResponsibilityId(parentResponsibilityElement);
 174  0
             String delegationType = element.getChildText(DELEGATION_TYPE, element.getNamespace());
 175  0
         if (delegationType == null || DelegationType.parseCode(delegationType) == null) {
 176  0
             throw new XmlException("Invalid delegation type specified for delegate rule '" + delegationType + "'");
 177  
         }
 178  
         
 179  0
         ruleDelegation.setResponsibilityId(parentResponsibilityId);
 180  0
         ruleDelegation.setDelegationType(DelegationType.fromCode(delegationType));
 181  
         
 182  0
         Element ruleElement = element.getChild(RULE, element.getNamespace());
 183  0
         RuleBaseValues rule = parseRule(ruleElement);
 184  0
         rule.setDelegateRule(true);
 185  0
         ruleDelegation.setDelegationRule(rule);
 186  
             
 187  0
             return ruleDelegation;
 188  
     }
 189  
     
 190  
     private String parseParentResponsibilityId(Element element) throws XmlException {
 191  0
             String responsibilityId = element.getChildText(RESPONSIBILITY_ID, element.getNamespace());
 192  0
             if (!StringUtils.isBlank(responsibilityId)) {
 193  0
                     return responsibilityId;
 194  
             }
 195  0
             String parentRuleName = element.getChildText(PARENT_RULE_NAME, element.getNamespace());
 196  0
             if (StringUtils.isBlank(parentRuleName)) {
 197  0
                     throw new XmlException("One of responsibilityId or parentRuleName needs to be defined");
 198  
             }
 199  0
             RuleBaseValues parentRule = KEWServiceLocator.getRuleService().getRuleByName(parentRuleName);
 200  0
             if (parentRule == null) {
 201  0
                     throw new XmlException("Could find the parent rule with name '" + parentRuleName + "'");
 202  
             }
 203  0
             RuleResponsibilityBo ruleResponsibilityNameAndType = parseResponsibilityNameAndType(element);
 204  0
             if (ruleResponsibilityNameAndType == null) {
 205  0
                     throw new XmlException("Could not locate a valid responsibility declaration for the parent responsibility.");
 206  
             }
 207  0
             String parentResponsibilityId = KEWServiceLocator.getRuleService().findResponsibilityIdForRule(parentRuleName, 
 208  
                             ruleResponsibilityNameAndType.getRuleResponsibilityName(),
 209  
                             ruleResponsibilityNameAndType.getRuleResponsibilityType());
 210  0
             if (parentResponsibilityId == null) {
 211  0
                     throw new XmlException("Failed to locate parent responsibility for rule with name '" + parentRuleName + "' and responsibility " + ruleResponsibilityNameAndType);
 212  
             }
 213  0
             return parentResponsibilityId;
 214  
     }
 215  
     
 216  
     /**
 217  
      * Parses, and only parses, a rule definition (be it a top-level rule, or a rule delegation).  This method will
 218  
      * NOT dirty or save any existing data, it is side-effect-free.
 219  
      * @param element the rule element
 220  
      * @return a new RuleBaseValues object which is not yet saved
 221  
      * @throws XmlException
 222  
      */
 223  
     private RuleBaseValues parseRule(Element element) throws XmlException {
 224  0
         String name = element.getChildText(NAME, element.getNamespace());
 225  0
         RuleBaseValues rule = createRule(name);
 226  
         
 227  0
         setDefaultRuleValues(rule);
 228  0
         rule.setName(name);
 229  
         
 230  0
         String toDatestr = element.getChildText( TO_DATE, element.getNamespace());
 231  0
         String fromDatestr = element.getChildText( FROM_DATE, element.getNamespace());
 232  0
         rule.setToDateValue(formatDate("toDate", toDatestr));
 233  0
         rule.setFromDateValue(formatDate("fromDate", fromDatestr));
 234  
 
 235  0
         String description = element.getChildText(DESCRIPTION, element.getNamespace());
 236  0
         if (StringUtils.isBlank(description)) {
 237  0
             throw new XmlException("Rule must have a description.");
 238  
         }
 239  
                 
 240  0
         String documentTypeName = element.getChildText(DOCUMENT_TYPE, element.getNamespace());
 241  0
         if (StringUtils.isBlank(documentTypeName)) {
 242  0
                 throw new XmlException("Rule must have a document type.");
 243  
         }
 244  0
         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
 245  0
         if (documentType == null) {
 246  0
                 throw new XmlException("Could not locate document type '" + documentTypeName + "'");
 247  
         }
 248  
 
 249  0
         RuleTemplateBo ruleTemplate = null;
 250  0
         String ruleTemplateName = element.getChildText(RULE_TEMPLATE, element.getNamespace());        
 251  0
         Element ruleExtensionsElement = element.getChild(RULE_EXTENSIONS, element.getNamespace());
 252  0
         if (!StringUtils.isBlank(ruleTemplateName)) {
 253  0
                 ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
 254  0
                 if (ruleTemplate == null) {
 255  0
                         throw new XmlException("Could not locate rule template '" + ruleTemplateName + "'");
 256  
                 }
 257  
         } else {
 258  0
                 if (ruleExtensionsElement != null) {
 259  0
                         throw new XmlException("Templateless rules may not have rule extensions");
 260  
                 }
 261  
         }
 262  
 
 263  0
         RuleExpressionDef ruleExpressionDef = null;
 264  0
         Element exprElement = element.getChild(RULE_EXPRESSION, element.getNamespace());
 265  0
         if (exprElement != null) {
 266  0
                 String exprType = exprElement.getAttributeValue("type");
 267  0
                 if (StringUtils.isEmpty(exprType)) {
 268  0
                         throw new XmlException("Expression type must be specified");
 269  
                 }
 270  0
                 String expression = exprElement.getTextTrim();
 271  0
                 ruleExpressionDef = new RuleExpressionDef();
 272  0
                 ruleExpressionDef.setType(exprType);
 273  0
                 ruleExpressionDef.setExpression(expression);
 274  
         }
 275  
         
 276  0
         String forceActionValue = element.getChildText(FORCE_ACTION, element.getNamespace());
 277  0
         Boolean forceAction = Boolean.valueOf(DEFAULT_FORCE_ACTION);
 278  0
         if (!StringUtils.isBlank(forceActionValue)) {
 279  0
             forceAction = Boolean.valueOf(forceActionValue);
 280  
         }
 281  
 
 282  0
         rule.setDocTypeName(documentType.getName());
 283  0
         if (ruleTemplate != null) {
 284  0
             rule.setRuleTemplateId(ruleTemplate.getId());
 285  0
             rule.setRuleTemplate(ruleTemplate);
 286  
         }
 287  0
         if (ruleExpressionDef != null) {
 288  0
             rule.setRuleExpressionDef(ruleExpressionDef);
 289  
         }
 290  0
         rule.setDescription(description);
 291  0
         rule.setForceAction(forceAction);
 292  
 
 293  0
         Element responsibilitiesElement = element.getChild(RESPONSIBILITIES, element.getNamespace());
 294  0
         rule.setRuleResponsibilities(parseResponsibilities(responsibilitiesElement, rule));
 295  0
         rule.setRuleExtensions(parseRuleExtensions(ruleExtensionsElement, rule));
 296  
 
 297  0
         return rule;
 298  
     }
 299  
     
 300  
     /**
 301  
      * Creates the rule that the parser will populate.  If a rule with the given name
 302  
      * already exists, it's keys and responsibilities will be copied over to the
 303  
      * new rule.  The calling code will then sort through the original responsibilities
 304  
      * and compare them with those being defined on the XML being parsed.
 305  
      */
 306  
     private RuleBaseValues createRule(String ruleName) {
 307  0
             RuleBaseValues rule = new RuleBaseValues();
 308  0
             RuleBaseValues existingRule = (ruleName != null) ? KEWServiceLocator.getRuleService().getRuleByName(ruleName) : null;
 309  0
             if (existingRule != null) {
 310  
                     // copy keys and responsibiliities from the existing rule
 311  0
                     rule.setId(existingRule.getId());
 312  0
                     rule.setPreviousRuleId(existingRule.getPreviousRuleId());
 313  0
                     rule.setPreviousVersion(existingRule.getPreviousVersion());
 314  0
                     rule.setRuleResponsibilities(existingRule.getRuleResponsibilities());
 315  
             }
 316  0
             return rule;
 317  
     }
 318  
 
 319  
     /**
 320  
      * Checks to see whether this anonymous rule duplicates an existing rule.
 321  
      * Currently the uniqueness is on ruleResponsibilityName, and extension key/values.
 322  
      * @param rule the rule to check
 323  
      * @throws XmlException if this incoming rule duplicates an existing rule
 324  
      */
 325  
     private void checkRuleForDuplicate(RuleBaseValues rule) throws XmlException {
 326  0
             String ruleId = KEWServiceLocator.getRuleService().getDuplicateRuleId(rule);
 327  0
         if (ruleId != null) {
 328  0
                 throw new XmlException("Rule '" + rule.getDescription() + "' on doc '" + rule.getDocTypeName() + "' is a duplicate of rule with rule Id " + ruleId);
 329  
         }
 330  0
     }
 331  
     
 332  
     private void checkRuleDelegationForDuplicate(RuleDelegationBo ruleDelegation) throws XmlException {
 333  0
             checkRuleForDuplicate(ruleDelegation.getDelegationRule());
 334  0
     }
 335  
 
 336  
     private void setDefaultRuleValues(RuleBaseValues rule) throws XmlException {
 337  0
         rule.setForceAction(Boolean.FALSE);
 338  0
         rule.setActivationDate(new Timestamp(System.currentTimeMillis()));
 339  0
         rule.setActive(Boolean.TRUE);
 340  0
         rule.setCurrentInd(Boolean.TRUE);
 341  0
         rule.setTemplateRuleInd(Boolean.FALSE);
 342  0
         rule.setVersionNbr(new Integer(0));
 343  0
         rule.setDelegateRule(false);
 344  0
     }
 345  
 
 346  
     private List<RuleResponsibilityBo> parseResponsibilities(Element element, RuleBaseValues rule) throws XmlException {
 347  0
         if (element == null) {
 348  0
             return new ArrayList<RuleResponsibilityBo>(0);
 349  
         }
 350  0
         List<RuleResponsibilityBo> existingResponsibilities = rule.getRuleResponsibilities();
 351  0
         List<RuleResponsibilityBo> responsibilities = new ArrayList<RuleResponsibilityBo>();
 352  0
         List<Element> responsibilityElements = (List<Element>)element.getChildren(RESPONSIBILITY, element.getNamespace());
 353  0
         for (Element responsibilityElement : responsibilityElements) {
 354  0
             RuleResponsibilityBo responsibility = parseResponsibility(responsibilityElement, rule);
 355  0
             reconcileWithExistingResponsibility(responsibility, existingResponsibilities);
 356  0
             responsibilities.add(responsibility);
 357  0
         }
 358  0
         if (responsibilities.size() == 0) {
 359  0
             throw new XmlException("Rule responsibility list must have at least one responsibility.");
 360  
         }
 361  0
         return responsibilities;
 362  
     }
 363  
 
 364  
     public RuleResponsibilityBo parseResponsibility(Element element, RuleBaseValues rule) throws XmlException {
 365  0
         RuleResponsibilityBo responsibility = new RuleResponsibilityBo();
 366  0
         responsibility.setRuleBaseValues(rule);
 367  0
         String actionRequested = null;
 368  0
         String priority = null;
 369  0
         actionRequested = element.getChildText(ACTION_REQUESTED, element.getNamespace());
 370  0
         if (StringUtils.isBlank(actionRequested)) {
 371  0
                 actionRequested = DEFAULT_ACTION_REQUESTED;
 372  
         }
 373  0
         priority = element.getChildText(PRIORITY, element.getNamespace());
 374  0
         if (StringUtils.isBlank(priority)) {
 375  0
                 priority = String.valueOf(DEFAULT_RULE_PRIORITY);
 376  
         }
 377  0
         String approvePolicy = element.getChildText(APPROVE_POLICY, element.getNamespace());
 378  0
         Element delegations = element.getChild(DELEGATIONS, element.getNamespace());
 379  0
         if (actionRequested == null) {
 380  0
             throw new XmlException("actionRequested is required on responsibility");
 381  
         }
 382  0
         if (!actionRequested.equals(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ) && !actionRequested.equals(KewApiConstants.ACTION_REQUEST_APPROVE_REQ) && !actionRequested.equals(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ) && !actionRequested.equals(KewApiConstants.ACTION_REQUEST_FYI_REQ)) {
 383  0
             throw new XmlException("Invalid action requested code '" + actionRequested + "'");
 384  
         }
 385  0
         if (StringUtils.isBlank(approvePolicy)) {
 386  0
             approvePolicy = DEFAULT_APPROVE_POLICY;
 387  
         }
 388  0
         if (!approvePolicy.equals(ActionRequestPolicy.ALL.getCode()) && !approvePolicy.equals(ActionRequestPolicy.FIRST.getCode())) {
 389  0
             throw new XmlException("Invalid approve policy '" + approvePolicy + "'");
 390  
         }
 391  0
         Integer priorityNumber = Integer.valueOf(priority);
 392  0
         responsibility.setActionRequestedCd(actionRequested);
 393  0
         responsibility.setPriority(priorityNumber);
 394  0
         responsibility.setApprovePolicy(approvePolicy);
 395  
         
 396  0
         RuleResponsibilityBo responsibilityNameAndType = parseResponsibilityNameAndType(element);
 397  0
         if (responsibilityNameAndType == null) {
 398  0
                 throw new XmlException("Could not locate a valid responsibility declaration on a responsibility on rule with description '" + rule.getDescription() + "'");
 399  
         }
 400  0
         if (responsibilityNameAndType.getRuleResponsibilityType().equals(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID)
 401  
                         && responsibility.getApprovePolicy().equals(ActionRequestPolicy.ALL.getCode())) {
 402  0
                 throw new XmlException("Invalid approve policy '" + approvePolicy + "'.  This policy is not supported with Groups.");
 403  
         }
 404  0
         responsibility.setRuleResponsibilityName(responsibilityNameAndType.getRuleResponsibilityName());
 405  0
         responsibility.setRuleResponsibilityType(responsibilityNameAndType.getRuleResponsibilityType());
 406  
         
 407  0
         return responsibility;
 408  
     }
 409  
 
 410  
     public RuleResponsibilityBo parseResponsibilityNameAndType(Element element) throws XmlException {
 411  0
             RuleResponsibilityBo responsibility = new RuleResponsibilityBo();
 412  
             
 413  0
             String principalId = element.getChildText(PRINCIPAL_ID, element.getNamespace());
 414  0
         String principalName = element.getChildText(PRINCIPAL_NAME, element.getNamespace());
 415  0
         String groupId = element.getChildText(GROUP_ID, element.getNamespace());
 416  0
         Element groupNameElement = element.getChild(GROUP_NAME, element.getNamespace());
 417  0
         String role = element.getChildText(ROLE, element.getNamespace());
 418  0
         Element roleNameElement = element.getChild(ROLE_NAME, element.getNamespace());
 419  
         
 420  0
         String user = element.getChildText(USER, element.getNamespace());
 421  0
         String workgroup = element.getChildText(WORKGROUP, element.getNamespace());
 422  
         
 423  0
         if (!StringUtils.isEmpty(user)) {
 424  0
                 principalName = user;
 425  0
                 LOG.warn("Rule XML is using deprecated element 'user', please use 'principalName' instead.");
 426  
         }
 427  
         
 428  
         // in code below, we allow core config parameter replacement in responsibilities
 429  0
         if (!StringUtils.isBlank(principalId)) {
 430  0
                 principalId = Utilities.substituteConfigParameters(principalId);
 431  0
                 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
 432  0
             if (principal == null) {
 433  0
                     throw new XmlException("Could not locate principal with the given id: " + principalId);
 434  
             }
 435  0
             responsibility.setRuleResponsibilityName(principalId);
 436  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 437  0
         } else if (!StringUtils.isBlank(principalName)) {
 438  0
                 principalName = Utilities.substituteConfigParameters(principalName);
 439  0
                 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalName);
 440  0
             if (principal == null) {
 441  0
                     throw new XmlException("Could not locate principal with the given name: " + principalName);
 442  
             }
 443  0
             responsibility.setRuleResponsibilityName(principal.getPrincipalId());
 444  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 445  0
         } else if (!StringUtils.isBlank(groupId)) {
 446  0
             groupId = Utilities.substituteConfigParameters(groupId);
 447  0
             Group group = KimApiServiceLocator.getGroupService().getGroup(groupId);
 448  0
             if (group == null) {
 449  0
                 throw new XmlException("Could not locate group with the given id: " + groupId);
 450  
             }
 451  0
             responsibility.setRuleResponsibilityName(groupId);
 452  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID);
 453  0
         } else if (groupNameElement != null) {
 454  0
                 String groupName = groupNameElement.getText();
 455  0
                 String groupNamespace = groupNameElement.getAttributeValue(NAMESPACE);
 456  0
                 if (StringUtils.isBlank(groupName)) {
 457  0
                         throw new XmlException("Group name element has no value");
 458  
                 }
 459  0
                 if (StringUtils.isBlank(groupNamespace)) {
 460  0
                         throw new XmlException("namespace attribute must be specified");
 461  
                 }
 462  0
             groupName = Utilities.substituteConfigParameters(groupName);
 463  0
             groupNamespace = Utilities.substituteConfigParameters(groupNamespace);
 464  0
             Group group = KimApiServiceLocator.getGroupService().getGroupByNameAndNamespaceCode(groupNamespace,
 465  
                     groupName);
 466  0
             if (group == null) {
 467  0
                 throw new XmlException("Could not locate group with the given namespace: " + groupNamespace + " and name: " + groupName);
 468  
             }
 469  0
             responsibility.setRuleResponsibilityName(group.getId());
 470  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID);
 471  0
         } else if (!StringUtils.isBlank(role)) {
 472  0
                 role = Utilities.substituteConfigParameters(role);
 473  0
                 responsibility.setRuleResponsibilityName(role);
 474  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID);
 475  0
         } else if (roleNameElement != null) {
 476  0
                 String roleName = roleNameElement.getText();
 477  0
                 String attributeClassName = roleNameElement.getAttributeValue(ATTRIBUTE_CLASS_NAME);
 478  0
                 if (StringUtils.isBlank(roleName)) {
 479  0
                         throw new XmlException("Role name element has no value");
 480  
                 }
 481  0
                 if (StringUtils.isBlank(attributeClassName)) {
 482  0
                         throw new XmlException("attributeClassName attribute must be specified");
 483  
                 }
 484  0
                 roleName = Utilities.substituteConfigParameters(roleName);
 485  0
                 attributeClassName = Utilities.substituteConfigParameters(attributeClassName);
 486  0
                 responsibility.setRuleResponsibilityName(RoleName.constructRoleValue(attributeClassName, roleName));
 487  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID);
 488  0
         } else if (!StringUtils.isBlank(workgroup)) {
 489  0
                 LOG.warn("Rule XML is using deprecated element 'workgroup', please use 'groupName' instead.");
 490  0
             workgroup = Utilities.substituteConfigParameters(workgroup);
 491  0
             String workgroupNamespace = Utilities.parseGroupNamespaceCode(workgroup);
 492  0
             String workgroupName = Utilities.parseGroupName(workgroup);
 493  
 
 494  0
             Group workgroupObject = KimApiServiceLocator.getGroupService().getGroupByNameAndNamespaceCode(
 495  
                     workgroupNamespace, workgroupName);
 496  0
             if (workgroupObject == null) {
 497  0
                 throw new XmlException("Could not locate workgroup: " + workgroup);
 498  
             }
 499  0
             responsibility.setRuleResponsibilityName(workgroupObject.getId());
 500  0
             responsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID);
 501  0
         } else {
 502  0
                 return null;
 503  
         }
 504  
         
 505  0
         return responsibility;
 506  
     }
 507  
     
 508  
     /**
 509  
      * Attempts to reconcile the given RuleResponsibility with the list of existing responsibilities (in the case of a
 510  
      * rule being updated via the XML).  This goal of this code is to copy responsibility ids from existing responsibilities
 511  
      * to the new responsibility where appropriate.  The code will attempt to find exact matches based on the values found
 512  
      * on the responsibilities.
 513  
      */
 514  
     private void reconcileWithExistingResponsibility(RuleResponsibilityBo responsibility, List<RuleResponsibilityBo> existingResponsibilities) {
 515  0
             if (existingResponsibilities == null || existingResponsibilities.isEmpty()) {
 516  0
                     return;
 517  
             }
 518  0
             RuleResponsibilityBo exactMatch = null;
 519  0
             for (RuleResponsibilityBo existingResponsibility : existingResponsibilities) {
 520  0
                     if (isExactResponsibilityMatch(responsibility, existingResponsibility)) {
 521  0
                             exactMatch = existingResponsibility;
 522  0
                             break;
 523  
                     }
 524  
             }
 525  0
             if (exactMatch != null) {
 526  0
                     responsibility.setResponsibilityId(exactMatch.getResponsibilityId());
 527  
             }
 528  0
     }
 529  
     
 530  
     /**
 531  
      * Checks if the given responsibilities are exact matches of one another.
 532  
      */
 533  
     private boolean isExactResponsibilityMatch(RuleResponsibilityBo newResponsibility, RuleResponsibilityBo existingResponsibility) {
 534  0
             if (existingResponsibility.getResponsibilityId().equals(newResponsibility.getResponsibilityId())) {
 535  0
                     return true;
 536  
             }
 537  0
             if (existingResponsibility.getRuleResponsibilityName().equals(newResponsibility.getRuleResponsibilityName()) &&
 538  
                             existingResponsibility.getRuleResponsibilityType().equals(newResponsibility.getRuleResponsibilityType()) &&
 539  
                             existingResponsibility.getApprovePolicy().equals(newResponsibility.getApprovePolicy()) &&
 540  
                             existingResponsibility.getActionRequestedCd().equals(newResponsibility.getActionRequestedCd()) &&
 541  
                             existingResponsibility.getPriority().equals(newResponsibility.getPriority())) {
 542  0
                     return true;
 543  
             }
 544  0
             return false;
 545  
     }
 546  
 
 547  
     private List parseRuleExtensions(Element element, RuleBaseValues rule) throws XmlException {
 548  0
         if (element == null) {
 549  0
             return new ArrayList();
 550  
         }
 551  0
         RuleExtensionXmlParser parser = new RuleExtensionXmlParser();
 552  0
         return parser.parseRuleExtensions(element, rule);
 553  
     }
 554  
     
 555  
     public Timestamp formatDate(String dateLabel, String dateString) throws XmlException {
 556  0
             if (StringUtils.isBlank(dateString)) {
 557  0
                     return null;
 558  
             }
 559  
             try {
 560  0
                     return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
 561  0
             } catch (ParseException e) {
 562  0
                     throw new XmlException(dateLabel + " is not in the proper format.  Should have been: " + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
 563  
             }
 564  
     }
 565  
     
 566  
 }