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