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-2007 The Kuali Foundation
 3  
  *
 4  
  *
 5  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.opensource.org/licenses/ecl2.php
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.kuali.rice.kew.xml;
 18  
 
 19  
 import java.io.IOException;
 20  
 import java.io.InputStream;
 21  
 import java.sql.Timestamp;
 22  
 import java.text.ParseException;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 
 27  
 import javax.xml.parsers.ParserConfigurationException;
 28  
 
 29  
 import org.apache.commons.lang.StringUtils;
 30  
 import org.jdom.Document;
 31  
 import org.jdom.Element;
 32  
 import org.jdom.JDOMException;
 33  
 import org.kuali.rice.core.util.RiceConstants;
 34  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 35  
 import org.kuali.rice.kew.exception.InvalidXmlException;
 36  
 import org.kuali.rice.kew.rule.Role;
 37  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 38  
 import org.kuali.rice.kew.rule.RuleDelegation;
 39  
 import org.kuali.rice.kew.rule.RuleExpressionDef;
 40  
 import org.kuali.rice.kew.rule.RuleResponsibility;
 41  
 import org.kuali.rice.kew.rule.bo.RuleTemplate;
 42  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 43  
 import org.kuali.rice.kew.util.KEWConstants;
 44  
 import org.kuali.rice.kew.util.Utilities;
 45  
 import org.kuali.rice.kew.util.XmlHelper;
 46  
 import org.kuali.rice.kim.bo.Group;
 47  
 import org.kuali.rice.kim.bo.entity.KimPrincipal;
 48  
 import org.kuali.rice.kim.service.KIMServiceLocator;
 49  
 import org.xml.sax.SAXException;
 50  
 
 51  
 
 52  
 /**
 53  
  * Parses rules from XML.
 54  
  *
 55  
  * @see RuleBaseValues
 56  
  *
 57  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 58  
  */
 59  0
 public class RuleXmlParser implements XmlConstants {
 60  
 
 61  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RuleXmlParser.class);
 62  
 
 63  
     /**
 64  
      * Priority to use if rule responsibility omits priority
 65  
      */
 66  
     private static final int DEFAULT_RULE_PRIORITY = 1;
 67  
     /**
 68  
      * Value of Force Action flag if omitted; default to false, we will NOT force action for approvals
 69  
      */
 70  
     private static final boolean DEFAULT_FORCE_ACTION = false;
 71  
     /**
 72  
      * Default approve policy, if omitted; defaults to FIRST_APPROVE, the request will be satisfied by the first approval
 73  
      */
 74  
     private static final String DEFAULT_APPROVE_POLICY = KEWConstants.APPROVE_POLICY_FIRST_APPROVE;
 75  
     /**
 76  
      * Default action requested, if omitted; defaults to "A"pprove
 77  
      */
 78  
     private static final String DEFAULT_ACTION_REQUESTED = KEWConstants.ACTION_REQUEST_APPROVE_REQ;
 79  
 
 80  
     public List<RuleDelegation> parseRuleDelegations(InputStream input) throws IOException, InvalidXmlException {
 81  
             try {
 82  0
             Document doc = XmlHelper.trimSAXXml(input);
 83  0
             Element root = doc.getRootElement();
 84  0
             return parseRuleDelegations(root);
 85  0
         } catch (JDOMException e) {
 86  0
             throw new InvalidXmlException("Parse error.", e);
 87  0
         } catch (SAXException e){
 88  0
             throw new InvalidXmlException("Parse error.",e);
 89  0
         } catch(ParserConfigurationException e){
 90  0
             throw new InvalidXmlException("Parse error.",e);
 91  
         }
 92  
     }
 93  
     
 94  
     public List<RuleBaseValues> parseRules(InputStream input) throws IOException, InvalidXmlException {
 95  
         try {
 96  0
             Document doc = XmlHelper.trimSAXXml(input);
 97  0
             Element root = doc.getRootElement();
 98  0
             return parseRules(root);
 99  0
         } catch (JDOMException e) {
 100  0
             throw new InvalidXmlException("Parse error.", e);
 101  0
         } catch (SAXException e){
 102  0
             throw new InvalidXmlException("Parse error.",e);
 103  0
         } catch(ParserConfigurationException e){
 104  0
             throw new InvalidXmlException("Parse error.",e);
 105  
         }
 106  
     }
 107  
 
 108  
     /**
 109  
      * Parses and saves rules
 110  
      * @param element top-level 'data' element which should contain a <rules> child element
 111  
      * @throws InvalidXmlException
 112  
      */
 113  
     public List<RuleBaseValues> parseRules(Element element) throws InvalidXmlException {
 114  0
             List<RuleBaseValues> rulesToSave = new ArrayList<RuleBaseValues>();
 115  0
         for (Element rulesElement: (List<Element>) element.getChildren(RULES, RULE_NAMESPACE)) {
 116  0
             for (Element ruleElement: (List<Element>) rulesElement.getChildren(RULE, RULE_NAMESPACE)) {
 117  0
                 RuleBaseValues rule = parseRule(ruleElement);
 118  0
                 rulesToSave.add(rule);
 119  0
             }
 120  
         }
 121  0
         checkForDuplicateRules(rulesToSave);
 122  0
         return KEWServiceLocator.getRuleService().saveRules(rulesToSave, false);
 123  
     }
 124  
     
 125  
     /**
 126  
      * Parses and saves rule delegations
 127  
      * @param element top-level 'data' element which should contain a <rules> child element
 128  
      * @throws InvalidXmlException
 129  
      */
 130  
     public List<RuleDelegation> parseRuleDelegations(Element element) throws InvalidXmlException {
 131  0
             List<RuleDelegation> ruleDelegationsToSave = new ArrayList<RuleDelegation>();
 132  0
         for (Element ruleDelegationsElement: (List<Element>) element.getChildren(RULE_DELEGATIONS, RULE_NAMESPACE)) {
 133  0
             for (Element ruleDelegationElement: (List<Element>) ruleDelegationsElement.getChildren(RULE_DELEGATION, RULE_NAMESPACE)) {
 134  0
                 RuleDelegation ruleDelegation = parseRuleDelegation(ruleDelegationElement);
 135  0
                 ruleDelegationsToSave.add(ruleDelegation);
 136  0
             }
 137  
         }
 138  
         //checkForDuplicateRuleDelegations(ruleDelegationsToSave);
 139  0
         return KEWServiceLocator.getRuleService().saveRuleDelegations(ruleDelegationsToSave, false);
 140  
     }
 141  
     
 142  
     /**
 143  
      * Checks for rules in the List that duplicate other Rules already in the system 
 144  
      */
 145  
     private void checkForDuplicateRules(List<RuleBaseValues> rules) throws InvalidXmlException {
 146  0
             for (RuleBaseValues rule : rules) {
 147  0
                     if (StringUtils.isBlank(rule.getName())) {
 148  0
                             LOG.debug("Checking for rule duplication on an anonymous rule.");
 149  0
                             checkRuleForDuplicate(rule);
 150  
                     }
 151  
             }
 152  0
     }
 153  
     
 154  
     /**
 155  
      * Checks for rule delegations in the List that duplicate other Rules already in the system 
 156  
      */
 157  
     private void checkForDuplicateRuleDelegations(List<RuleDelegation> ruleDelegations) throws InvalidXmlException {
 158  0
             for (RuleDelegation ruleDelegation : ruleDelegations) {
 159  0
                     if (StringUtils.isBlank(ruleDelegation.getDelegationRuleBaseValues().getName())) {
 160  0
                             LOG.debug("Checking for rule duplication on an anonymous rule delegation.");
 161  0
                             checkRuleDelegationForDuplicate(ruleDelegation);
 162  
                     }
 163  
             }
 164  0
     }
 165  
 
 166  
     private RuleDelegation parseRuleDelegation(Element element) throws InvalidXmlException {
 167  0
             RuleDelegation ruleDelegation = new RuleDelegation();
 168  0
             Element parentResponsibilityElement = element.getChild(PARENT_RESPONSIBILITY, element.getNamespace());
 169  0
             if (parentResponsibilityElement == null) {
 170  0
                     throw new InvalidXmlException("parent responsibility was not defined");
 171  
             }
 172  0
             Long parentResponsibilityId = parseParentResponsibilityId(parentResponsibilityElement);
 173  0
             String delegationType = element.getChildText(DELEGATION_TYPE, element.getNamespace());
 174  0
         if (delegationType == null || !(delegationType.equals(KEWConstants.DELEGATION_PRIMARY) || delegationType.equals(KEWConstants.DELEGATION_SECONDARY))) {
 175  0
             throw new InvalidXmlException("Invalid delegation type specified for delegate rule '" + delegationType + "'");
 176  
         }
 177  
         
 178  0
         ruleDelegation.setResponsibilityId(parentResponsibilityId);
 179  0
         ruleDelegation.setDelegationType(delegationType);
 180  
         
 181  0
         Element ruleElement = element.getChild(RULE, element.getNamespace());
 182  0
         RuleBaseValues rule = parseRule(ruleElement);
 183  0
         rule.setDelegateRule(true);
 184  0
         ruleDelegation.setDelegationRuleBaseValues(rule);
 185  
             
 186  0
             return ruleDelegation;
 187  
     }
 188  
     
 189  
     private Long parseParentResponsibilityId(Element element) throws InvalidXmlException {
 190  0
             String responsibilityId = element.getChildText(RESPONSIBILITY_ID, element.getNamespace());
 191  0
             if (!StringUtils.isBlank(responsibilityId)) {
 192  0
                     return Long.valueOf(responsibilityId);
 193  
             }
 194  0
             String parentRuleName = element.getChildText(PARENT_RULE_NAME, element.getNamespace());
 195  0
             if (StringUtils.isBlank(parentRuleName)) {
 196  0
                     throw new InvalidXmlException("One of responsibilityId or parentRuleName needs to be defined");
 197  
             }
 198  0
             RuleBaseValues parentRule = KEWServiceLocator.getRuleService().getRuleByName(parentRuleName);
 199  0
             if (parentRule == null) {
 200  0
                     throw new InvalidXmlException("Could find the parent rule with name '" + parentRuleName + "'");
 201  
             }
 202  0
             RuleResponsibility ruleResponsibilityNameAndType = parseResponsibilityNameAndType(element);
 203  0
             if (ruleResponsibilityNameAndType == null) {
 204  0
                     throw new InvalidXmlException("Could not locate a valid responsibility declaration for the parent responsibility.");
 205  
             }
 206  0
             Long parentResponsibilityId = KEWServiceLocator.getRuleService().findResponsibilityIdForRule(parentRuleName, 
 207  
                             ruleResponsibilityNameAndType.getRuleResponsibilityName(),
 208  
                             ruleResponsibilityNameAndType.getRuleResponsibilityType());
 209  0
             if (parentResponsibilityId == null) {
 210  0
                     throw new InvalidXmlException("Failed to locate parent responsibility for rule with name '" + parentRuleName + "' and responsibility " + ruleResponsibilityNameAndType);
 211  
             }
 212  0
             return parentResponsibilityId;
 213  
     }
 214  
     
 215  
     /**
 216  
      * Parses, and only parses, a rule definition (be it a top-level rule, or a rule delegation).  This method will
 217  
      * NOT dirty or save any existing data, it is side-effect-free.
 218  
      * @param element the rule element
 219  
      * @param ruleDelegation the ruleDelegation object if this rule is being parsed as a delegation
 220  
      * @return a new RuleBaseValues object which is not yet saved
 221  
      * @throws InvalidXmlException
 222  
      */
 223  
     private RuleBaseValues parseRule(Element element) throws InvalidXmlException {
 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.setToDate(formatDate("toDate", toDatestr));
 233  0
         rule.setFromDate(formatDate("fromDate", fromDatestr));
 234  
 
 235  0
         String description = element.getChildText(DESCRIPTION, element.getNamespace());
 236  0
         if (StringUtils.isBlank(description)) {
 237  0
             throw new InvalidXmlException("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 InvalidXmlException("Rule must have a document type.");
 243  
         }
 244  0
         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
 245  0
         if (documentType == null) {
 246  0
                 throw new InvalidXmlException("Could not locate document type '" + documentTypeName + "'");
 247  
         }
 248  
 
 249  0
         RuleTemplate 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 InvalidXmlException("Could not locate rule template '" + ruleTemplateName + "'");
 256  
                 }
 257  
         } else {
 258  0
                 if (ruleExtensionsElement != null) {
 259  0
                         throw new InvalidXmlException("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 InvalidXmlException("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.getRuleTemplateId());
 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.setResponsibilities(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 = KEWServiceLocator.getRuleService().getRuleByName(ruleName);
 309  0
             if (existingRule != null) {
 310  
                     // copy keys and responsibiliities from the existing rule
 311  0
                     rule.setRuleBaseValuesId(existingRule.getRuleBaseValuesId());
 312  0
                     rule.setPreviousVersionId(existingRule.getPreviousVersionId());
 313  0
                     rule.setPreviousVersion(existingRule.getPreviousVersion());
 314  0
                     rule.setResponsibilities(existingRule.getResponsibilities());
 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 InvalidXmlException if this incoming rule duplicates an existing rule
 324  
      */
 325  
     private void checkRuleForDuplicate(RuleBaseValues rule) throws InvalidXmlException {
 326  0
         Long ruleId = KEWServiceLocator.getRuleService().getDuplicateRuleId(rule);
 327  0
         if (ruleId != null) {
 328  0
                 throw new InvalidXmlException("Rule '" + rule.getDescription() + "' on doc '" + rule.getDocTypeName() + "' is a duplicate of rule with rule Id " + ruleId);
 329  
         }
 330  0
     }
 331  
     
 332  
     private void checkRuleDelegationForDuplicate(RuleDelegation ruleDelegation) throws InvalidXmlException {
 333  0
             checkRuleForDuplicate(ruleDelegation.getDelegationRuleBaseValues());
 334  0
     }
 335  
 
 336  
     private void setDefaultRuleValues(RuleBaseValues rule) throws InvalidXmlException {
 337  0
         rule.setForceAction(Boolean.FALSE);
 338  0
         rule.setActivationDate(new Timestamp(System.currentTimeMillis()));
 339  0
         rule.setActiveInd(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<RuleResponsibility> parseResponsibilities(Element element, RuleBaseValues rule) throws InvalidXmlException {
 347  0
         if (element == null) {
 348  0
             return new ArrayList<RuleResponsibility>(0);
 349  
         }
 350  0
         List<RuleResponsibility> existingResponsibilities = rule.getResponsibilities();
 351  0
         List<RuleResponsibility> responsibilities = new ArrayList<RuleResponsibility>();
 352  0
         List responsibilityElements = element.getChildren(RESPONSIBILITY, element.getNamespace());
 353  0
         for (Iterator iterator = responsibilityElements.iterator(); iterator.hasNext();) {
 354  0
             Element responsibilityElement = (Element) iterator.next();
 355  0
             RuleResponsibility responsibility = parseResponsibility(responsibilityElement, rule);
 356  0
             reconcileWithExistingResponsibility(responsibility, existingResponsibilities);
 357  0
             responsibilities.add(responsibility);
 358  0
         }
 359  0
         if (responsibilities.size() == 0) {
 360  0
             throw new InvalidXmlException("Rule responsibility list must have at least one responsibility.");
 361  
         }
 362  0
         return responsibilities;
 363  
     }
 364  
 
 365  
     public RuleResponsibility parseResponsibility(Element element, RuleBaseValues rule) throws InvalidXmlException {
 366  0
         RuleResponsibility responsibility = new RuleResponsibility();
 367  0
         responsibility.setRuleBaseValues(rule);
 368  0
         String actionRequested = null;
 369  0
         String priority = null;
 370  0
         actionRequested = element.getChildText(ACTION_REQUESTED, element.getNamespace());
 371  0
         if (StringUtils.isBlank(actionRequested)) {
 372  0
                 actionRequested = DEFAULT_ACTION_REQUESTED;
 373  
         }
 374  0
         priority = element.getChildText(PRIORITY, element.getNamespace());
 375  0
         if (StringUtils.isBlank(priority)) {
 376  0
                 priority = String.valueOf(DEFAULT_RULE_PRIORITY);
 377  
         }
 378  0
         String approvePolicy = element.getChildText(APPROVE_POLICY, element.getNamespace());
 379  0
         Element delegations = element.getChild(DELEGATIONS, element.getNamespace());
 380  0
         if (actionRequested == null) {
 381  0
             throw new InvalidXmlException("actionRequested is required on responsibility");
 382  
         }
 383  0
         if (!actionRequested.equals(KEWConstants.ACTION_REQUEST_COMPLETE_REQ) && !actionRequested.equals(KEWConstants.ACTION_REQUEST_APPROVE_REQ) && !actionRequested.equals(KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ) && !actionRequested.equals(KEWConstants.ACTION_REQUEST_FYI_REQ)) {
 384  0
             throw new InvalidXmlException("Invalid action requested code '" + actionRequested + "'");
 385  
         }
 386  0
         if (StringUtils.isBlank(approvePolicy)) {
 387  0
             approvePolicy = DEFAULT_APPROVE_POLICY;
 388  
         }
 389  0
         if (!approvePolicy.equals(KEWConstants.APPROVE_POLICY_ALL_APPROVE) && !approvePolicy.equals(KEWConstants.APPROVE_POLICY_FIRST_APPROVE)) {
 390  0
             throw new InvalidXmlException("Invalid approve policy '" + approvePolicy + "'");
 391  
         }
 392  0
         Integer priorityNumber = Integer.valueOf(priority);
 393  0
         responsibility.setActionRequestedCd(actionRequested);
 394  0
         responsibility.setPriority(priorityNumber);
 395  0
         responsibility.setApprovePolicy(approvePolicy);
 396  
         
 397  0
         RuleResponsibility responsibilityNameAndType = parseResponsibilityNameAndType(element);
 398  0
         if (responsibilityNameAndType == null) {
 399  0
                 throw new InvalidXmlException("Could not locate a valid responsibility declaration on a responsibility on rule with description '" + rule.getDescription() + "'");
 400  
         }
 401  0
         if (responsibilityNameAndType.getRuleResponsibilityType().equals(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID)
 402  
                         && responsibility.getApprovePolicy().equals(KEWConstants.APPROVE_POLICY_ALL_APPROVE)) {
 403  0
                 throw new InvalidXmlException("Invalid approve policy '" + approvePolicy + "'.  This policy is not supported with Groups.");
 404  
         }
 405  0
         responsibility.setRuleResponsibilityName(responsibilityNameAndType.getRuleResponsibilityName());
 406  0
         responsibility.setRuleResponsibilityType(responsibilityNameAndType.getRuleResponsibilityType());
 407  
         
 408  0
         return responsibility;
 409  
     }
 410  
 
 411  
     public RuleResponsibility parseResponsibilityNameAndType(Element element) throws InvalidXmlException {
 412  0
             RuleResponsibility responsibility = new RuleResponsibility();
 413  
             
 414  0
             String principalId = element.getChildText(PRINCIPAL_ID, element.getNamespace());
 415  0
         String principalName = element.getChildText(PRINCIPAL_NAME, element.getNamespace());
 416  0
         String groupId = element.getChildText(GROUP_ID, element.getNamespace());
 417  0
         Element groupNameElement = element.getChild(GROUP_NAME, element.getNamespace());
 418  0
         String role = element.getChildText(ROLE, element.getNamespace());
 419  0
         Element roleNameElement = element.getChild(ROLE_NAME, element.getNamespace());
 420  
         
 421  0
         String user = element.getChildText(USER, element.getNamespace());
 422  0
         String workgroup = element.getChildText(WORKGROUP, element.getNamespace());
 423  
         
 424  0
         if (!StringUtils.isEmpty(user)) {
 425  0
                 principalName = user;
 426  0
                 LOG.warn("Rule XML is using deprecated element 'user', please use 'principalName' instead.");
 427  
         }
 428  
         
 429  
         // in code below, we allow core config parameter replacement in responsibilities
 430  0
         if (!StringUtils.isBlank(principalId)) {
 431  0
                 principalId = Utilities.substituteConfigParameters(principalId);
 432  0
                 KimPrincipal principal = KIMServiceLocator.getIdentityManagementService().getPrincipal(principalId);
 433  0
             if (principal == null) {
 434  0
                     throw new InvalidXmlException("Could not locate principal with the given id: " + principalId);
 435  
             }
 436  0
             responsibility.setRuleResponsibilityName(principalId);
 437  0
             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 438  0
         } else if (!StringUtils.isBlank(principalName)) {
 439  0
                 principalName = Utilities.substituteConfigParameters(principalName);
 440  0
                 KimPrincipal principal = KIMServiceLocator.getIdentityManagementService().getPrincipalByPrincipalName(principalName);
 441  0
             if (principal == null) {
 442  0
                     throw new InvalidXmlException("Could not locate principal with the given name: " + principalName);
 443  
             }
 444  0
             responsibility.setRuleResponsibilityName(principal.getPrincipalId());
 445  0
             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 446  0
         } else if (!StringUtils.isBlank(groupId)) {
 447  0
             groupId = Utilities.substituteConfigParameters(groupId);
 448  0
             Group group = KIMServiceLocator.getIdentityManagementService().getGroup(groupId);
 449  0
             if (group == null) {
 450  0
                 throw new InvalidXmlException("Could not locate group with the given id: " + groupId);
 451  
             }
 452  0
             responsibility.setRuleResponsibilityName(groupId);
 453  0
             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID);
 454  0
         } else if (groupNameElement != null) {
 455  0
                 String groupName = groupNameElement.getText();
 456  0
                 String groupNamespace = groupNameElement.getAttributeValue(NAMESPACE);
 457  0
                 if (StringUtils.isBlank(groupName)) {
 458  0
                         throw new InvalidXmlException("Group name element has no value");
 459  
                 }
 460  0
                 if (StringUtils.isBlank(groupNamespace)) {
 461  0
                         throw new InvalidXmlException("namespace attribute must be specified");
 462  
                 }
 463  0
             groupName = Utilities.substituteConfigParameters(groupName);
 464  0
             groupNamespace = Utilities.substituteConfigParameters(groupNamespace);
 465  0
             Group group = KIMServiceLocator.getIdentityManagementService().getGroupByName(groupNamespace, groupName);
 466  0
             if (group == null) {
 467  0
                 throw new InvalidXmlException("Could not locate group with the given namespace: " + groupNamespace + " and name: " + groupName);
 468  
             }
 469  0
             responsibility.setRuleResponsibilityName(group.getGroupId());
 470  0
             responsibility.setRuleResponsibilityType(KEWConstants.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(KEWConstants.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 InvalidXmlException("Role name element has no value");
 480  
                 }
 481  0
                 if (StringUtils.isBlank(attributeClassName)) {
 482  0
                         throw new InvalidXmlException("attributeClassName attribute must be specified");
 483  
                 }
 484  0
                 roleName = Utilities.substituteConfigParameters(roleName);
 485  0
                 attributeClassName = Utilities.substituteConfigParameters(attributeClassName);
 486  0
                 responsibility.setRuleResponsibilityName(Role.constructRoleValue(attributeClassName, roleName));
 487  0
             responsibility.setRuleResponsibilityType(KEWConstants.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 = KIMServiceLocator.getIdentityManagementService().getGroupByName(workgroupNamespace, workgroupName);
 495  0
             if (workgroupObject == null) {
 496  0
                 throw new InvalidXmlException("Could not locate workgroup: " + workgroup);
 497  
             }
 498  0
             responsibility.setRuleResponsibilityName(workgroupObject.getGroupId());
 499  0
             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID);
 500  0
         } else {
 501  0
                 return null;
 502  
         }
 503  
         
 504  0
         return responsibility;
 505  
     }
 506  
     
 507  
     /**
 508  
      * Attempts to reconcile the given RuleResponsibility with the list of existing responsibilities (in the case of a
 509  
      * rule being updated via the XML).  This goal of this code is to copy responsibility ids from existing responsibilities
 510  
      * to the new responsibility where appropriate.  The code will attempt to find exact matches based on the values found
 511  
      * on the responsibilities.
 512  
      */
 513  
     private void reconcileWithExistingResponsibility(RuleResponsibility responsibility, List<RuleResponsibility> existingResponsibilities) {
 514  0
             if (existingResponsibilities == null || existingResponsibilities.isEmpty()) {
 515  0
                     return;
 516  
             }
 517  0
             RuleResponsibility exactMatch = null;
 518  0
             for (RuleResponsibility existingResponsibility : existingResponsibilities) {
 519  0
                     if (isExactResponsibilityMatch(responsibility, existingResponsibility)) {
 520  0
                             exactMatch = existingResponsibility;
 521  0
                             break;
 522  
                     }
 523  
             }
 524  0
             if (exactMatch != null) {
 525  0
                     responsibility.setResponsibilityId(exactMatch.getResponsibilityId());
 526  
             }
 527  0
     }
 528  
     
 529  
     /**
 530  
      * Checks if the given responsibilities are exact matches of one another.
 531  
      */
 532  
     private boolean isExactResponsibilityMatch(RuleResponsibility newResponsibility, RuleResponsibility existingResponsibility) {
 533  0
             if (existingResponsibility.getResponsibilityId().equals(newResponsibility.getResponsibilityId())) {
 534  0
                     return true;
 535  
             }
 536  0
             if (existingResponsibility.getRuleResponsibilityName().equals(newResponsibility.getRuleResponsibilityName()) &&
 537  
                             existingResponsibility.getRuleResponsibilityType().equals(newResponsibility.getRuleResponsibilityType()) &&
 538  
                             existingResponsibility.getApprovePolicy().equals(newResponsibility.getApprovePolicy()) &&
 539  
                             existingResponsibility.getActionRequestedCd().equals(newResponsibility.getActionRequestedCd()) &&
 540  
                             existingResponsibility.getPriority().equals(newResponsibility.getPriority())) {
 541  0
                     return true;
 542  
             }
 543  0
             return false;
 544  
     }
 545  
 
 546  
     private List parseRuleExtensions(Element element, RuleBaseValues rule) throws InvalidXmlException {
 547  0
         if (element == null) {
 548  0
             return new ArrayList();
 549  
         }
 550  0
         RuleExtensionXmlParser parser = new RuleExtensionXmlParser();
 551  0
         return parser.parseRuleExtensions(element, rule);
 552  
     }
 553  
     
 554  
     public Timestamp formatDate(String dateLabel, String dateString) throws InvalidXmlException {
 555  0
             if (StringUtils.isBlank(dateString)) {
 556  0
                     return null;
 557  
             }
 558  
             try {
 559  0
                     return new Timestamp(RiceConstants.getDefaultDateFormat().parse(dateString).getTime());
 560  0
             } catch (ParseException e) {
 561  0
                     throw new InvalidXmlException(dateLabel + " is not in the proper format.  Should have been: " + RiceConstants.DEFAULT_DATE_FORMAT_PATTERN);
 562  
             }
 563  
     }
 564  
     
 565  
 }