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