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