Coverage Report - org.kuali.rice.kew.rule.service.impl.RuleServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
RuleServiceImpl
0%
0/867
0%
0/494
4.416
RuleServiceImpl$1
N/A
N/A
4.416
RuleServiceImpl$RuleDelegationSorter
0%
0/7
0%
0/4
4.416
RuleServiceImpl$RuleRoutingConfig
0%
0/28
0%
0/20
4.416
RuleServiceImpl$RuleVersion
0%
0/1
N/A
4.416
 
 1  
 /*
 2  
  * Copyright 2005-2008 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.rule.service.impl;
 18  
 
 19  
 import java.io.InputStream;
 20  
 import java.sql.Timestamp;
 21  
 import java.text.ParseException;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Collection;
 24  
 import java.util.Collections;
 25  
 import java.util.Comparator;
 26  
 import java.util.HashMap;
 27  
 import java.util.HashSet;
 28  
 import java.util.Iterator;
 29  
 import java.util.List;
 30  
 import java.util.Map;
 31  
 import java.util.Set;
 32  
 
 33  
 import javax.xml.namespace.QName;
 34  
 import org.apache.commons.beanutils.PropertyUtils;
 35  
 import org.apache.commons.collections.ComparatorUtils;
 36  
 import org.apache.commons.lang.ObjectUtils;
 37  
 import org.apache.commons.lang.StringUtils;
 38  
 import org.jdom.Element;
 39  
 import org.kuali.rice.core.util.RiceConstants;
 40  
 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
 41  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 42  
 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
 43  
 import org.kuali.rice.kew.dto.WorkflowIdDTO;
 44  
 import org.kuali.rice.kew.exception.WorkflowException;
 45  
 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
 46  
 import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
 47  
 import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
 48  
 import org.kuali.rice.kew.export.ExportDataSet;
 49  
 import org.kuali.rice.kew.identity.Id;
 50  
 import org.kuali.rice.kew.messaging.MessageServiceNames;
 51  
 import org.kuali.rice.kew.responsibility.service.ResponsibilityIdService;
 52  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 53  
 import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
 54  
 import org.kuali.rice.kew.rule.MyRules2;
 55  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 56  
 import org.kuali.rice.kew.rule.RuleDelegation;
 57  
 import org.kuali.rice.kew.rule.RuleExtension;
 58  
 import org.kuali.rice.kew.rule.RuleExtensionValue;
 59  
 import org.kuali.rice.kew.rule.RuleResponsibility;
 60  
 import org.kuali.rice.kew.rule.RuleRoutingDefinition;
 61  
 import org.kuali.rice.kew.rule.RuleValidationAttribute;
 62  
 import org.kuali.rice.kew.rule.bo.RuleTemplate;
 63  
 import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
 64  
 import org.kuali.rice.kew.rule.dao.RuleDAO;
 65  
 import org.kuali.rice.kew.rule.dao.RuleResponsibilityDAO;
 66  
 import org.kuali.rice.kew.rule.service.RuleCacheProcessor;
 67  
 import org.kuali.rice.kew.rule.service.RuleDelegationCacheProcessor;
 68  
 import org.kuali.rice.kew.rule.service.RuleDelegationService;
 69  
 import org.kuali.rice.kew.rule.service.RuleService;
 70  
 import org.kuali.rice.kew.rule.service.RuleTemplateService;
 71  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 72  
 import org.kuali.rice.kew.service.WorkflowDocument;
 73  
 import org.kuali.rice.kew.user.UserId;
 74  
 import org.kuali.rice.kew.util.KEWConstants;
 75  
 import org.kuali.rice.kew.util.PerformanceLogger;
 76  
 import org.kuali.rice.kew.util.Utilities;
 77  
 import org.kuali.rice.kew.validation.RuleValidationContext;
 78  
 import org.kuali.rice.kew.validation.ValidationResults;
 79  
 import org.kuali.rice.kew.web.session.UserSession;
 80  
 import org.kuali.rice.kew.workgroup.GroupId;
 81  
 import org.kuali.rice.kew.xml.RuleXmlParser;
 82  
 import org.kuali.rice.kew.xml.XmlConstants;
 83  
 import org.kuali.rice.kew.xml.export.RuleXmlExporter;
 84  
 import org.kuali.rice.kim.bo.Group;
 85  
 import org.kuali.rice.kim.bo.entity.KimPrincipal;
 86  
 import org.kuali.rice.kim.service.IdentityManagementService;
 87  
 import org.kuali.rice.kim.service.KIMServiceLocator;
 88  
 import org.kuali.rice.kns.util.Guid;
 89  
 import org.kuali.rice.kns.util.KNSConstants;
 90  
 import org.kuali.rice.ksb.service.KSBServiceLocator;
 91  
 
 92  
 
 93  0
 public class RuleServiceImpl implements RuleService {
 94  
 
 95  
     private static final String USING_RULE_CACHE_IND = "CACHING_IND";
 96  
     private static final String XML_PARSE_ERROR = "general.error.parsexml";
 97  
     private static final String RULE_GROUP_CACHE = "org.kuali.workflow.rules.RuleCache";
 98  
 
 99  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RuleServiceImpl.class);
 100  
 
 101  
     private RuleDAO ruleDAO;
 102  
     private RuleResponsibilityDAO ruleResponsibilityDAO;
 103  
 
 104  
     public RuleResponsibilityDAO getRuleResponsibilityDAO() {
 105  0
         return ruleResponsibilityDAO;
 106  
     }
 107  
 
 108  
     public RuleBaseValues getRuleByName(String name) {
 109  0
         return ruleDAO.findRuleBaseValuesByName(name);
 110  
     }
 111  
 
 112  
     public RuleBaseValues findDefaultRuleByRuleTemplateId(Long ruleTemplateId){
 113  0
         return this.ruleDAO.findDefaultRuleByRuleTemplateId(ruleTemplateId);
 114  
     }
 115  
     public void setRuleResponsibilityDAO(RuleResponsibilityDAO ruleResponsibilityDAO) {
 116  0
         this.ruleResponsibilityDAO = ruleResponsibilityDAO;
 117  0
     }
 118  
 
 119  
     public void save2(RuleBaseValues ruleBaseValues) throws Exception {
 120  0
         save2(ruleBaseValues, null, true);
 121  0
     }
 122  
 
 123  
     public void save2(RuleBaseValues ruleBaseValues, RuleDelegation ruleDelegation, boolean saveDelegations) throws Exception {
 124  0
         if (ruleBaseValues.getPreviousVersionId() != null) {
 125  0
             RuleBaseValues oldRule = findRuleBaseValuesById(ruleBaseValues.getPreviousVersionId());
 126  0
             ruleBaseValues.setPreviousVersion(oldRule);
 127  0
             ruleBaseValues.setCurrentInd(Boolean.FALSE);
 128  0
             ruleBaseValues.setVersionNbr(getNextVersionNumber(oldRule));
 129  
         }
 130  0
         if (ruleBaseValues.getVersionNbr() == null) {
 131  0
             ruleBaseValues.setVersionNbr(Integer.valueOf(0));
 132  
         }
 133  0
         if (ruleBaseValues.getCurrentInd() == null) {
 134  0
             ruleBaseValues.setCurrentInd(Boolean.FALSE);
 135  
         }
 136  
         // iterate through all associated responsibilities, and if they are unsaved (responsibilityId is null)
 137  
         // set a new id on them, and recursively save any associated delegation rules
 138  0
         for (Iterator iterator = ruleBaseValues.getResponsibilities().iterator(); iterator.hasNext();) {
 139  0
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 140  0
             if (responsibility.getResponsibilityId() == null) {
 141  0
                 responsibility.setResponsibilityId(getResponsibilityIdService().getNewResponsibilityId());
 142  
             }
 143  0
             if (saveDelegations) {
 144  0
                 for (Iterator iter = responsibility.getDelegationRules().iterator(); iter.hasNext();) {
 145  0
                     RuleDelegation localRuleDelegation = (RuleDelegation) iter.next();
 146  0
                     save2(localRuleDelegation.getDelegationRuleBaseValues(), localRuleDelegation, true);
 147  0
                 }
 148  
             }
 149  0
         }
 150  0
         validate2(ruleBaseValues, ruleDelegation, null);
 151  0
         getRuleDAO().save(ruleBaseValues);
 152  0
     }
 153  
 
 154  
     public void makeCurrent(Long routeHeaderId) {
 155  0
         makeCurrent(findByRouteHeaderId(routeHeaderId));
 156  0
     }
 157  
 
 158  
     public void makeCurrent(List rules) {
 159  0
         PerformanceLogger performanceLogger = new PerformanceLogger();
 160  
 
 161  0
         boolean isGenerateRuleArs = true;
 162  0
         String generateRuleArs = Utilities.getKNSParameterValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
 163  0
         if (!StringUtils.isBlank(generateRuleArs)) {
 164  0
             isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
 165  
         }
 166  0
         Set responsibilityIds = new HashSet();
 167  0
         HashMap rulesToSave = new HashMap();
 168  
 
 169  0
         Collections.sort(rules, new RuleDelegationSorter());
 170  0
         boolean delegateFirst = false;
 171  0
         for (Iterator iter = rules.iterator(); iter.hasNext();) {
 172  0
             RuleBaseValues rule = (RuleBaseValues) iter.next();
 173  
 
 174  0
             performanceLogger.log("Preparing rule: " + rule.getDescription());
 175  
 
 176  0
             rule.setCurrentInd(Boolean.TRUE);
 177  0
             Timestamp date = new Timestamp(System.currentTimeMillis());
 178  0
             rule.setActivationDate(date);
 179  
             try {
 180  0
                 rule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
 181  0
             } catch (Exception e) {
 182  0
                 LOG.error("Parse Exception", e);
 183  0
             }
 184  0
             rulesToSave.put(rule.getRuleBaseValuesId(), rule);
 185  0
             RuleBaseValues oldRule = rule.getPreviousVersion();
 186  0
             if (oldRule != null) {
 187  0
                 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
 188  
 
 189  0
                 oldRule.setCurrentInd(Boolean.FALSE);
 190  0
                 oldRule.setDeactivationDate(date);
 191  0
                 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
 192  0
                 if (!delegateFirst) {
 193  0
                     responsibilityIds.addAll(getResponsibilityIdsFromGraph(oldRule, isGenerateRuleArs));
 194  
                 }
 195  
                 //TODO if more than one delegate is edited from the create delegation screen (which currently can not happen), then this logic will not work.
 196  0
                 if (rule.getDelegateRule().booleanValue() && rule.getPreviousVersionId() != null) {
 197  0
                     delegateFirst = true;
 198  
                 }
 199  
 
 200  0
                 List oldDelegationRules = findOldDelegationRules(oldRule, rule, performanceLogger);
 201  0
                 for (Iterator iterator = oldDelegationRules.iterator(); iterator.hasNext();) {
 202  0
                     RuleBaseValues delegationRule = (RuleBaseValues) iterator.next();
 203  
 
 204  0
                     performanceLogger.log("Setting previous delegation rule: " + delegationRule.getRuleBaseValuesId() + "to non current.");
 205  
 
 206  0
                     delegationRule.setCurrentInd(Boolean.FALSE);
 207  0
                     rulesToSave.put(delegationRule.getRuleBaseValuesId(), delegationRule);
 208  0
                     responsibilityIds.addAll(getResponsibilityIdsFromGraph(delegationRule, isGenerateRuleArs));
 209  0
                 }
 210  
             }
 211  0
             for (Iterator iterator = rule.getResponsibilities().iterator(); iterator.hasNext();) {
 212  0
                 RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 213  0
                 for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
 214  0
                     RuleDelegation delegation = (RuleDelegation) delIterator.next();
 215  
 
 216  0
                     delegation.getDelegationRuleBaseValues().setCurrentInd(Boolean.TRUE);
 217  0
                     RuleBaseValues delegatorRule = delegation.getDelegationRuleBaseValues();
 218  
 
 219  0
                     performanceLogger.log("Setting delegate rule: " + delegatorRule.getDescription() + " to current.");
 220  0
                     if (delegatorRule.getActivationDate() == null) {
 221  0
                         delegatorRule.setActivationDate(date);
 222  
                     }
 223  
                     try {
 224  0
                         delegatorRule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
 225  0
                     } catch (Exception e) {
 226  0
                         LOG.error("Parse Exception", e);
 227  0
                     }
 228  0
                     rulesToSave.put(delegatorRule.getRuleBaseValuesId(), delegatorRule);
 229  0
                 }
 230  0
             }
 231  0
         }
 232  0
         Map<String, Long> notifyMap = new HashMap<String, Long>();
 233  0
         for (Iterator iterator = rulesToSave.values().iterator(); iterator.hasNext();) {
 234  0
             RuleBaseValues rule = (RuleBaseValues) iterator.next();
 235  0
             getRuleDAO().save(rule);
 236  0
             performanceLogger.log("Saved rule: " + rule.getRuleBaseValuesId());
 237  0
             installNotification(rule, notifyMap);
 238  0
         }
 239  0
         LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
 240  0
         for (Iterator iterator = notifyMap.values().iterator(); iterator.hasNext();) {
 241  0
             queueRuleCache((Long)iterator.next());
 242  
         }
 243  
 
 244  0
         getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
 245  0
         performanceLogger.log("Time to make current");
 246  0
     }
 247  
 
 248  
     /**
 249  
      * TODO consolidate this method with makeCurrent.  The reason there's a seperate implementation is because the
 250  
      * original makeCurrent(...) could not properly handle versioning a List of multiple rules (including multiple
 251  
      * delegates rules for a single parent.  ALso, this work is being done for a patch so we want to mitigate the
 252  
      * impact on the existing rule code.
 253  
      *
 254  
      * <p>This version will only work for remove/replace operations where rules
 255  
      * aren't being added or removed.  This is why it doesn't perform some of the functions like checking
 256  
      * for delegation rules that were removed from a parent rule.
 257  
      */
 258  
     public void makeCurrent2(List rules) {
 259  0
         PerformanceLogger performanceLogger = new PerformanceLogger();
 260  
 
 261  0
         boolean isGenerateRuleArs = true;
 262  0
         String generateRuleArs = Utilities.getKNSParameterValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
 263  0
         if (!StringUtils.isBlank(generateRuleArs)) {
 264  0
             isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
 265  
         }
 266  0
         Set<Long> responsibilityIds = new HashSet<Long>();
 267  0
         Map<Long, RuleBaseValues> rulesToSave = new HashMap<Long, RuleBaseValues>();
 268  
 
 269  0
         Collections.sort(rules, new RuleDelegationSorter());
 270  0
         for (Iterator iter = rules.iterator(); iter.hasNext();) {
 271  0
             RuleBaseValues rule = (RuleBaseValues) iter.next();
 272  
 
 273  0
             performanceLogger.log("Preparing rule: " + rule.getDescription());
 274  
 
 275  0
             rule.setCurrentInd(Boolean.TRUE);
 276  0
             Timestamp date = new Timestamp(System.currentTimeMillis());
 277  0
             rule.setActivationDate(date);
 278  
             try {
 279  0
                 rule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
 280  0
             } catch (Exception e) {
 281  0
                 LOG.error("Parse Exception", e);
 282  0
             }
 283  0
             rulesToSave.put(rule.getRuleBaseValuesId(), rule);
 284  0
             RuleBaseValues oldRule = rule.getPreviousVersion();
 285  0
             if (oldRule != null) {
 286  0
                 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
 287  0
                 oldRule.setCurrentInd(Boolean.FALSE);
 288  0
                 oldRule.setDeactivationDate(date);
 289  0
                 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
 290  0
                 responsibilityIds.addAll(getModifiedResponsibilityIds(oldRule, rule));
 291  
             }
 292  0
             for (Iterator iterator = rule.getResponsibilities().iterator(); iterator.hasNext();) {
 293  0
                 RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 294  0
                 for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
 295  0
                     RuleDelegation delegation = (RuleDelegation) delIterator.next();
 296  0
                     RuleBaseValues delegateRule = delegation.getDelegationRuleBaseValues();
 297  0
                     delegateRule.setCurrentInd(Boolean.TRUE);
 298  0
                     performanceLogger.log("Setting delegate rule: " + delegateRule.getDescription() + " to current.");
 299  0
                     if (delegateRule.getActivationDate() == null) {
 300  0
                         delegateRule.setActivationDate(date);
 301  
                     }
 302  
                     try {
 303  0
                         delegateRule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
 304  0
                     } catch (Exception e) {
 305  0
                         LOG.error("Parse Exception", e);
 306  0
                     }
 307  0
                     rulesToSave.put(delegateRule.getRuleBaseValuesId(), delegateRule);
 308  0
                 }
 309  0
             }
 310  0
         }
 311  0
         Map<String, Long> notifyMap = new HashMap<String, Long>();
 312  0
         for (RuleBaseValues rule : rulesToSave.values()) {
 313  0
             getRuleDAO().save(rule);
 314  0
             performanceLogger.log("Saved rule: " + rule.getRuleBaseValuesId());
 315  0
             installNotification(rule, notifyMap);
 316  
         }
 317  0
         LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
 318  0
         for (Iterator iterator = notifyMap.values().iterator(); iterator.hasNext();) {
 319  0
             queueRuleCache((Long)iterator.next());
 320  
         }
 321  0
         if (isGenerateRuleArs) {
 322  0
             getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
 323  
         }
 324  0
         performanceLogger.log("Time to make current");
 325  0
     }
 326  
 
 327  
     /**
 328  
      * makeCurrent(RuleBaseValues) is the version of makeCurrent which is initiated from the new Routing Rule
 329  
      * Maintenance document.  Because of the changes in the data model and the front end here,
 330  
      * this method can be much less complicated than the previous 2!
 331  
      */
 332  
     public void makeCurrent(RuleBaseValues rule, boolean isRetroactiveUpdatePermitted) {
 333  0
             makeCurrent(null, rule, isRetroactiveUpdatePermitted);
 334  0
     }
 335  
 
 336  
     public void makeCurrent(RuleDelegation ruleDelegation, boolean isRetroactiveUpdatePermitted) {
 337  0
             makeCurrent(ruleDelegation, ruleDelegation.getDelegationRuleBaseValues(), isRetroactiveUpdatePermitted);
 338  0
     }
 339  
 
 340  
     protected void makeCurrent(RuleDelegation ruleDelegation, RuleBaseValues rule, boolean isRetroactiveUpdatePermitted) {
 341  0
         PerformanceLogger performanceLogger = new PerformanceLogger();
 342  
 
 343  0
         boolean isGenerateRuleArs = false;
 344  0
         if (isRetroactiveUpdatePermitted) {
 345  0
                 isGenerateRuleArs = true;
 346  0
                 String generateRuleArs = Utilities.getKNSParameterValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
 347  0
                 if (!StringUtils.isBlank(generateRuleArs)) {
 348  0
                         isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
 349  
                 }
 350  
         }
 351  0
         Set<Long> responsibilityIds = new HashSet<Long>();
 352  
 
 353  
 
 354  0
         performanceLogger.log("Preparing rule: " + rule.getDescription());
 355  
 
 356  0
         Map<Long, RuleBaseValues> rulesToSave = new HashMap<Long, RuleBaseValues>();
 357  0
         generateRuleNameIfNeeded(rule);
 358  0
         assignResponsibilityIds(rule);
 359  0
         rule.setCurrentInd(Boolean.TRUE);
 360  0
         Timestamp date = new Timestamp(System.currentTimeMillis());
 361  0
         rule.setActivationDate(date);
 362  0
         rule.setDeactivationDate(null);
 363  
 
 364  0
         rulesToSave.put(rule.getRuleBaseValuesId(), rule);
 365  0
         if (rule.getPreviousVersionId() != null) {
 366  0
                 RuleBaseValues oldRule = findRuleBaseValuesById(rule.getPreviousVersionId());
 367  0
                 rule.setPreviousVersion(oldRule);
 368  
         }
 369  0
         rule.setVersionNbr(0);
 370  0
         RuleBaseValues oldRule = rule.getPreviousVersion();
 371  0
         if (oldRule != null) {
 372  0
                 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
 373  0
                 oldRule.setCurrentInd(Boolean.FALSE);
 374  0
                 oldRule.setDeactivationDate(date);
 375  0
                 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
 376  0
                 responsibilityIds.addAll(getModifiedResponsibilityIds(oldRule, rule));
 377  0
                 rule.setVersionNbr(getNextVersionNumber(oldRule));
 378  
         }
 379  
                
 380  
 
 381  0
         boolean isRuleDelegation = ruleDelegation != null;
 382  
         
 383  0
         Map<String, Long> notifyMap = new HashMap<String, Long>(); 
 384  
         
 385  0
         for (RuleBaseValues ruleToSave : rulesToSave.values()) {                
 386  0
                 getRuleDAO().save(ruleToSave);
 387  0
                 performanceLogger.log("Saved rule: " + ruleToSave.getRuleBaseValuesId());
 388  0
             if (!isRuleDelegation) {
 389  0
                 installNotification(ruleToSave, notifyMap);
 390  
             } 
 391  
         }
 392  0
         if (isRuleDelegation) {
 393  0
                 responsibilityIds.add(ruleDelegation.getResponsibilityId());
 394  0
                 ruleDelegation.setDelegateRuleId(rule.getRuleBaseValuesId());
 395  0
                 getRuleDelegationService().save(ruleDelegation);
 396  0
                 installDelegationNotification(ruleDelegation.getResponsibilityId(), notifyMap);
 397  
         }
 398  0
         LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
 399  0
         for (Iterator iterator = notifyMap.values().iterator(); iterator.hasNext();) {
 400  0
             if (isRuleDelegation) {
 401  0
                 queueDelegationRuleCache((Long)iterator.next());
 402  
             } else {
 403  0
                 queueRuleCache((Long)iterator.next());
 404  
             } 
 405  
         }
 406  
         
 407  
 
 408  
         
 409  0
         if (isGenerateRuleArs) {
 410  0
             getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
 411  
         }
 412  0
         performanceLogger.log("Time to make current");
 413  0
     }
 414  
 
 415  
 
 416  
     private void queueRuleCache(Long ruleId){
 417  
 //      PersistedMessage ruleCache = new PersistedMessage();
 418  
 //      ruleCache.setQueuePriority(KEWConstants.ROUTE_QUEUE_RULE_CACHE_PRIORITY);
 419  
 //      ruleCache.setQueueDate(new Timestamp(new Date().getTime()));
 420  
 //      ruleCache.setQueueStatus(KEWConstants.ROUTE_QUEUE_QUEUED);
 421  
 //      ruleCache.setRetryCount(new Integer(0));
 422  
 //      ruleCache.setPayload("" + ruleId);
 423  
 //      ruleCache.setProcessorClassName("org.kuali.rice.ksb.cache.RuleCacheProcessor");
 424  
 //      getRouteQueueService().requeueDocument(ruleCache);
 425  
 
 426  
 
 427  0
         RuleCacheProcessor ruleCacheProcessor = MessageServiceNames.getRuleCacheProcessor();
 428  0
         ruleCacheProcessor.clearRuleFromCache(ruleId);
 429  
 
 430  0
     }
 431  
 
 432  
 //  private RouteQueueService getRouteQueueService() {
 433  
 //  return (RouteQueueService)SpringServiceLocator.getService(SpringServiceLocator.ROUTE_QUEUE_SRV);
 434  
 //  }
 435  
 
 436  
     /**
 437  
      * Ensure that we don't have any notification duplication.
 438  
      */
 439  
     private void installNotification(RuleBaseValues rule, Map<String, Long> notifyMap) {
 440  
             // don't notify the cache if it's a "template" rule!
 441  0
             if (!rule.getTemplateRuleInd()) {
 442  0
                     String key = getRuleCacheKey(rule.getRuleTemplateName(), rule.getDocTypeName());
 443  0
                     if (!notifyMap.containsKey(key)) {
 444  0
                             notifyMap.put(key, rule.getRuleBaseValuesId());
 445  
                     }
 446  
             }
 447  0
     }
 448  
 
 449  
     private void queueDelegationRuleCache(Long responsibilityId) {
 450  0
         RuleDelegationCacheProcessor ruleDelegationCacheProcessor = (RuleDelegationCacheProcessor)KSBServiceLocator.getMessageHelper().getServiceAsynchronously(new QName("RuleDelegationCacheProcessorService"), null, null, null, null);        
 451  0
         ruleDelegationCacheProcessor.clearRuleDelegationFromCache(responsibilityId);            
 452  0
     }
 453  
     
 454  
     private void installDelegationNotification(Long responsibilityId, Map<String, Long> notifyMap) {
 455  
             // don't notify the cache if it's a "template" rule!
 456  0
             String key = getRuleDlgnCacheKey(responsibilityId);
 457  0
             if (!notifyMap.containsKey(key)) {
 458  0
                     notifyMap.put(key, responsibilityId);
 459  
             }
 460  0
     }
 461  
 
 462  
         protected String getRuleDlgnCacheKey(Long responsibilityId) {
 463  0
                 return "RuleDlgnCache:" + responsibilityId;
 464  
         }
 465  
         
 466  
     public RuleBaseValues getParentRule(Long ruleBaseValuesId) {
 467  0
         return getRuleDAO().getParentRule(ruleBaseValuesId);
 468  
     }
 469  
 
 470  
     public void notifyCacheOfDocumentTypeChange(DocumentType documentType) {
 471  0
         DocumentType rootDocumentType = KEWServiceLocator.getDocumentTypeService().findRootDocumentType(documentType);
 472  0
         notifyCacheOfDocumentTypeChangeFromRoot(rootDocumentType, documentType);
 473  0
         notifyCacheOfDocumentTypeChangeFromParent(documentType);
 474  0
     }
 475  
 
 476  
     /**
 477  
      * Flushes rules cached for the given DocumentType and then recursivley flushes rules cached
 478  
      * for all children DocumentTypes.
 479  
      */
 480  
     protected void notifyCacheOfDocumentTypeChangeFromParent(DocumentType documentType) {
 481  0
         flushDocumentTypeFromCache(documentType.getName());
 482  0
         for (Iterator iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
 483  0
             notifyCacheOfDocumentTypeChangeFromParent((DocumentType) iter.next());
 484  
         }
 485  0
     }
 486  
 
 487  
     /**
 488  
      * Flushes rules cached from the root of the DocumentType hierarchy (at the given root DocumentType).  Stops
 489  
      * when it hits the given DocumentType.  This method exists because of the nature of
 490  
      * DocumentTypeService.findRootDocumentType(...).  Whenever we have a modification to child document type
 491  
      * and we call findRootDocumentType(...) on it, we end up getting back a version of the root document type
 492  
      * which is cached in the OJB transaction cache and doesn't have the appropriate child document type attached.
 493  
      * A better way to handle this would be to go into the DocumentType service and fix how it versions document
 494  
      * types in versionAndSave to prevent this issue from occurring.
 495  
      *
 496  
      * <p>If such a fix was made then we could simply pass the root DocumentType into notifyCacheOfDocumentTypeChange
 497  
      * and be gauranteed that we will see all appropriate children as we call getChildrenDocTypes().
 498  
      *
 499  
      * <p>One last note, we don't necesarily have to stop this cache flusing at the given DocumentType but there's
 500  
      * no reason to duplicate the work that is going to be done in notifyCacheOfDocumentTypeChangeFromParent.
 501  
      */
 502  
     protected void notifyCacheOfDocumentTypeChangeFromRoot(DocumentType rootDocumentType, DocumentType documentType) {
 503  0
         if (rootDocumentType.getName().equals(documentType.getName())) {
 504  0
             return;
 505  
         }
 506  0
         flushDocumentTypeFromCache(rootDocumentType.getName());
 507  0
         for (Iterator iter = rootDocumentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
 508  0
             notifyCacheOfDocumentTypeChangeFromRoot((DocumentType) iter.next(), documentType);
 509  
         }
 510  0
     }
 511  
 
 512  
     public void notifyCacheOfRuleChange(RuleBaseValues rule, DocumentType documentType) {
 513  0
         Boolean cachingRules = Boolean.valueOf(Utilities.getKNSParameterBooleanValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, USING_RULE_CACHE_IND));
 514  
 
 515  0
         LOG.info("Entering notifyCacheOfRuleChange.  CachingRules: " + cachingRules + " ; ruleID: " + rule.getRuleBaseValuesId());
 516  0
         if (!cachingRules.booleanValue()) {
 517  0
             return;
 518  
         }
 519  
         // named rules may be templateless, and therefore cannot be mapped into the cache by templatename/doctype key
 520  
         // but we still need to make sure that if there was a previous version with a template, that the cache is blown away
 521  0
         String ruleTemplateName = null;
 522  0
         if (rule.getRuleTemplate() == null) {
 523  0
             if (rule.getPreviousVersion() != null) {
 524  0
                 RuleBaseValues prev = rule.getPreviousVersion();
 525  0
                 if (prev.getRuleTemplate() != null) {
 526  0
                     ruleTemplateName = prev.getRuleTemplate().getName();
 527  
                 }
 528  0
             }
 529  
         } else {
 530  0
             ruleTemplateName = rule.getRuleTemplate().getName();
 531  
         }
 532  
 
 533  0
         if (documentType == null) {
 534  0
             documentType = getDocumentTypeService().findByName(rule.getDocTypeName());
 535  
             // if it's a delegate rule, we need to look at the parent's template
 536  0
             if (Boolean.TRUE.equals(rule.getDelegateRule())) {
 537  0
                 List delegations = getRuleDelegationService().findByDelegateRuleId(rule.getRuleBaseValuesId());
 538  0
                 for (Iterator iterator = delegations.iterator(); iterator.hasNext();) {
 539  0
                     RuleDelegation ruleDelegation = (RuleDelegation) iterator.next();
 540  0
                     RuleBaseValues parentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
 541  0
                     if (Boolean.TRUE.equals(parentRule.getCurrentInd())) {
 542  0
                         ruleTemplateName = parentRule.getRuleTemplate().getName();
 543  0
                         break;
 544  
                     }
 545  0
                 }
 546  
             }
 547  
         }
 548  0
         flushListFromCache(ruleTemplateName, documentType.getName());
 549  
 
 550  
 //      if (getListFromCache(ruleTemplateName, documentType.getName()) != null) {
 551  
 //      eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentType.getName())));
 552  
 //      }
 553  
         //}
 554  
         //walk the down the document hierarchy when refreshing the cache. The
 555  
         // rule could be cached through more than one path
 556  
         //HREDOC could be cached under HREDOC.child and HREDOC.child1
 557  0
         for (Iterator iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
 558  0
             DocumentType childDocumentType = (DocumentType) iter.next();
 559  
             //SpringServiceLocator.getCacheAdministrator().flushEntry(getRuleCacheKey(ruleTemplateName, childDocumentType.getName()));
 560  
 //          if (getListFromCache(rule.getRuleTemplate().getName(), childDocumentType.getName()) != null) {
 561  
 //          eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(rule.getRuleTemplate().getName(), childDocumentType.getName())));
 562  
 //          }
 563  0
             notifyCacheOfRuleChange(rule, childDocumentType);
 564  0
         }
 565  0
         LOG.info("Leaving notifyCacheOfRuleChange.  CachingRules: " + cachingRules + " ; ruleID: " + rule.getRuleBaseValuesId() + " ; documentType: " + documentType.getDocumentTypeId());
 566  
 
 567  
 
 568  
 
 569  0
     }
 570  
 
 571  
     /**
 572  
      * Returns the key of the rule cache.
 573  
      */
 574  
     protected String getRuleCacheKey(String ruleTemplateName, String docTypeName) {
 575  0
         return "RuleCache:" + ruleTemplateName + "_" + docTypeName;
 576  
     }
 577  
 
 578  
     /*
 579  
      * Return the cache group name for the given DocumentType
 580  
      */
 581  
     protected String getDocumentTypeRuleCacheGroupName(String documentTypeName) {
 582  0
         return "DocumentTypeRuleCache:"+documentTypeName;
 583  
     }
 584  
 
 585  
     protected List<RuleBaseValues> getListFromCache(String ruleTemplateName, String documentTypeName) {
 586  0
         LOG.debug("Retrieving List of Rules from cache for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
 587  0
         return (List) KEWServiceLocator.getCacheAdministrator().getFromCache(getRuleCacheKey(ruleTemplateName, documentTypeName));
 588  
         //return (List) SpringServiceLocator.getCache().getCachedObjectById(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentTypeName));
 589  
     }
 590  
 
 591  
     protected void putListInCache(String ruleTemplateName, String documentTypeName, List<RuleBaseValues> rules) {
 592  0
         assert(ruleTemplateName != null) : "putListInCache was called with a null ruleTemplateName";
 593  0
         LOG.info("Caching " + rules.size() + " rules for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
 594  0
         String groups[] = new String[] { getDocumentTypeRuleCacheGroupName(documentTypeName), RULE_GROUP_CACHE };
 595  0
         KEWServiceLocator.getCacheAdministrator().putInCache(getRuleCacheKey(ruleTemplateName, documentTypeName), rules, groups);
 596  0
     }
 597  
 
 598  
     protected void flushDocumentTypeFromCache(String documentTypeName) {
 599  0
         LOG.info("Flushing DocumentType from Cache for the given name: " + documentTypeName);
 600  0
         KEWServiceLocator.getCacheAdministrator().flushGroup(getDocumentTypeRuleCacheGroupName(documentTypeName));
 601  0
     }
 602  
 
 603  
     protected void flushListFromCache(String ruleTemplateName, String documentTypeName) {
 604  0
         LOG.info("Flushing rules from Cache for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
 605  0
         KEWServiceLocator.getCacheAdministrator().flushEntry(getRuleCacheKey(ruleTemplateName, documentTypeName));
 606  0
     }
 607  
 
 608  
     public void flushRuleCache() {
 609  0
         LOG.info("Flushing entire Rule Cache.");
 610  0
         KEWServiceLocator.getCacheAdministrator().flushGroup(RULE_GROUP_CACHE);
 611  0
     }
 612  
 
 613  
     private Set getResponsibilityIdsFromGraph(RuleBaseValues rule, boolean isRuleCollecting) {
 614  0
         Set responsibilityIds = new HashSet();
 615  0
         for (Iterator iterator = rule.getResponsibilities().iterator(); iterator.hasNext();) {
 616  0
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 617  0
             if (isRuleCollecting) {
 618  0
                 responsibilityIds.add(responsibility.getResponsibilityId());
 619  
             }
 620  0
         }
 621  0
         return responsibilityIds;
 622  
     }
 623  
 
 624  
     /**
 625  
      * Returns the responsibility IDs that were modified between the 2 given versions of the rule.  Any added
 626  
      * or removed responsibilities are also included in the returned Set.
 627  
      */
 628  
     private Set<Long> getModifiedResponsibilityIds(RuleBaseValues oldRule, RuleBaseValues newRule) {
 629  0
         Map<Long, RuleResponsibility> modifiedResponsibilityMap = new HashMap<Long, RuleResponsibility>();
 630  0
         for (Iterator iterator = oldRule.getResponsibilities().iterator(); iterator.hasNext();) {
 631  0
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 632  0
             modifiedResponsibilityMap.put(responsibility.getResponsibilityId(), responsibility);
 633  0
         }
 634  0
         for (Iterator iterator = newRule.getResponsibilities().iterator(); iterator.hasNext();) {
 635  0
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 636  0
             RuleResponsibility oldResponsibility = modifiedResponsibilityMap.get(responsibility.getResponsibilityId());
 637  0
             if (oldResponsibility == null) {
 638  
                 // if there's no old responsibility then it's a new responsibility, add it
 639  0
                 modifiedResponsibilityMap.put(responsibility.getResponsibilityId(), responsibility);
 640  0
             } else if (!hasResponsibilityChanged(oldResponsibility, responsibility)) {
 641  
                 // if it hasn't been modified, remove it from the collection of modified ids
 642  0
                 modifiedResponsibilityMap.remove(responsibility.getResponsibilityId());
 643  
             }
 644  0
         }
 645  0
         return modifiedResponsibilityMap.keySet();
 646  
     }
 647  
 
 648  
     /**
 649  
      * Determines if the given responsibilities are different or not.
 650  
      */
 651  
     private boolean hasResponsibilityChanged(RuleResponsibility oldResponsibility, RuleResponsibility newResponsibility) {
 652  0
         return !ObjectUtils.equals(oldResponsibility.getActionRequestedCd(), newResponsibility.getActionRequestedCd()) ||
 653  
         !ObjectUtils.equals(oldResponsibility.getApprovePolicy(), newResponsibility.getActionRequestedCd()) ||
 654  
         !ObjectUtils.equals(oldResponsibility.getPriority(), newResponsibility.getPriority()) ||
 655  
         !ObjectUtils.equals(oldResponsibility.getRole(), newResponsibility.getRole()) ||
 656  
         !ObjectUtils.equals(oldResponsibility.getRuleResponsibilityName(), newResponsibility.getRuleResponsibilityName()) ||
 657  
         !ObjectUtils.equals(oldResponsibility.getRuleResponsibilityType(), newResponsibility.getRuleResponsibilityType());
 658  
     }
 659  
 
 660  
     /*
 661  
      private Map findOldDelegationRules(RuleBaseValues oldRule, RuleBaseValues newRule, PerformanceLogger performanceLogger) {
 662  
         Map oldRules = new HashMap();
 663  
         performanceLogger.log("Begin to get delegation rules.");
 664  
         for (Iterator iterator = oldRule.getResponsibilities().iterator(); iterator.hasNext();) {
 665  
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 666  
             for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
 667  
                 RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
 668  
                 RuleBaseValues delegateRule = ruleDelegation.getDelegationRuleBaseValues();
 669  
                 performanceLogger.log("Found delegate rule: "+ delegateRule.getRuleBaseValuesId());
 670  
                 oldRules.put(ruleDelegation.getDelegateRuleId(), delegateRule);
 671  
             }
 672  
         }
 673  
         performanceLogger.log("Begin removing rule delegations from new rule.");
 674  
         for (Iterator iterator = newRule.getResponsibilities().iterator(); iterator.hasNext();) {
 675  
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 676  
             for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
 677  
                 RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
 678  
                 performanceLogger.log("Removing rule delegation: "+ ruleDelegation.getDelegateRuleId()+" from new rule.");
 679  
                 oldRules.remove(ruleDelegation.getDelegateRuleId());
 680  
             }
 681  
         }
 682  
         return oldRules;
 683  
     }
 684  
      */
 685  
     /**
 686  
      * This method will find any old delegation rules on the previous version of the parent rule which are not on the
 687  
      * new version of the rule so that they can be marked non-current.
 688  
      */
 689  
     private List findOldDelegationRules(RuleBaseValues oldRule, RuleBaseValues newRule, PerformanceLogger performanceLogger) {
 690  0
         performanceLogger.log("Begin to get delegation rules.");
 691  0
         List oldDelegations = getRuleDAO().findOldDelegations(oldRule, newRule);
 692  0
         performanceLogger.log("Located "+oldDelegations.size()+" old delegation rules.");
 693  0
         return oldDelegations;
 694  
     }
 695  
 
 696  
     public Long route2(Long routeHeaderId, MyRules2 myRules, KimPrincipal principal, String annotation, boolean blanketApprove) throws Exception {
 697  0
         List errors = new ArrayList();
 698  0
         if (myRules.getRules().isEmpty()) {
 699  0
             errors.add(new WorkflowServiceErrorImpl("Rule required", "rule.required"));
 700  
         }
 701  0
         if (!errors.isEmpty()) {
 702  0
             throw new WorkflowServiceErrorException("RuleBaseValues validation errors", errors);
 703  
         }
 704  0
         WorkflowDocument workflowDocument = null;
 705  0
         if (routeHeaderId == null) {
 706  0
             workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), getRuleDocmentTypeName(myRules.getRules()));
 707  
         } else {
 708  0
             workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), routeHeaderId);
 709  
         }
 710  
 
 711  0
         for (Iterator iter = myRules.getRules().iterator(); iter.hasNext();) {
 712  0
             RuleBaseValues rule = (RuleBaseValues) iter.next();
 713  0
             rule.setRouteHeaderId(workflowDocument.getRouteHeaderId());
 714  
 
 715  0
             workflowDocument.addAttributeDefinition(new RuleRoutingDefinition(rule.getDocTypeName()));
 716  0
             getRuleDAO().retrieveAllReferences(rule);
 717  0
             save2(rule);
 718  0
         }
 719  
 
 720  0
         workflowDocument.setTitle(generateTitle(myRules));
 721  0
         if (blanketApprove) {
 722  0
             workflowDocument.blanketApprove(annotation);
 723  
         } else {
 724  0
             workflowDocument.routeDocument(annotation);
 725  
         }
 726  0
         return workflowDocument.getRouteHeaderId();
 727  
     }
 728  
 
 729  
     public Long routeRuleWithDelegate(Long routeHeaderId, RuleBaseValues parentRule, RuleBaseValues delegateRule, KimPrincipal principal, String annotation, boolean blanketApprove) throws Exception {
 730  0
         if (parentRule == null) {
 731  0
             throw new IllegalArgumentException("Cannot route a delegate without a parent rule.");
 732  
         }
 733  0
         if (parentRule.getDelegateRule().booleanValue()) {
 734  0
             throw new IllegalArgumentException("Parent rule cannot be a delegate.");
 735  
         }
 736  0
         if (parentRule.getPreviousVersionId() == null && delegateRule.getPreviousVersionId() == null) {
 737  0
             throw new IllegalArgumentException("Previous rule version required.");
 738  
         }
 739  
 
 740  
         // if the parent rule is new, unsaved, then save it
 741  
 //      boolean isRoutingParent = parentRule.getRuleBaseValuesId() == null;
 742  
 //      if (isRoutingParent) {
 743  
 //      // it's very important that we do not save delegations here (that's what the false parameter is for)
 744  
 //      // this is because, if we save the delegations, the existing delegations on our parent rule will become
 745  
 //      // saved as "non current" before the rule is approved!!!
 746  
 //      save2(parentRule, null, false);
 747  
 //      //save2(parentRule, null, true);
 748  
 //      }
 749  
 
 750  
         // XXX: added when the RuleValidation stuff was added, basically we just need to get the RuleDelegation
 751  
         // that points to our delegate rule, this rule code is scary...
 752  0
         RuleDelegation ruleDelegation = getRuleDelegation(parentRule, delegateRule);
 753  
 
 754  0
         save2(delegateRule, ruleDelegation, true);
 755  
 
 756  
 //      if the parent rule is new, unsaved, then save it
 757  
         // It's important to save the parent rule after the delegate rule is saved, that way we can ensure that any new rule
 758  
         // delegations have a valid, saved, delegation rule to point to (otherwise we end up with a null constraint violation)
 759  0
         boolean isRoutingParent = parentRule.getRuleBaseValuesId() == null;
 760  0
         if (isRoutingParent) {
 761  
             // it's very important that we do not save delegations here (that's what the false parameter is for)
 762  
             // this is because, if we save the delegations, the existing delegations on our parent rule will become
 763  
             // saved as "non current" before the rule is approved!!!
 764  0
             save2(parentRule, null, false);
 765  
             //save2(parentRule, null, true);
 766  
         }
 767  
 
 768  0
         WorkflowDocument workflowDocument = null;
 769  0
         if (routeHeaderId != null) {
 770  0
             workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), routeHeaderId);
 771  
         } else {
 772  0
             List rules = new ArrayList();
 773  0
             rules.add(delegateRule);
 774  0
             rules.add(parentRule);
 775  0
             workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), getRuleDocmentTypeName(rules));
 776  
         }
 777  0
         workflowDocument.setTitle(generateTitle(parentRule, delegateRule));
 778  0
         delegateRule.setRouteHeaderId(workflowDocument.getRouteHeaderId());
 779  0
         workflowDocument.addAttributeDefinition(new RuleRoutingDefinition(parentRule.getDocTypeName()));
 780  0
         getRuleDAO().save(delegateRule);
 781  0
         if (isRoutingParent) {
 782  0
             parentRule.setRouteHeaderId(workflowDocument.getRouteHeaderId());
 783  0
             getRuleDAO().save(parentRule);
 784  
         }
 785  0
         if (blanketApprove) {
 786  0
             workflowDocument.blanketApprove(annotation);
 787  
         } else {
 788  0
             workflowDocument.routeDocument(annotation);
 789  
         }
 790  0
         return workflowDocument.getRouteHeaderId();
 791  
     }
 792  
 
 793  
     /**
 794  
      * Gets the RuleDelegation object from the parentRule that points to the delegateRule.
 795  
      */
 796  
     private RuleDelegation getRuleDelegation(RuleBaseValues parentRule, RuleBaseValues delegateRule) throws Exception {
 797  0
         for (Iterator iterator = parentRule.getResponsibilities().iterator(); iterator.hasNext(); ) {
 798  0
             RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
 799  0
             for (Iterator respIt = responsibility.getDelegationRules().iterator(); respIt.hasNext(); ) {
 800  0
                 RuleDelegation ruleDelegation = (RuleDelegation) respIt.next();
 801  
                 // they should be the same object in memory
 802  0
                 if (ruleDelegation.getDelegationRuleBaseValues().equals(delegateRule)) {
 803  0
                     return ruleDelegation;
 804  
                 }
 805  0
             }
 806  0
         }
 807  0
         return null;
 808  
     }
 809  
 
 810  
     private String generateTitle(RuleBaseValues parentRule, RuleBaseValues delegateRule) {
 811  0
         StringBuffer title = new StringBuffer();
 812  0
         if (delegateRule.getPreviousVersionId() != null) {
 813  0
             title.append("Editing Delegation Rule '").append(delegateRule.getDescription()).append("' on '");
 814  
         } else {
 815  0
             title.append("Adding Delegation Rule '").append(delegateRule.getDescription()).append("' to '");
 816  
         }
 817  0
         title.append(parentRule.getDescription()).append("'");
 818  0
         return title.toString();
 819  
     }
 820  
 
 821  
     private String generateTitle(MyRules2 myRules) {
 822  0
         StringBuffer title = new StringBuffer();
 823  0
         RuleBaseValues firstRule = myRules.getRule(0);
 824  0
         if (myRules.getRules().size() > 1) {
 825  0
             title.append("Routing ").append(myRules.getSize()).append(" Rules, '");
 826  0
             title.append(firstRule.getDescription()).append("',...");
 827  0
         } else if (firstRule.getPreviousVersionId() != null) {
 828  0
             title.append("Editing Rule '").append(firstRule.getDescription()).append("'");
 829  
         } else {
 830  0
             title.append("Adding Rule '").append(firstRule.getDescription()).append("'");
 831  
         }
 832  0
         return title.toString();
 833  
     }
 834  
 
 835  
     public void validate(RuleBaseValues ruleBaseValues, List errors) {
 836  0
         if (errors == null) {
 837  0
             errors = new ArrayList();
 838  
         }
 839  0
         if (getDocumentTypeService().findByName(ruleBaseValues.getDocTypeName()) == null) {
 840  0
             errors.add(new WorkflowServiceErrorImpl("Document Type Invalid", "doctype.documenttypeservice.doctypename.required"));
 841  
         }
 842  0
         if (ruleBaseValues.getToDate().before(ruleBaseValues.getFromDate())) {
 843  0
             errors.add(new WorkflowServiceErrorImpl("From Date is later than to date", "routetemplate.ruleservice.daterange.fromafterto"));
 844  
         }
 845  0
         if (ruleBaseValues.getActiveInd() == null) {
 846  0
             errors.add(new WorkflowServiceErrorImpl("Active Indicator is required", "routetemplate.ruleservice.activeind.required"));
 847  
         }
 848  0
         if (ruleBaseValues.getDescription() == null || ruleBaseValues.getDescription().equals("")) {
 849  0
             errors.add(new WorkflowServiceErrorImpl("Description is required", "routetemplate.ruleservice.description.required"));
 850  
         }
 851  0
         if (ruleBaseValues.getForceAction() == null) {
 852  0
             errors.add(new WorkflowServiceErrorImpl("Force Action is required", "routetemplate.ruleservice.forceAction.required"));
 853  
         }
 854  0
         if (ruleBaseValues.getResponsibilities().isEmpty()) {
 855  0
             errors.add(new WorkflowServiceErrorImpl("A responsibility is required", "routetemplate.ruleservice.responsibility.required"));
 856  
         } else {
 857  0
             for (Iterator iter = ruleBaseValues.getResponsibilities().iterator(); iter.hasNext();) {
 858  0
                 RuleResponsibility responsibility = (RuleResponsibility) iter.next();
 859  0
                 if (responsibility.getRuleResponsibilityName() != null && KEWConstants.RULE_RESPONSIBILITY_GROUP_ID.equals(responsibility.getRuleResponsibilityType())) {
 860  0
                     if (getIdentityManagementService().getGroup(responsibility.getRuleResponsibilityName()) == null) {
 861  0
                         errors.add(new WorkflowServiceErrorImpl("Workgroup is invalid", "routetemplate.ruleservice.workgroup.invalid"));
 862  
                     }
 863  0
                 } else if (responsibility.getPrincipal() == null && responsibility.getRole() == null) {
 864  0
                     errors.add(new WorkflowServiceErrorImpl("User is invalid", "routetemplate.ruleservice.user.invalid"));
 865  
                 }
 866  0
             }
 867  
         }
 868  0
         if (!errors.isEmpty()) {
 869  0
             throw new WorkflowServiceErrorException("RuleBaseValues validation errors", errors);
 870  
         }
 871  0
     }
 872  
 
 873  
     public void validate2(RuleBaseValues ruleBaseValues, RuleDelegation ruleDelegation, List errors) {
 874  0
         if (errors == null) {
 875  0
             errors = new ArrayList();
 876  
         }
 877  0
         if (getDocumentTypeService().findByName(ruleBaseValues.getDocTypeName()) == null) {
 878  0
             errors.add(new WorkflowServiceErrorImpl("Document Type Invalid", "doctype.documenttypeservice.doctypename.required"));
 879  0
             LOG.error("Document Type Invalid");
 880  
         }
 881  0
         if (ruleBaseValues.getToDate() == null) {
 882  
             try {
 883  0
                 ruleBaseValues.setToDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
 884  0
             } catch (ParseException e) {
 885  0
                 LOG.error("Error date-parsing default date");
 886  0
                 throw new WorkflowServiceErrorException("Error parsing default date.", e);
 887  0
             }
 888  
         }
 889  0
         if (ruleBaseValues.getFromDate() == null) {
 890  0
             ruleBaseValues.setFromDate(new Timestamp(System.currentTimeMillis()));
 891  
         }
 892  0
         if (ruleBaseValues.getToDate().before(ruleBaseValues.getFromDate())) {
 893  0
             errors.add(new WorkflowServiceErrorImpl("From Date is later than to date", "routetemplate.ruleservice.daterange.fromafterto"));
 894  0
             LOG.error("From Date is later than to date");
 895  
         }
 896  0
         if (ruleBaseValues.getActiveInd() == null) {
 897  0
             errors.add(new WorkflowServiceErrorImpl("Active Indicator is required", "routetemplate.ruleservice.activeind.required"));
 898  0
             LOG.error("Active Indicator is missing");
 899  
         }
 900  0
         if (ruleBaseValues.getDescription() == null || ruleBaseValues.getDescription().equals("")) {
 901  0
             errors.add(new WorkflowServiceErrorImpl("Description is required", "routetemplate.ruleservice.description.required"));
 902  0
             LOG.error("Description is missing");
 903  
         }
 904  0
         if (ruleBaseValues.getForceAction() == null) {
 905  0
             errors.add(new WorkflowServiceErrorImpl("Force Action is required", "routetemplate.ruleservice.forceAction.required"));
 906  0
             LOG.error("Force Action is missing");
 907  
         }
 908  
 
 909  0
         for (Iterator iter = ruleBaseValues.getResponsibilities().iterator(); iter.hasNext();) {
 910  0
             RuleResponsibility responsibility = (RuleResponsibility) iter.next();
 911  0
             if (responsibility.getRuleResponsibilityName() != null && KEWConstants.RULE_RESPONSIBILITY_GROUP_ID.equals(responsibility.getRuleResponsibilityType())) {
 912  0
                 if (getIdentityManagementService().getGroup(responsibility.getRuleResponsibilityName()) == null) {
 913  0
                     errors.add(new WorkflowServiceErrorImpl("Workgroup is invalid", "routetemplate.ruleservice.workgroup.invalid"));
 914  0
                     LOG.error("Workgroup is invalid");
 915  
                 }
 916  0
             } else if (responsibility.getPrincipal() == null && responsibility.getRole() == null) {
 917  0
                 errors.add(new WorkflowServiceErrorImpl("User is invalid", "routetemplate.ruleservice.user.invalid"));
 918  0
                 LOG.error("User is invalid");
 919  0
             } else if (responsibility.isUsingRole()) {
 920  0
                 if (responsibility.getApprovePolicy() == null || !(responsibility.getApprovePolicy().equals(KEWConstants.APPROVE_POLICY_ALL_APPROVE) || responsibility.getApprovePolicy().equals(KEWConstants.APPROVE_POLICY_FIRST_APPROVE))) {
 921  0
                     errors.add(new WorkflowServiceErrorImpl("Approve Policy is Invalid", "routetemplate.ruleservice.approve.policy.invalid"));
 922  0
                     LOG.error("Approve Policy is Invalid");
 923  
                 }
 924  
             }
 925  0
         }
 926  
 
 927  0
         if (ruleBaseValues.getRuleTemplate() != null) {
 928  0
             for (Iterator iter = ruleBaseValues.getRuleTemplate().getActiveRuleTemplateAttributes().iterator(); iter.hasNext();) {
 929  0
                 RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) iter.next();
 930  0
                 if (!templateAttribute.isRuleValidationAttribute()) {
 931  0
                     continue;
 932  
                 }
 933  0
                 RuleValidationAttribute attribute = templateAttribute.getRuleValidationAttribute();
 934  0
                 UserSession userSession = UserSession.getAuthenticatedUser();
 935  
                 try {
 936  0
                     RuleValidationContext validationContext = new RuleValidationContext(ruleBaseValues, ruleDelegation, userSession);
 937  0
                     ValidationResults results = attribute.validate(validationContext);
 938  0
                     if (results != null && !results.getValidationResults().isEmpty()) {
 939  0
                         errors.add(results);
 940  
                     }
 941  0
                 } catch (Exception e) {
 942  0
                     if (e instanceof RuntimeException) {
 943  0
                         throw (RuntimeException)e;
 944  
                     }
 945  0
                     throw new RuntimeException("Problem validation rule.", e);
 946  0
                 }
 947  
 
 948  0
             }
 949  
         }
 950  0
         if (ruleBaseValues.getRuleExpressionDef() != null) {
 951  
             // rule expressions do not require parse-/save-time validation
 952  
         }
 953  
 
 954  0
         if (!errors.isEmpty()) {
 955  0
             throw new WorkflowServiceErrorException("RuleBaseValues validation errors", errors);
 956  
         }
 957  0
     }
 958  
 
 959  
     public List findByRouteHeaderId(Long routeHeaderId) {
 960  0
         return getRuleDAO().findByRouteHeaderId(routeHeaderId);
 961  
     }
 962  
 
 963  
     public List search(String docTypeName, Long ruleId, Long ruleTemplateId, String ruleDescription, String groupId, String principalId,
 964  
             Boolean delegateRule, Boolean activeInd, Map extensionValues, String workflowIdDirective) {
 965  0
         return getRuleDAO().search(docTypeName, ruleId, ruleTemplateId, ruleDescription, groupId, principalId, delegateRule,
 966  
                 activeInd, extensionValues, workflowIdDirective);
 967  
     }
 968  
 
 969  
     public List search(String docTypeName, String ruleTemplateName, String ruleDescription, String groupId, String principalId,
 970  
             Boolean workgroupMember, Boolean delegateRule, Boolean activeInd, Map extensionValues, Collection<String> actionRequestCodes) {
 971  
 
 972  0
         if ( (StringUtils.isEmpty(docTypeName)) &&
 973  
                 (StringUtils.isEmpty(ruleTemplateName)) &&
 974  
                 (StringUtils.isEmpty(ruleDescription)) &&
 975  
                 (StringUtils.isEmpty(groupId)) &&
 976  
                 (StringUtils.isEmpty(principalId)) &&
 977  
                 (extensionValues.isEmpty()) &&
 978  
                 (actionRequestCodes.isEmpty()) ) {
 979  
             // all fields are empty
 980  0
             throw new IllegalArgumentException("At least one criterion must be sent");
 981  
         }
 982  
 
 983  0
         RuleTemplate ruleTemplate = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
 984  0
         Long ruleTemplateId = null;
 985  0
         if (ruleTemplate != null) {
 986  0
             ruleTemplateId = ruleTemplate.getRuleTemplateId();
 987  
         }
 988  
 
 989  0
         if ( ( (extensionValues != null) && (!extensionValues.isEmpty()) ) &&
 990  
                 (ruleTemplateId == null) ) {
 991  
             // cannot have extensions without a correct template
 992  0
             throw new IllegalArgumentException("A Rule Template Name must be given if using Rule Extension values");
 993  
         }
 994  
 
 995  0
         Collection<String> workgroupIds = new ArrayList<String>();
 996  0
         if (principalId != null) {
 997  0
             KEWServiceLocator.getIdentityHelperService().validatePrincipalId(principalId);
 998  0
             if ( (workgroupMember == null) || (workgroupMember.booleanValue()) ) {
 999  0
                         workgroupIds = getIdentityManagementService().getGroupIdsForPrincipal(principalId);
 1000  
                 } else {
 1001  
                         // user was passed but workgroups should not be parsed... do nothing
 1002  
                 }
 1003  0
         } else if (groupId != null) {
 1004  0
                 Group group = KEWServiceLocator.getIdentityHelperService().getGroup(groupId);
 1005  0
                 if (group == null) {
 1006  0
                         throw new IllegalArgumentException("Group does not exist in for given group id: " + groupId);
 1007  
                 } else  {
 1008  0
                         workgroupIds.add(group.getGroupId());
 1009  
                 }
 1010  
         }
 1011  
 
 1012  0
         return getRuleDAO().search(docTypeName, ruleTemplateId, ruleDescription, workgroupIds, principalId,
 1013  
                 delegateRule,activeInd, extensionValues, actionRequestCodes);
 1014  
     }
 1015  
 
 1016  
     public void delete(Long ruleBaseValuesId) {
 1017  0
         getRuleDAO().delete(ruleBaseValuesId);
 1018  0
     }
 1019  
 
 1020  
     public RuleBaseValues findRuleBaseValuesById(Long ruleBaseValuesId) {
 1021  0
         return getRuleDAO().findRuleBaseValuesById(ruleBaseValuesId);
 1022  
     }
 1023  
 
 1024  
     public RuleResponsibility findRuleResponsibility(Long responsibilityId) {
 1025  0
         return getRuleDAO().findRuleResponsibility(responsibilityId);
 1026  
     }
 1027  
 
 1028  
     public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType, boolean ignoreCache) {
 1029  0
         PerformanceLogger performanceLogger = new PerformanceLogger();
 1030  0
         Boolean cachingRules = Boolean.valueOf(Utilities.getKNSParameterBooleanValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, USING_RULE_CACHE_IND));
 1031  0
         if (cachingRules.booleanValue()) {
 1032  
             //Cache cache = SpringServiceLocator.getCache();
 1033  0
             List<RuleBaseValues> rules = getListFromCache(ruleTemplateName, documentType);
 1034  0
             if (rules != null && !ignoreCache) {
 1035  0
                 performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " cached.");
 1036  0
                 return rules;
 1037  
             }
 1038  0
             RuleTemplate ruleTemplate = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
 1039  0
             if (ruleTemplate == null) {
 1040  0
                 return Collections.EMPTY_LIST;
 1041  
             }
 1042  0
             Long ruleTemplateId = ruleTemplate.getRuleTemplateId();
 1043  
             //RuleListCache translatedRules = new RuleListCache();
 1044  
             //translatedRules.setId(getRuleCacheKey(ruleTemplateName, documentType));
 1045  0
             rules = getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType));
 1046  
             //translatedRules.addAll(rules);
 1047  0
             putListInCache(ruleTemplateName, documentType, rules);
 1048  
             //cache.add(RULE_CACHE_NAME, translatedRules);
 1049  0
             performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " cache refreshed.");
 1050  0
             return rules;
 1051  
         } else {
 1052  0
             Long ruleTemplateId = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName).getRuleTemplateId();
 1053  0
             performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " not caching.");
 1054  0
             return getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType));
 1055  
         }
 1056  
     }
 1057  
 
 1058  
     public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType) {
 1059  0
         return fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateName, documentType, false);
 1060  
     }
 1061  
 
 1062  
     public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType, Timestamp effectiveDate){
 1063  0
         Long ruleTemplateId = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName).getRuleTemplateId();
 1064  0
         PerformanceLogger performanceLogger = new PerformanceLogger();
 1065  0
         performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " not caching.");
 1066  0
         return getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType), effectiveDate);
 1067  
     }
 1068  
     public List fetchAllRules(boolean currentRules) {
 1069  0
         return getRuleDAO().fetchAllRules(currentRules);
 1070  
     }
 1071  
 
 1072  
     private List getDocGroupAndTypeList(String documentType) {
 1073  0
         List docTypeList = new ArrayList();
 1074  0
         DocumentTypeService docTypeService = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
 1075  0
         DocumentType docType = docTypeService.findByName(documentType);
 1076  0
         while (docType != null) {
 1077  0
             docTypeList.add(docType.getName());
 1078  0
             docType = docType.getParentDocType();
 1079  
         }
 1080  0
         return docTypeList;
 1081  
     }
 1082  
 
 1083  
     private Integer getNextVersionNumber(RuleBaseValues currentRule) {
 1084  0
         List candidates = new ArrayList();
 1085  0
         candidates.add(currentRule.getVersionNbr());
 1086  0
         List pendingRules = ruleDAO.findByPreviousVersionId(currentRule.getRuleBaseValuesId());
 1087  0
         for (Iterator iterator = pendingRules.iterator(); iterator.hasNext();) {
 1088  0
             RuleBaseValues pendingRule = (RuleBaseValues) iterator.next();
 1089  0
             candidates.add(pendingRule.getVersionNbr());
 1090  0
         }
 1091  0
         Collections.sort(candidates);
 1092  0
         Integer maxVersionNumber = (Integer) candidates.get(candidates.size() - 1);
 1093  0
         if (maxVersionNumber == null) {
 1094  0
             return Integer.valueOf(0);
 1095  
         }
 1096  0
         return Integer.valueOf(maxVersionNumber.intValue() + 1);
 1097  
     }
 1098  
 
 1099  
     /**
 1100  
      * Determines if the given rule is locked for routing.
 1101  
      *
 1102  
      * In the case of a root rule edit, this method will take the rule id of the rule being edited.
 1103  
      *
 1104  
      * In the case of a new delegate rule or a delegate rule edit, this method will take the id of it's parent.
 1105  
      */
 1106  
     public Long isLockedForRouting(Long currentRuleBaseValuesId) {
 1107  
         // checks for any other versions of the given rule, essentially, if this is a rule edit we want to see how many other
 1108  
         // pending edits are out there
 1109  0
         List pendingRules = ruleDAO.findByPreviousVersionId(currentRuleBaseValuesId);
 1110  0
         boolean isDead = true;
 1111  0
         for (Iterator iterator = pendingRules.iterator(); iterator.hasNext();) {
 1112  0
             RuleBaseValues pendingRule = (RuleBaseValues) iterator.next();
 1113  
 
 1114  0
             if (pendingRule.getRouteHeaderId() != null && pendingRule.getRouteHeaderId().longValue() != 0) {
 1115  0
                 DocumentRouteHeaderValue routeHeader = getRouteHeaderService().getRouteHeader(pendingRule.getRouteHeaderId());
 1116  
                 // the pending edit is considered dead if it's been disapproved or cancelled and we are allowed to proceed with our own edit
 1117  0
                 isDead = routeHeader.isDisaproved() || routeHeader.isCanceled();
 1118  0
                 if (!isDead) {
 1119  0
                     return pendingRule.getRouteHeaderId();
 1120  
                 }
 1121  
             }
 1122  0
             for (Iterator iter = pendingRule.getResponsibilities().iterator(); iter.hasNext();) {
 1123  0
                 RuleResponsibility responsibility = (RuleResponsibility) iter.next();
 1124  0
                 for (Iterator iterator2 = responsibility.getDelegationRules().iterator(); iterator2.hasNext();) {
 1125  0
                     RuleDelegation delegation = (RuleDelegation) iterator2.next();
 1126  0
                     List pendingDelegateRules = ruleDAO.findByPreviousVersionId(delegation.getDelegationRuleBaseValues().getRuleBaseValuesId());
 1127  0
                     for (Iterator iterator3 = pendingDelegateRules.iterator(); iterator3.hasNext();) {
 1128  0
                         RuleBaseValues pendingDelegateRule = (RuleBaseValues) iterator3.next();
 1129  0
                         if (pendingDelegateRule.getRouteHeaderId() != null && pendingDelegateRule.getRouteHeaderId().longValue() != 0) {
 1130  0
                             DocumentRouteHeaderValue routeHeader = getRouteHeaderService().getRouteHeader(pendingDelegateRule.getRouteHeaderId());
 1131  0
                             isDead = routeHeader.isDisaproved() || routeHeader.isCanceled();
 1132  0
                             if (!isDead) {
 1133  0
                                 return pendingDelegateRule.getRouteHeaderId();
 1134  
                             }
 1135  
                         }
 1136  0
                     }
 1137  0
                 }
 1138  0
             }
 1139  0
         }
 1140  0
         return null;
 1141  
     }
 1142  
 
 1143  
     public RuleBaseValues getParentRule(RuleBaseValues rule) {
 1144  0
         if (rule == null || rule.getRuleBaseValuesId() == null) {
 1145  0
             throw new IllegalArgumentException("Rule must be non-null with non-null id: " + rule);
 1146  
         }
 1147  0
         if (!Boolean.TRUE.equals(rule.getDelegateRule())) {
 1148  0
             return null;
 1149  
         }
 1150  0
         return getRuleDAO().getParentRule(rule.getRuleBaseValuesId());
 1151  
     }
 1152  
 
 1153  
     /**
 1154  
      * This configuration is currently stored in a system parameter named "CUSTOM_DOCUMENT_TYPES ",
 1155  
      * long term we should come up with a better solution.  The format of this constant is a comma-separated
 1156  
      * list of entries of the following form:
 1157  
      *
 1158  
      * <<name of doc type on rule>>:<<rule template name on rule>>:<<type of rule>>:<<name of document type to use for rule routing>>
 1159  
      *
 1160  
      * Rule type indicates either main or delegation rules.  A main rule is indicated by the character 'M' and a
 1161  
      * delegate rule is indicated by the character 'D'.
 1162  
      *
 1163  
      * So, if you wanted to route "main" rules made for the "MyDocType" document with the rule template name
 1164  
      * "MyRuleTemplate" using the "MyMainRuleDocType" doc type, it would be specified as follows:
 1165  
      *
 1166  
      * MyDocType:MyRuleTemplate:M:MyMainRuleDocType
 1167  
      *
 1168  
      * If you also wanted to route "delegate" rules made for the "MyDocType" document with rule template name
 1169  
      * "MyDelegateTemplate" using the "MyDelegateRuleDocType", you would then set the constant as follows:
 1170  
      *
 1171  
      * MyDocType:MyRuleTemplate:M:MyMainRuleDocType,MyDocType:MyDelegateTemplate:D:MyDelegateRuleDocType
 1172  
      *
 1173  
      * TODO this method ended up being a mess, we should get rid of this as soon as we can
 1174  
      */
 1175  
     public String getRuleDocmentTypeName(List rules) {
 1176  0
         if (rules.size() == 0) {
 1177  0
             throw new IllegalArgumentException("Cannot determine rule DocumentType for an empty list of rules.");
 1178  
         }
 1179  0
         String ruleDocTypeName = null;
 1180  0
         RuleRoutingConfig config = RuleRoutingConfig.parse();
 1181  
         // There are 2 cases here
 1182  0
         RuleBaseValues firstRule = (RuleBaseValues)rules.get(0);
 1183  0
         if (Boolean.TRUE.equals(firstRule.getDelegateRule())) {
 1184  
             // if it's a delegate rule then the list will contain only 2 elements, the first is the delegate rule,
 1185  
             // the second is the parent rule.  In this case just look at the custom routing process for the delegate rule.
 1186  0
             ruleDocTypeName = config.getDocumentTypeName(firstRule);
 1187  
         } else {
 1188  
             // if this is a list of parent rules being routed, look at all configued routing types and verify that they are
 1189  
             // all the same, if not throw an exception
 1190  0
             String parentRulesDocTypeName = null;
 1191  0
             for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
 1192  0
                 RuleBaseValues rule = (RuleBaseValues) iterator.next();
 1193  
                 // if it's a delegate rule just skip it
 1194  0
                 if  (Boolean.TRUE.equals(rule.getDelegateRule())) {
 1195  0
                     continue;
 1196  
                 }
 1197  0
                 String currentDocTypeName = config.getDocumentTypeName(rule);
 1198  0
                 if (parentRulesDocTypeName == null) {
 1199  0
                     parentRulesDocTypeName = currentDocTypeName;
 1200  
                 } else {
 1201  0
                     if (!Utilities.equals(currentDocTypeName, parentRulesDocTypeName)) {
 1202  0
                         throw new RuntimeException("There are multiple rules being routed and they have different document type definitions!  " + parentRulesDocTypeName + " and " + currentDocTypeName);
 1203  
                     }
 1204  
                 }
 1205  0
             }
 1206  0
             ruleDocTypeName = parentRulesDocTypeName;
 1207  
         }
 1208  0
         if (ruleDocTypeName == null) {
 1209  0
             ruleDocTypeName = KEWConstants.DEFAULT_RULE_DOCUMENT_NAME;
 1210  
         }
 1211  0
         return ruleDocTypeName;
 1212  
     }
 1213  
 
 1214  
     public void setRuleDAO(RuleDAO ruleDAO) {
 1215  0
         this.ruleDAO = ruleDAO;
 1216  0
     }
 1217  
 
 1218  
     public RuleDAO getRuleDAO() {
 1219  0
         return ruleDAO;
 1220  
     }
 1221  
 
 1222  
     public void deleteRuleResponsibilityById(Long ruleResponsibilityId) {
 1223  0
         getRuleResponsibilityDAO().delete(ruleResponsibilityId);
 1224  0
     }
 1225  
 
 1226  
     public RuleResponsibility findByRuleResponsibilityId(Long ruleResponsibilityId) {
 1227  0
         return getRuleResponsibilityDAO().findByRuleResponsibilityId(ruleResponsibilityId);
 1228  
     }
 1229  
 
 1230  
     public List findRuleBaseValuesByResponsibilityReviewer(String reviewerName, String type) {
 1231  0
         return getRuleDAO().findRuleBaseValuesByResponsibilityReviewer(reviewerName, type);
 1232  
     }
 1233  
 
 1234  
     public List findRuleBaseValuesByResponsibilityReviewerTemplateDoc(String ruleTemplateName, String documentType, String reviewerName, String type) {
 1235  0
         return getRuleDAO().findRuleBaseValuesByResponsibilityReviewerTemplateDoc(ruleTemplateName, documentType, reviewerName, type);
 1236  
     }
 1237  
 
 1238  
     public RuleTemplateService getRuleTemplateService() {
 1239  0
         return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
 1240  
     }
 1241  
 
 1242  
     public DocumentTypeService getDocumentTypeService() {
 1243  0
         return (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
 1244  
     }
 1245  
 
 1246  
     public IdentityManagementService getIdentityManagementService() {
 1247  0
         return (IdentityManagementService) KIMServiceLocator.getService(KIMServiceLocator.KIM_IDENTITY_MANAGEMENT_SERVICE);
 1248  
     }
 1249  
 
 1250  
     public ActionRequestService getActionRequestService() {
 1251  0
         return (ActionRequestService) KEWServiceLocator.getService(KEWServiceLocator.ACTION_REQUEST_SRV);
 1252  
     }
 1253  
 
 1254  
     private ResponsibilityIdService getResponsibilityIdService() {
 1255  0
         return (ResponsibilityIdService) KEWServiceLocator.getService(KEWServiceLocator.RESPONSIBILITY_ID_SERVICE);
 1256  
     }
 1257  
 
 1258  
     private RuleDelegationService getRuleDelegationService() {
 1259  0
         return (RuleDelegationService) KEWServiceLocator.getService(KEWServiceLocator.RULE_DELEGATION_SERVICE);
 1260  
     }
 1261  
 
 1262  
     private RouteHeaderService getRouteHeaderService() {
 1263  0
         return (RouteHeaderService) KEWServiceLocator.getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV);
 1264  
     }
 1265  
 
 1266  
     /**
 1267  
      * A comparator implementation which compares RuleBaseValues and puts all delegate rules first.
 1268  
      */
 1269  0
     public class RuleDelegationSorter implements Comparator {
 1270  
         public int compare(Object arg0, Object arg1) {
 1271  0
             RuleBaseValues rule1 = (RuleBaseValues) arg0;
 1272  0
             RuleBaseValues rule2 = (RuleBaseValues) arg1;
 1273  
 
 1274  0
             Integer rule1Value = new Integer((rule1.getDelegateRule().booleanValue() ? 0 : 1));
 1275  0
             Integer rule2Value = new Integer((rule2.getDelegateRule().booleanValue() ? 0 : 1));
 1276  0
             int value = rule1Value.compareTo(rule2Value);
 1277  0
             return value;
 1278  
         }
 1279  
     }
 1280  
 
 1281  
 
 1282  
     public void loadXml(InputStream inputStream, String principalId) {
 1283  0
         RuleXmlParser parser = new RuleXmlParser();
 1284  
         try {
 1285  0
             parser.parseRules(inputStream);
 1286  0
         } catch (Exception e) { //any other exception
 1287  0
             LOG.error("Error loading xml file", e);
 1288  0
             WorkflowServiceErrorException wsee = new WorkflowServiceErrorException("Error loading xml file", new WorkflowServiceErrorImpl("Error loading xml file", XML_PARSE_ERROR));
 1289  0
             wsee.initCause(e);
 1290  0
             throw wsee;
 1291  0
         }
 1292  0
     }
 1293  
 
 1294  
     public Element export(ExportDataSet dataSet) {
 1295  0
         RuleXmlExporter exporter = new RuleXmlExporter(XmlConstants.RULE_NAMESPACE);
 1296  0
         return exporter.export(dataSet);
 1297  
     }
 1298  
 
 1299  
     public void removeRuleInvolvement(Id entityToBeRemoved, List<Long> ruleIds, Long documentId) throws WorkflowException {
 1300  0
         KimPrincipal principal = null;
 1301  0
         Group workgroupToRemove = null;
 1302  0
         if (entityToBeRemoved instanceof UserId) {
 1303  0
             principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(((UserId) entityToBeRemoved));
 1304  0
         } else if (entityToBeRemoved instanceof GroupId) {
 1305  0
                 workgroupToRemove = KEWServiceLocator.getIdentityHelperService().getGroup((GroupId)entityToBeRemoved);
 1306  
         } else {
 1307  0
             throw new WorkflowRuntimeException("Invalid ID for entity to be replaced was passed, type was: " + entityToBeRemoved);
 1308  
         }
 1309  0
         List<RuleBaseValues> existingRules = loadRules(ruleIds);
 1310  
         // sort the rules so that delegations are last, very important in order to deal with parent-child versioning properly
 1311  0
         Collections.sort(existingRules, ComparatorUtils.reversedComparator(new RuleDelegationSorter()));
 1312  
         // we maintain the old-new mapping so we can associate versioned delegate rules with their appropriate re-versioned parents when applicable
 1313  0
         Map<Long, RuleBaseValues> oldIdNewRuleMapping = new HashMap<Long, RuleBaseValues>();
 1314  0
         Map<Long, RuleBaseValues> rulesToVersion = new HashMap<Long, RuleBaseValues>();
 1315  0
         for (RuleBaseValues existingRule : existingRules) {
 1316  0
             if (!shouldChangeRuleInvolvement(documentId, existingRule)) {
 1317  0
                 continue;
 1318  
             }
 1319  0
             List<RuleResponsibility> finalResponsibilities = new ArrayList<RuleResponsibility>();
 1320  0
             RuleVersion ruleVersion = createNewRemoveReplaceVersion(existingRule, oldIdNewRuleMapping, documentId);
 1321  0
             boolean modified = false;
 1322  0
             for (RuleResponsibility responsibility : (List<RuleResponsibility>)ruleVersion.rule.getResponsibilities()) {
 1323  0
                 if (responsibility.isUsingWorkflowUser()) {
 1324  0
                     if (principal != null && responsibility.getRuleResponsibilityName().equals(principal.getPrincipalName())) {
 1325  0
                         modified = true;
 1326  0
                         continue;
 1327  
                     }
 1328  0
                 } else if (responsibility.isUsingGroup()) {
 1329  0
                     if (workgroupToRemove != null && responsibility.getRuleResponsibilityName().equals(workgroupToRemove.getGroupId())) {
 1330  0
                         modified = true;
 1331  0
                         continue;
 1332  
                     }
 1333  
                 }
 1334  0
                 finalResponsibilities.add(responsibility);
 1335  
             }
 1336  0
             if (modified) {
 1337  
                 // if this is a delegation rule, we need to hook it up to the parent rule
 1338  0
                 if (ruleVersion.parent != null && ruleVersion.delegation != null) {
 1339  0
                     hookUpDelegateRuleToParentRule(ruleVersion.parent, ruleVersion.rule, ruleVersion.delegation);
 1340  
                 }
 1341  0
                 if (finalResponsibilities.isEmpty()) {
 1342  
                     // deactivate the rule instead
 1343  0
                     ruleVersion.rule.setActiveInd(false);
 1344  
                 } else {
 1345  0
                     ruleVersion.rule.setResponsibilities(finalResponsibilities);
 1346  
                 }
 1347  
                 try {
 1348  0
                     save2(ruleVersion.rule, ruleVersion.delegation, false);
 1349  0
                     if (ruleVersion.delegation != null) {
 1350  0
                         KEWServiceLocator.getRuleDelegationService().save(ruleVersion.delegation);
 1351  
                     }
 1352  0
                     rulesToVersion.put(ruleVersion.rule.getRuleBaseValuesId(), ruleVersion.rule);
 1353  0
                     if (ruleVersion.parent != null) {
 1354  0
                         save2(ruleVersion.parent, null, false);
 1355  0
                         rulesToVersion.put(ruleVersion.parent.getRuleBaseValuesId(), ruleVersion.parent);
 1356  
                     }
 1357  0
                 } catch (Exception e) {
 1358  0
                     throw new WorkflowRuntimeException(e);
 1359  0
                 }
 1360  
             }
 1361  0
         }
 1362  0
         makeCurrent2(new ArrayList<RuleBaseValues>(rulesToVersion.values()));
 1363  0
     }
 1364  
 
 1365  
     protected List<RuleBaseValues> loadRules(List<Long> ruleIds) {
 1366  0
         List<RuleBaseValues> rules = new ArrayList<RuleBaseValues>();
 1367  0
         for (Long ruleId : ruleIds) {
 1368  0
             RuleBaseValues rule = KEWServiceLocator.getRuleService().findRuleBaseValuesById(ruleId);
 1369  0
             rules.add(rule);
 1370  0
         }
 1371  0
         return rules;
 1372  
     }
 1373  
 
 1374  
     public void replaceRuleInvolvement(Id entityToBeReplaced, Id newEntity, List<Long> ruleIds, Long documentId) throws WorkflowException {
 1375  0
         KimPrincipal principalToBeReplaced = null;
 1376  0
         Group workgroupToReplace = null;
 1377  0
         if (entityToBeReplaced instanceof UserId) {
 1378  0
                 principalToBeReplaced = KEWServiceLocator.getIdentityHelperService().getPrincipal(((UserId) entityToBeReplaced));
 1379  0
         } else if (entityToBeReplaced instanceof GroupId) {
 1380  0
             workgroupToReplace = KEWServiceLocator.getIdentityHelperService().getGroup((GroupId)entityToBeReplaced);
 1381  
         } else {
 1382  0
             throw new WorkflowRuntimeException("Invalid ID for entity to be replaced was passed, type was: " + entityToBeReplaced);
 1383  
         }
 1384  0
         KimPrincipal newPrincipal = null;
 1385  0
         Group newWorkgroup = null;
 1386  0
         if (newEntity instanceof UserId) {
 1387  0
             newPrincipal = KEWServiceLocator.getIdentityHelperService().getPrincipal((UserId) newEntity);
 1388  0
         } else if (newEntity instanceof GroupId) {
 1389  0
             newWorkgroup = KEWServiceLocator.getIdentityHelperService().getGroup((GroupId)newEntity);
 1390  
         }
 1391  0
         List<RuleBaseValues> existingRules = loadRules(ruleIds);
 1392  
         // sort the rules so that delegations are last, very important in order to deal with parent-child versioning properly
 1393  0
         Collections.sort(existingRules, ComparatorUtils.reversedComparator(new RuleDelegationSorter()));
 1394  
         // we maintain the old-new mapping so we can associate versioned delegate rules with their appropriate re-versioned parents when applicable
 1395  0
         Map<Long, RuleBaseValues> oldIdNewRuleMapping = new HashMap<Long, RuleBaseValues>();
 1396  0
         Map<Long, RuleBaseValues> rulesToVersion = new HashMap<Long, RuleBaseValues>();
 1397  0
         for (RuleBaseValues existingRule : existingRules) {
 1398  0
             if (!shouldChangeRuleInvolvement(documentId, existingRule)) {
 1399  0
                 continue;
 1400  
             }
 1401  0
             RuleVersion ruleVersion = createNewRemoveReplaceVersion(existingRule, oldIdNewRuleMapping, documentId);
 1402  0
             RuleBaseValues rule = ruleVersion.rule;
 1403  0
             boolean modified = false;
 1404  0
             for (RuleResponsibility responsibility : (List<RuleResponsibility>)rule.getResponsibilities()) {
 1405  0
                 if (responsibility.isUsingWorkflowUser()) {
 1406  0
                     if (principalToBeReplaced != null && responsibility.getRuleResponsibilityName().equals(principalToBeReplaced.getPrincipalId())) {
 1407  0
                         if (newPrincipal != null) {
 1408  0
                             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 1409  0
                             responsibility.setRuleResponsibilityName(newPrincipal.getPrincipalId());
 1410  0
                             modified = true;
 1411  0
                         } else if (newWorkgroup != null) {
 1412  0
                             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID);
 1413  0
                             responsibility.setRuleResponsibilityName(newWorkgroup.getGroupId());
 1414  0
                             modified = true;
 1415  
                         }
 1416  
                     }
 1417  0
                 } else if (responsibility.isUsingGroup()) {
 1418  0
                     if (workgroupToReplace != null && responsibility.getRuleResponsibilityName().equals(workgroupToReplace.getGroupId())) {
 1419  0
                         if (newPrincipal != null) {
 1420  0
                             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
 1421  0
                             responsibility.setRuleResponsibilityName(newPrincipal.getPrincipalId());
 1422  0
                             modified = true;
 1423  0
                         } else if (newWorkgroup != null) {
 1424  0
                             responsibility.setRuleResponsibilityType(KEWConstants.RULE_RESPONSIBILITY_GROUP_ID);
 1425  0
                             responsibility.setRuleResponsibilityName(newWorkgroup.getGroupId().toString());
 1426  0
                             modified = true;
 1427  
                         }
 1428  
                     }
 1429  
                 }
 1430  
             }
 1431  0
             if (modified) {
 1432  
                 try {
 1433  
                     // if this is a delegation rule, we need to hook it up to the parent rule
 1434  0
                     if (ruleVersion.parent != null && ruleVersion.delegation != null) {
 1435  0
                         hookUpDelegateRuleToParentRule(ruleVersion.parent, ruleVersion.rule, ruleVersion.delegation);
 1436  
                     }
 1437  0
                     save2(ruleVersion.rule, ruleVersion.delegation, false);
 1438  0
                     if (ruleVersion.delegation != null) {
 1439  0
                         KEWServiceLocator.getRuleDelegationService().save(ruleVersion.delegation);
 1440  
                     }
 1441  0
                     rulesToVersion.put(ruleVersion.rule.getRuleBaseValuesId(), ruleVersion.rule);
 1442  0
                     if (ruleVersion.parent != null) {
 1443  0
                         save2(ruleVersion.parent, null, false);
 1444  0
                         rulesToVersion.put(ruleVersion.parent.getRuleBaseValuesId(), ruleVersion.parent);
 1445  
                     }
 1446  0
                 } catch (Exception e) {
 1447  0
                     throw new WorkflowRuntimeException(e);
 1448  0
                 }
 1449  
             }
 1450  0
         }
 1451  
 
 1452  0
         makeCurrent2(new ArrayList<RuleBaseValues>(rulesToVersion.values()));
 1453  
 
 1454  0
     }
 1455  
 
 1456  
     /**
 1457  
      * If a rule has been modified and is no longer current since the original request was made, we need to
 1458  
      * be sure to NOT update the rule.
 1459  
      */
 1460  
     protected boolean shouldChangeRuleInvolvement(Long documentId, RuleBaseValues rule) {
 1461  0
         if (!rule.getCurrentInd()) {
 1462  0
             LOG.warn("Rule requested for rule involvement change by document " + documentId + " is no longer current.  Change will not be executed!  Rule id is: " + rule.getRuleBaseValuesId());
 1463  0
             return false;
 1464  
         }
 1465  0
         Long lockingDocumentId = KEWServiceLocator.getRuleService().isLockedForRouting(rule.getRuleBaseValuesId());
 1466  0
         if (lockingDocumentId != null) {
 1467  0
             LOG.warn("Rule requested for rule involvement change by document " + documentId + " is locked by document " + lockingDocumentId + " and cannot be modified.  " +
 1468  
                     "Change will not be executed!  Rule id is: " + rule.getRuleBaseValuesId());
 1469  0
             return false;
 1470  
         }
 1471  0
         return true;
 1472  
     }
 1473  
 
 1474  
     protected RuleDelegation getRuleDelegationForDelegateRule(RuleBaseValues rule) {
 1475  0
         if (Boolean.TRUE.equals(rule.getDelegateRule())) {
 1476  0
             List delegations = getRuleDelegationService().findByDelegateRuleId(rule.getRuleBaseValuesId());
 1477  0
             for (Iterator iterator = delegations.iterator(); iterator.hasNext();) {
 1478  0
                 RuleDelegation ruleDelegation = (RuleDelegation) iterator.next();
 1479  0
                 RuleBaseValues parentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
 1480  0
                 if (Boolean.TRUE.equals(parentRule.getCurrentInd())) {
 1481  0
                     return ruleDelegation;
 1482  
                 }
 1483  0
             }
 1484  
         }
 1485  0
         return null;
 1486  
     }
 1487  
 
 1488  
     /**
 1489  
      * This is essentially the code required to create a new version of a rule.  While this is being done in the Rule
 1490  
      * GUI It's not sufficiently abstracted at the web-tier so we must essentially re-implement it here :(
 1491  
      * This would be a good place to do some work to clean this up.
 1492  
      *
 1493  
      * <p>The oldNewMapping which is passed in allows us to attach the existing rule that gets reversioned to an already re-versioned
 1494  
      * parent rule in the case where that is applicable.  This case would occur whenever both a parent and one or more of it's delegate rules are changed
 1495  
      * as part of the same transaction.
 1496  
      */
 1497  
     protected RuleVersion createNewRemoveReplaceVersion(RuleBaseValues existingRule, Map<Long, RuleBaseValues> originalIdNewRuleMapping, Long documentId) {
 1498  
         try {
 1499  
             // first check if the rule has already been re-versioned
 1500  0
             RuleBaseValues rule = null;
 1501  0
             if (originalIdNewRuleMapping.containsKey(existingRule.getRuleBaseValuesId())) {
 1502  0
                 rule = originalIdNewRuleMapping.get(existingRule.getRuleBaseValuesId());
 1503  
             } else {
 1504  0
                 rule = createNewRuleVersion(existingRule, documentId);
 1505  
             }
 1506  
 
 1507  0
             RuleVersion ruleVersion = new RuleVersion();
 1508  0
             RuleBaseValues existingParentRule = null;
 1509  0
             RuleBaseValues newParentRule = null;
 1510  
             // if it's a delegate rule, we need to find the appropriate parent and attach it
 1511  0
             if (rule.getDelegateRule()) {
 1512  0
                 RuleDelegation existingBaseDelegation = getRuleDelegationForDelegateRule(existingRule);
 1513  0
                 ruleVersion.delegation = existingBaseDelegation;
 1514  0
                 existingParentRule = existingBaseDelegation.getRuleResponsibility().getRuleBaseValues();
 1515  0
                 if (originalIdNewRuleMapping.containsKey(existingParentRule.getRuleBaseValuesId())) {
 1516  0
                     newParentRule = originalIdNewRuleMapping.get(existingParentRule.getRuleBaseValuesId());
 1517  
                 } else {
 1518  
                     // re-version the parent rule
 1519  0
                     newParentRule = createNewRuleVersion(existingParentRule, documentId);
 1520  
                 }
 1521  
             }
 1522  
 
 1523  
             // put our newly created rules into the map
 1524  0
             originalIdNewRuleMapping.put(existingRule.getRuleBaseValuesId(), rule);
 1525  0
             if (existingParentRule != null && !originalIdNewRuleMapping.containsKey(existingParentRule.getRuleBaseValuesId())) {
 1526  0
                 originalIdNewRuleMapping.put(existingParentRule.getRuleBaseValuesId(), newParentRule);
 1527  
             }
 1528  
 
 1529  0
             ruleVersion.rule = rule;
 1530  0
             ruleVersion.parent = newParentRule;
 1531  0
             return ruleVersion;
 1532  0
         } catch (Exception e) {
 1533  0
             if (e instanceof RuntimeException) {
 1534  0
                 throw (RuntimeException)e;
 1535  
             }
 1536  0
             throw new WorkflowRuntimeException(e);
 1537  
         }
 1538  
     }
 1539  
 
 1540  
     protected void hookUpDelegateRuleToParentRule(RuleBaseValues newParentRule, RuleBaseValues newDelegationRule, RuleDelegation existingRuleDelegation) {
 1541  
         // hook up parent rule to new rule delegation
 1542  0
         boolean foundDelegation = false;
 1543  0
         outer:for (RuleResponsibility responsibility : (List<RuleResponsibility>)newParentRule.getResponsibilities()) {
 1544  0
             for (RuleDelegation ruleDelegation : (List<RuleDelegation>)responsibility.getDelegationRules()) {
 1545  0
                 if (ruleDelegation.getDelegationRuleBaseValues().getRuleBaseValuesId().equals(existingRuleDelegation.getDelegationRuleBaseValues().getRuleBaseValuesId())) {
 1546  0
                     ruleDelegation.setDelegationRuleBaseValues(newDelegationRule);
 1547  0
                     foundDelegation = true;
 1548  0
                     break outer;
 1549  
                 }
 1550  
             }
 1551  
         }
 1552  0
         if (!foundDelegation) {
 1553  0
             throw new WorkflowRuntimeException("Failed to locate the existing rule delegation with id: " + existingRuleDelegation.getDelegationRuleBaseValues().getRuleBaseValuesId());
 1554  
         }
 1555  
 
 1556  0
     }
 1557  
 
 1558  
     protected RuleBaseValues createNewRuleVersion(RuleBaseValues existingRule, Long documentId) throws Exception {
 1559  0
         RuleBaseValues rule = new RuleBaseValues();
 1560  0
         PropertyUtils.copyProperties(rule, existingRule);
 1561  0
         rule.setPreviousVersion(existingRule);
 1562  0
         rule.setPreviousVersionId(existingRule.getRuleBaseValuesId());
 1563  0
         rule.setRuleBaseValuesId(null);
 1564  0
         rule.setActivationDate(null);
 1565  0
         rule.setDeactivationDate(null);
 1566  0
         rule.setVersionNumber(0L);
 1567  0
         rule.setRouteHeaderId(documentId);
 1568  
 
 1569  
         // TODO: FIXME: need to copy the rule expression here too?
 1570  
 
 1571  0
         rule.setResponsibilities(new ArrayList());
 1572  0
         for (RuleResponsibility existingResponsibility : (List<RuleResponsibility>)existingRule.getResponsibilities()) {
 1573  0
             RuleResponsibility responsibility = new RuleResponsibility();
 1574  0
             PropertyUtils.copyProperties(responsibility, existingResponsibility);
 1575  0
             responsibility.setRuleBaseValues(rule);
 1576  0
             responsibility.setRuleBaseValuesId(null);
 1577  0
             responsibility.setRuleResponsibilityKey(null);
 1578  0
             responsibility.setVersionNumber(0L);
 1579  0
             rule.getResponsibilities().add(responsibility);
 1580  
 //            responsibility.setDelegationRules(new ArrayList());
 1581  
 //            for (RuleDelegation existingDelegation : (List<RuleDelegation>)existingResponsibility.getDelegationRules()) {
 1582  
 //                RuleDelegation delegation = new RuleDelegation();
 1583  
 //                PropertyUtils.copyProperties(delegation, existingDelegation);
 1584  
 //                delegation.setRuleDelegationId(null);
 1585  
 //                delegation.setRuleResponsibility(responsibility);
 1586  
 //                delegation.setRuleResponsibilityId(null);
 1587  
 //                delegation.setVersionNumber(0L);
 1588  
 //                // it's very important that we do NOT recurse down into the delegation rules and reversion those,
 1589  
 //                // this is important to how rule versioning works
 1590  
 //                responsibility.getDelegationRules().add(delegation);
 1591  
 //            }
 1592  0
         }
 1593  0
         rule.setRuleExtensions(new ArrayList());
 1594  0
         for (RuleExtension existingExtension : (List<RuleExtension>)existingRule.getRuleExtensions()) {
 1595  0
             RuleExtension extension = new RuleExtension();
 1596  0
             PropertyUtils.copyProperties(extension, existingExtension);
 1597  0
             extension.setLockVerNbr(0);
 1598  0
             extension.setRuleBaseValues(rule);
 1599  0
             extension.setRuleBaseValuesId(null);
 1600  0
             extension.setRuleExtensionId(null);
 1601  0
             rule.getRuleExtensions().add(extension);
 1602  0
             extension.setExtensionValues(new ArrayList<RuleExtensionValue>());
 1603  0
             for (RuleExtensionValue existingExtensionValue : extension.getExtensionValues()) {
 1604  0
                 RuleExtensionValue extensionValue = new RuleExtensionValue();
 1605  0
                 PropertyUtils.copyProperties(extensionValue, existingExtensionValue);
 1606  0
                 extensionValue.setExtension(extension);
 1607  0
                 extensionValue.setRuleExtensionId(null);
 1608  0
                 extensionValue.setLockVerNbr(0);
 1609  0
                 extensionValue.setRuleExtensionValueId(null);
 1610  0
                 extension.getExtensionValues().add(extensionValue);
 1611  0
             }
 1612  0
         }
 1613  0
         return rule;
 1614  
     }
 1615  
 
 1616  0
     private static class RuleVersion {
 1617  
         public RuleBaseValues rule;
 1618  
         public RuleBaseValues parent;
 1619  
         public RuleDelegation delegation;
 1620  
     }
 1621  
 
 1622  0
     private static class RuleRoutingConfig {
 1623  0
         private List configs = new ArrayList();
 1624  
         public static RuleRoutingConfig parse() {
 1625  0
             RuleRoutingConfig config = new RuleRoutingConfig();
 1626  0
             String constant = Utilities.getKNSParameterValue(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_CUSTOM_DOC_TYPES);
 1627  0
             if (!StringUtils.isEmpty(constant)) {
 1628  0
                 String[] ruleConfigs = constant.split(",");
 1629  0
                 for (int index = 0; index < ruleConfigs.length; index++) {
 1630  0
                     String[] configElements = ruleConfigs[index].split(":");
 1631  0
                     if (configElements.length != 4) {
 1632  0
                         throw new RuntimeException("Found incorrect number of config elements within a section of the custom rule document types config.  There should have been four ':' delimited sections!  " + ruleConfigs[index]);
 1633  
                     }
 1634  0
                     config.configs.add(configElements);
 1635  
                 }
 1636  
             }
 1637  0
             return config;
 1638  
         }
 1639  
         public String getDocumentTypeName(RuleBaseValues rule) {
 1640  0
             for (Iterator iterator = configs.iterator(); iterator.hasNext();) {
 1641  0
                 String[] configElements = (String[]) iterator.next();
 1642  0
                 String docTypeName = configElements[0];
 1643  0
                 String ruleTemplateName = configElements[1];
 1644  0
                 String type = configElements[2];
 1645  0
                 String ruleDocTypeName = configElements[3];
 1646  0
                 if (rule.getDocTypeName().equals(docTypeName) && rule.getRuleTemplateName().equals(ruleTemplateName)) {
 1647  0
                     if (type.equals("M")) {
 1648  0
                         if (Boolean.FALSE.equals(rule.getDelegateRule())) {
 1649  0
                             return ruleDocTypeName;
 1650  
                         }
 1651  0
                     } else if (type.equals("D")) {
 1652  0
                         if (Boolean.TRUE.equals(rule.getDelegateRule())) {
 1653  0
                             return ruleDocTypeName;
 1654  
                         }
 1655  
                     } else {
 1656  0
                         throw new RuntimeException("Bad rule type '" + type + "' in rule doc type routing config.");
 1657  
                     }
 1658  
                 }
 1659  0
             }
 1660  0
             return null;
 1661  
         }
 1662  
     }
 1663  
 
 1664  
     public Long getDuplicateRuleId(RuleBaseValues rule) {
 1665  
 
 1666  
             // TODO: this method is extremely slow, if we could implement a more optimized query here, that would help tremendously
 1667  
 
 1668  0
             List responsibilities = rule.getResponsibilities();
 1669  0
             List extensions = rule.getRuleExtensions();
 1670  0
             String docTypeName = rule.getDocTypeName();
 1671  0
             String ruleTemplateName = rule.getRuleTemplateName();
 1672  0
         List rules = fetchAllCurrentRulesForTemplateDocCombination(rule.getRuleTemplateName(), rule.getDocTypeName(), false);
 1673  0
         Iterator it = rules.iterator();
 1674  0
         while (it.hasNext()) {
 1675  0
             RuleBaseValues r = (RuleBaseValues) it.next();
 1676  0
             if (Utilities.equals(rule.getActiveInd(), r.getActiveInd()) &&
 1677  
                 Utilities.equals(docTypeName, r.getDocTypeName()) &&
 1678  
                     Utilities.equals(ruleTemplateName, r.getRuleTemplateName()) &&
 1679  
                     Utilities.equals(rule.getRuleExpressionDef(), r.getRuleExpressionDef()) &&
 1680  
                     Utilities.collectionsEquivalent(responsibilities, r.getResponsibilities()) &&
 1681  
                     Utilities.collectionsEquivalent(extensions, r.getRuleExtensions())) {
 1682  
                 // we have a duplicate
 1683  0
                 return r.getRuleBaseValuesId();
 1684  
             }
 1685  0
         }
 1686  0
         return null;
 1687  
     }
 1688  
 
 1689  
     private void generateRuleNameIfNeeded(RuleBaseValues rule) {
 1690  0
         if (StringUtils.isBlank(rule.getName())) {
 1691  0
                 rule.setName(new Guid().toString());
 1692  
         }
 1693  0
     }
 1694  
 
 1695  
     private void assignResponsibilityIds(RuleBaseValues rule) {
 1696  0
             for (RuleResponsibility responsibility : rule.getResponsibilities()) {
 1697  0
                     if (responsibility.getResponsibilityId() == null) {
 1698  0
                             responsibility.setResponsibilityId(KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId());
 1699  
                     }
 1700  
             }
 1701  0
     }
 1702  
 
 1703  
     public RuleBaseValues saveRule(RuleBaseValues rule, boolean isRetroactiveUpdatePermitted) {
 1704  0
             rule.setPreviousVersionId(rule.getRuleBaseValuesId());
 1705  0
                 rule.setPreviousVersion(null);
 1706  0
                 rule.setRuleBaseValuesId(null);
 1707  0
                 makeCurrent(rule, isRetroactiveUpdatePermitted);
 1708  0
                 return rule;
 1709  
     }
 1710  
 
 1711  
     public List<RuleBaseValues> saveRules(List<RuleBaseValues> rulesToSave, boolean isRetroactiveUpdatePermitted) {
 1712  0
             List<RuleBaseValues> savedRules = new ArrayList<RuleBaseValues>();
 1713  0
             for (RuleBaseValues rule : rulesToSave) {
 1714  0
                     rule = saveRule(rule, isRetroactiveUpdatePermitted);
 1715  0
                     savedRules.add(rule);
 1716  
             }
 1717  0
             return savedRules;
 1718  
     }
 1719  
 
 1720  
     public RuleDelegation saveRuleDelegation(RuleDelegation ruleDelegation, boolean isRetroactiveUpdatePermitted) {
 1721  0
             RuleBaseValues rule = ruleDelegation.getDelegationRuleBaseValues();
 1722  0
                 rule.setPreviousVersionId(rule.getRuleBaseValuesId());
 1723  0
                 rule.setPreviousVersion(null);
 1724  0
                 rule.setRuleBaseValuesId(null);
 1725  0
                 ruleDelegation.setRuleDelegationId(null);
 1726  0
                 makeCurrent(ruleDelegation, isRetroactiveUpdatePermitted);
 1727  0
                 return ruleDelegation;
 1728  
     }
 1729  
 
 1730  
     public List<RuleDelegation> saveRuleDelegations(List<RuleDelegation> ruleDelegationsToSave, boolean isRetroactiveUpdatePermitted) {
 1731  0
             List<RuleDelegation> savedRuleDelegations = new ArrayList<RuleDelegation>();
 1732  0
             for (RuleDelegation ruleDelegation : ruleDelegationsToSave) {
 1733  0
                     ruleDelegation = saveRuleDelegation(ruleDelegation, isRetroactiveUpdatePermitted);
 1734  0
                     savedRuleDelegations.add(ruleDelegation);
 1735  
             }
 1736  0
             return savedRuleDelegations;
 1737  
     }
 1738  
 
 1739  
     public Long findResponsibilityIdForRule(String ruleName, String ruleResponsibilityName, String ruleResponsibilityType) {
 1740  0
             return getRuleDAO().findResponsibilityIdForRule(ruleName, ruleResponsibilityName, ruleResponsibilityType);
 1741  
     }
 1742  
 
 1743  
 }