Clover Coverage Report - Implementation 2.0.0-SNAPSHOT
Coverage timestamp: Wed Dec 31 1969 19:00:00 EST
../../../../../../../img/srcFileCovDistChart0.png 0% of files have more coverage
665   1,498   256   7.82
268   1,126   0.38   21.25
85     3.01  
4    
 
  RuleServiceImpl       Line # 90 634 0% 242 964 0% 0.0
  RuleServiceImpl.RuleDelegationSorter       Line # 1219 6 0% 3 11 0% 0.0
  RuleServiceImpl.RuleVersion       Line # 1371 0 - 0 0 - -1.0
  RuleServiceImpl.RuleRoutingConfig       Line # 1377 25 0% 11 43 0% 0.0
 
No Tests
 
1    /*
2    * Copyright 2006-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package org.kuali.rice.kew.rule.service.impl;
18   
19    import java.io.InputStream;
20    import java.sql.Timestamp;
21    import java.text.ParseException;
22    import java.util.ArrayList;
23    import java.util.Collection;
24    import java.util.Collections;
25    import java.util.Comparator;
26    import java.util.HashMap;
27    import java.util.HashSet;
28    import java.util.Iterator;
29    import java.util.List;
30    import java.util.Map;
31    import java.util.Set;
32    import java.util.UUID;
33   
34    import javax.xml.namespace.QName;
35   
36    import org.apache.commons.beanutils.PropertyUtils;
37    import org.apache.commons.lang.ObjectUtils;
38    import org.apache.commons.lang.StringUtils;
39    import org.jdom.Element;
40    import org.kuali.rice.core.api.impex.ExportDataSet;
41    import org.kuali.rice.core.api.impex.xml.XmlConstants;
42    import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
43    import org.kuali.rice.core.util.CollectionUtils;
44    import org.kuali.rice.core.util.RiceConstants;
45    import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
46    import org.kuali.rice.kew.doctype.bo.DocumentType;
47    import org.kuali.rice.kew.doctype.service.DocumentTypeService;
48    import org.kuali.rice.kew.dto.WorkflowIdDTO;
49    import org.kuali.rice.kew.exception.WorkflowRuntimeException;
50    import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
51    import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
52    import org.kuali.rice.kew.messaging.MessageServiceNames;
53    import org.kuali.rice.kew.responsibility.service.ResponsibilityIdService;
54    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
55    import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
56    import org.kuali.rice.kew.rule.RuleBaseValues;
57    import org.kuali.rice.kew.rule.RuleDelegation;
58    import org.kuali.rice.kew.rule.RuleExtension;
59    import org.kuali.rice.kew.rule.RuleExtensionValue;
60    import org.kuali.rice.kew.rule.RuleResponsibility;
61    import org.kuali.rice.kew.rule.RuleRoutingDefinition;
62    import org.kuali.rice.kew.rule.RuleValidationAttribute;
63    import org.kuali.rice.kew.rule.bo.RuleTemplate;
64    import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
65    import org.kuali.rice.kew.rule.dao.RuleDAO;
66    import org.kuali.rice.kew.rule.dao.RuleResponsibilityDAO;
67    import org.kuali.rice.kew.rule.service.RuleCacheProcessor;
68    import org.kuali.rice.kew.rule.service.RuleDelegationCacheProcessor;
69    import org.kuali.rice.kew.rule.service.RuleDelegationService;
70    import org.kuali.rice.kew.rule.service.RuleService;
71    import org.kuali.rice.kew.rule.service.RuleTemplateService;
72    import org.kuali.rice.kew.service.KEWServiceLocator;
73    import org.kuali.rice.kew.service.WorkflowDocument;
74    import org.kuali.rice.kew.util.KEWConstants;
75    import org.kuali.rice.kew.util.PerformanceLogger;
76    import org.kuali.rice.kew.validation.RuleValidationContext;
77    import org.kuali.rice.kew.validation.ValidationResults;
78    import org.kuali.rice.kew.xml.RuleXmlParser;
79    import org.kuali.rice.kew.xml.export.RuleXmlExporter;
80    import org.kuali.rice.kim.bo.Group;
81    import org.kuali.rice.kim.bo.entity.KimPrincipal;
82    import org.kuali.rice.kim.service.IdentityManagementService;
83    import org.kuali.rice.kim.service.KIMServiceLocator;
84    import org.kuali.rice.kns.UserSession;
85    import org.kuali.rice.kns.util.GlobalVariables;
86    import org.kuali.rice.kns.util.KNSConstants;
87    import org.kuali.rice.ksb.service.KSBServiceLocator;
88   
89   
 
90    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    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  0 toggle public RuleResponsibilityDAO getRuleResponsibilityDAO() {
102  0 return ruleResponsibilityDAO;
103    }
104   
 
105  0 toggle public RuleBaseValues getRuleByName(String name) {
106  0 return ruleDAO.findRuleBaseValuesByName(name);
107    }
108   
 
109  0 toggle public RuleBaseValues findDefaultRuleByRuleTemplateId(Long ruleTemplateId){
110  0 return this.ruleDAO.findDefaultRuleByRuleTemplateId(ruleTemplateId);
111    }
 
112  0 toggle public void setRuleResponsibilityDAO(RuleResponsibilityDAO ruleResponsibilityDAO) {
113  0 this.ruleResponsibilityDAO = ruleResponsibilityDAO;
114    }
115   
 
116  0 toggle public void save2(RuleBaseValues ruleBaseValues) throws Exception {
117  0 save2(ruleBaseValues, null, true);
118    }
119   
 
120  0 toggle 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    }
145    }
146    }
147  0 validate2(ruleBaseValues, ruleDelegation, null);
148  0 getRuleDAO().save(ruleBaseValues);
149    }
150   
 
151  0 toggle public void makeCurrent(Long routeHeaderId) {
152  0 makeCurrent(findByRouteHeaderId(routeHeaderId));
153    }
154   
 
155  0 toggle public void makeCurrent(List rules) {
156  0 PerformanceLogger performanceLogger = new PerformanceLogger();
157   
158  0 boolean isGenerateRuleArs = true;
159  0 String generateRuleArs = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
160  0 if (!StringUtils.isBlank(generateRuleArs)) {
161  0 isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
162    }
163  0 Set responsibilityIds = new HashSet();
164  0 HashMap rulesToSave = new HashMap();
165   
166  0 Collections.sort(rules, new RuleDelegationSorter());
167  0 boolean delegateFirst = false;
168  0 for (Iterator iter = rules.iterator(); iter.hasNext();) {
169  0 RuleBaseValues rule = (RuleBaseValues) iter.next();
170   
171  0 performanceLogger.log("Preparing rule: " + rule.getDescription());
172   
173  0 rule.setCurrentInd(Boolean.TRUE);
174  0 Timestamp date = new Timestamp(System.currentTimeMillis());
175  0 rule.setActivationDate(date);
176  0 try {
177  0 rule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
178    } catch (Exception e) {
179  0 LOG.error("Parse Exception", e);
180    }
181  0 rulesToSave.put(rule.getRuleBaseValuesId(), rule);
182  0 RuleBaseValues oldRule = rule.getPreviousVersion();
183  0 if (oldRule != null) {
184  0 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
185   
186  0 oldRule.setCurrentInd(Boolean.FALSE);
187  0 oldRule.setDeactivationDate(date);
188  0 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
189  0 if (!delegateFirst) {
190  0 responsibilityIds.addAll(getResponsibilityIdsFromGraph(oldRule, isGenerateRuleArs));
191    }
192    //TODO if more than one delegate is edited from the create delegation screen (which currently can not happen), then this logic will not work.
193  0 if (rule.getDelegateRule().booleanValue() && rule.getPreviousVersionId() != null) {
194  0 delegateFirst = true;
195    }
196   
197  0 List oldDelegationRules = findOldDelegationRules(oldRule, rule, performanceLogger);
198  0 for (Iterator iterator = oldDelegationRules.iterator(); iterator.hasNext();) {
199  0 RuleBaseValues delegationRule = (RuleBaseValues) iterator.next();
200   
201  0 performanceLogger.log("Setting previous delegation rule: " + delegationRule.getRuleBaseValuesId() + "to non current.");
202   
203  0 delegationRule.setCurrentInd(Boolean.FALSE);
204  0 rulesToSave.put(delegationRule.getRuleBaseValuesId(), delegationRule);
205  0 responsibilityIds.addAll(getResponsibilityIdsFromGraph(delegationRule, isGenerateRuleArs));
206    }
207    }
208  0 for (Object element : rule.getResponsibilities()) {
209  0 RuleResponsibility responsibility = (RuleResponsibility) element;
210  0 for (Object element2 : responsibility.getDelegationRules()) {
211  0 RuleDelegation delegation = (RuleDelegation) element2;
212   
213  0 delegation.getDelegationRuleBaseValues().setCurrentInd(Boolean.TRUE);
214  0 RuleBaseValues delegatorRule = delegation.getDelegationRuleBaseValues();
215   
216  0 performanceLogger.log("Setting delegate rule: " + delegatorRule.getDescription() + " to current.");
217  0 if (delegatorRule.getActivationDate() == null) {
218  0 delegatorRule.setActivationDate(date);
219    }
220  0 try {
221  0 delegatorRule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
222    } catch (Exception e) {
223  0 LOG.error("Parse Exception", e);
224    }
225  0 rulesToSave.put(delegatorRule.getRuleBaseValuesId(), delegatorRule);
226    }
227    }
228    }
229  0 Map<String, Long> notifyMap = new HashMap<String, Long>();
230  0 for (Iterator iterator = rulesToSave.values().iterator(); iterator.hasNext();) {
231  0 RuleBaseValues rule = (RuleBaseValues) iterator.next();
232  0 getRuleDAO().save(rule);
233  0 performanceLogger.log("Saved rule: " + rule.getRuleBaseValuesId());
234  0 installNotification(rule, notifyMap);
235    }
236  0 LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
237  0 for (Object element : notifyMap.values()) {
238  0 queueRuleCache((Long)element);
239    }
240   
241  0 getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
242  0 performanceLogger.log("Time to make current");
243    }
244   
245    /**
246    * TODO consolidate this method with makeCurrent. The reason there's a seperate implementation is because the
247    * original makeCurrent(...) could not properly handle versioning a List of multiple rules (including multiple
248    * delegates rules for a single parent. ALso, this work is being done for a patch so we want to mitigate the
249    * impact on the existing rule code.
250    *
251    * <p>This version will only work for remove/replace operations where rules
252    * aren't being added or removed. This is why it doesn't perform some of the functions like checking
253    * for delegation rules that were removed from a parent rule.
254    */
 
255  0 toggle public void makeCurrent2(List rules) {
256  0 PerformanceLogger performanceLogger = new PerformanceLogger();
257   
258  0 boolean isGenerateRuleArs = true;
259  0 String generateRuleArs = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
260  0 if (!StringUtils.isBlank(generateRuleArs)) {
261  0 isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
262    }
263  0 Set<Long> responsibilityIds = new HashSet<Long>();
264  0 Map<Long, RuleBaseValues> rulesToSave = new HashMap<Long, RuleBaseValues>();
265   
266  0 Collections.sort(rules, new RuleDelegationSorter());
267  0 for (Iterator iter = rules.iterator(); iter.hasNext();) {
268  0 RuleBaseValues rule = (RuleBaseValues) iter.next();
269   
270  0 performanceLogger.log("Preparing rule: " + rule.getDescription());
271   
272  0 rule.setCurrentInd(Boolean.TRUE);
273  0 Timestamp date = new Timestamp(System.currentTimeMillis());
274  0 rule.setActivationDate(date);
275  0 try {
276  0 rule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
277    } catch (Exception e) {
278  0 LOG.error("Parse Exception", e);
279    }
280  0 rulesToSave.put(rule.getRuleBaseValuesId(), rule);
281  0 RuleBaseValues oldRule = rule.getPreviousVersion();
282  0 if (oldRule != null) {
283  0 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
284  0 oldRule.setCurrentInd(Boolean.FALSE);
285  0 oldRule.setDeactivationDate(date);
286  0 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
287  0 responsibilityIds.addAll(getModifiedResponsibilityIds(oldRule, rule));
288    }
289  0 for (Object element : rule.getResponsibilities()) {
290  0 RuleResponsibility responsibility = (RuleResponsibility) element;
291  0 for (Object element2 : responsibility.getDelegationRules()) {
292  0 RuleDelegation delegation = (RuleDelegation) element2;
293  0 RuleBaseValues delegateRule = delegation.getDelegationRuleBaseValues();
294  0 delegateRule.setCurrentInd(Boolean.TRUE);
295  0 performanceLogger.log("Setting delegate rule: " + delegateRule.getDescription() + " to current.");
296  0 if (delegateRule.getActivationDate() == null) {
297  0 delegateRule.setActivationDate(date);
298    }
299  0 try {
300  0 delegateRule.setDeactivationDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
301    } catch (Exception e) {
302  0 LOG.error("Parse Exception", e);
303    }
304  0 rulesToSave.put(delegateRule.getRuleBaseValuesId(), delegateRule);
305    }
306    }
307    }
308  0 Map<String, Long> notifyMap = new HashMap<String, Long>();
309  0 for (RuleBaseValues rule : rulesToSave.values()) {
310  0 getRuleDAO().save(rule);
311  0 performanceLogger.log("Saved rule: " + rule.getRuleBaseValuesId());
312  0 installNotification(rule, notifyMap);
313    }
314  0 LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
315  0 for (Object element : notifyMap.values()) {
316  0 queueRuleCache((Long)element);
317    }
318  0 if (isGenerateRuleArs) {
319  0 getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
320    }
321  0 performanceLogger.log("Time to make current");
322    }
323   
324    /**
325    * makeCurrent(RuleBaseValues) is the version of makeCurrent which is initiated from the new Routing Rule
326    * Maintenance document. Because of the changes in the data model and the front end here,
327    * this method can be much less complicated than the previous 2!
328    */
 
329  0 toggle public void makeCurrent(RuleBaseValues rule, boolean isRetroactiveUpdatePermitted) {
330  0 makeCurrent(null, rule, isRetroactiveUpdatePermitted);
331    }
332   
 
333  0 toggle public void makeCurrent(RuleDelegation ruleDelegation, boolean isRetroactiveUpdatePermitted) {
334  0 makeCurrent(ruleDelegation, ruleDelegation.getDelegationRuleBaseValues(), isRetroactiveUpdatePermitted);
335    }
336   
 
337  0 toggle protected void makeCurrent(RuleDelegation ruleDelegation, RuleBaseValues rule, boolean isRetroactiveUpdatePermitted) {
338  0 PerformanceLogger performanceLogger = new PerformanceLogger();
339   
340  0 boolean isGenerateRuleArs = false;
341  0 if (isRetroactiveUpdatePermitted) {
342  0 isGenerateRuleArs = true;
343  0 String generateRuleArs = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, KEWConstants.RULE_GENERATE_ACTION_REQESTS_IND);
344  0 if (!StringUtils.isBlank(generateRuleArs)) {
345  0 isGenerateRuleArs = KEWConstants.YES_RULE_CHANGE_AR_GENERATION_VALUE.equalsIgnoreCase(generateRuleArs);
346    }
347    }
348  0 Set<Long> responsibilityIds = new HashSet<Long>();
349   
350   
351  0 performanceLogger.log("Preparing rule: " + rule.getDescription());
352   
353  0 Map<Long, RuleBaseValues> rulesToSave = new HashMap<Long, RuleBaseValues>();
354  0 generateRuleNameIfNeeded(rule);
355  0 assignResponsibilityIds(rule);
356  0 rule.setCurrentInd(Boolean.TRUE);
357  0 Timestamp date = new Timestamp(System.currentTimeMillis());
358  0 rule.setActivationDate(date);
359  0 rule.setDeactivationDate(null);
360   
361  0 rulesToSave.put(rule.getRuleBaseValuesId(), rule);
362  0 if (rule.getPreviousVersionId() != null) {
363  0 RuleBaseValues oldRule = findRuleBaseValuesById(rule.getPreviousVersionId());
364  0 rule.setPreviousVersion(oldRule);
365    }
366  0 rule.setVersionNbr(0);
367  0 RuleBaseValues oldRule = rule.getPreviousVersion();
368  0 if (oldRule != null) {
369  0 performanceLogger.log("Setting previous rule: " + oldRule.getRuleBaseValuesId() + " to non current.");
370  0 oldRule.setCurrentInd(Boolean.FALSE);
371  0 oldRule.setDeactivationDate(date);
372  0 rulesToSave.put(oldRule.getRuleBaseValuesId(), oldRule);
373  0 responsibilityIds.addAll(getModifiedResponsibilityIds(oldRule, rule));
374  0 rule.setVersionNbr(getNextVersionNumber(oldRule));
375    }
376   
377   
378  0 boolean isRuleDelegation = ruleDelegation != null;
379   
380  0 Map<String, Long> notifyMap = new HashMap<String, Long>();
381   
382  0 for (RuleBaseValues ruleToSave : rulesToSave.values()) {
383  0 getRuleDAO().save(ruleToSave);
384  0 performanceLogger.log("Saved rule: " + ruleToSave.getRuleBaseValuesId());
385  0 if (!isRuleDelegation) {
386  0 installNotification(ruleToSave, notifyMap);
387    }
388    }
389  0 if (isRuleDelegation) {
390  0 responsibilityIds.add(ruleDelegation.getResponsibilityId());
391  0 ruleDelegation.setDelegateRuleId(rule.getRuleBaseValuesId());
392  0 getRuleDelegationService().save(ruleDelegation);
393  0 installDelegationNotification(ruleDelegation.getResponsibilityId(), notifyMap);
394    }
395  0 LOG.info("Notifying rule cache of "+notifyMap.size()+" cache changes.");
396  0 for (Iterator iterator = notifyMap.values().iterator(); iterator.hasNext();) {
397  0 if (isRuleDelegation) {
398  0 queueDelegationRuleCache((Long)iterator.next());
399    } else {
400  0 queueRuleCache((Long)iterator.next());
401    }
402    }
403   
404   
405   
406  0 if (isGenerateRuleArs) {
407  0 getActionRequestService().updateActionRequestsForResponsibilityChange(responsibilityIds);
408    }
409  0 performanceLogger.log("Time to make current");
410    }
411   
412   
 
413  0 toggle private void queueRuleCache(Long ruleId){
414    // PersistedMessageBO ruleCache = new PersistedMessageBO();
415    // ruleCache.setQueuePriority(KEWConstants.ROUTE_QUEUE_RULE_CACHE_PRIORITY);
416    // ruleCache.setQueueDate(new Timestamp(new Date().getTime()));
417    // ruleCache.setQueueStatus(KEWConstants.ROUTE_QUEUE_QUEUED);
418    // ruleCache.setRetryCount(new Integer(0));
419    // ruleCache.setPayload("" + ruleId);
420    // ruleCache.setProcessorClassName("org.kuali.rice.ksb.cache.RuleCacheProcessor");
421    // getRouteQueueService().requeueDocument(ruleCache);
422   
423   
424  0 RuleCacheProcessor ruleCacheProcessor = MessageServiceNames.getRuleCacheProcessor();
425  0 ruleCacheProcessor.clearRuleFromCache(ruleId);
426   
427    }
428   
429    // private RouteQueueService getRouteQueueService() {
430    // return (RouteQueueService)SpringServiceLocator.getService(SpringServiceLocator.ROUTE_QUEUE_SRV);
431    // }
432   
433    /**
434    * Ensure that we don't have any notification duplication.
435    */
 
436  0 toggle private void installNotification(RuleBaseValues rule, Map<String, Long> notifyMap) {
437    // don't notify the cache if it's a "template" rule!
438  0 if (!rule.getTemplateRuleInd()) {
439  0 String key = getRuleCacheKey(rule.getRuleTemplateName(), rule.getDocTypeName());
440  0 if (!notifyMap.containsKey(key)) {
441  0 notifyMap.put(key, rule.getRuleBaseValuesId());
442    }
443    }
444    }
445   
 
446  0 toggle private void queueDelegationRuleCache(Long responsibilityId) {
447  0 RuleDelegationCacheProcessor ruleDelegationCacheProcessor = (RuleDelegationCacheProcessor)KSBServiceLocator.getMessageHelper().getServiceAsynchronously(new QName("RuleDelegationCacheProcessorService"), null, null, null, null);
448  0 ruleDelegationCacheProcessor.clearRuleDelegationFromCache(responsibilityId);
449    }
450   
 
451  0 toggle private void installDelegationNotification(Long responsibilityId, Map<String, Long> notifyMap) {
452    // don't notify the cache if it's a "template" rule!
453  0 String key = getRuleDlgnCacheKey(responsibilityId);
454  0 if (!notifyMap.containsKey(key)) {
455  0 notifyMap.put(key, responsibilityId);
456    }
457    }
458   
 
459  0 toggle protected String getRuleDlgnCacheKey(Long responsibilityId) {
460  0 return "RuleDlgnCache:" + responsibilityId;
461    }
462   
 
463  0 toggle public RuleBaseValues getParentRule(Long ruleBaseValuesId) {
464  0 return getRuleDAO().getParentRule(ruleBaseValuesId);
465    }
466   
 
467  0 toggle public void notifyCacheOfDocumentTypeChange(DocumentType documentType) {
468  0 DocumentType rootDocumentType = KEWServiceLocator.getDocumentTypeService().findRootDocumentType(documentType);
469  0 notifyCacheOfDocumentTypeChangeFromRoot(rootDocumentType, documentType);
470  0 notifyCacheOfDocumentTypeChangeFromParent(documentType);
471    }
472   
473    /**
474    * Flushes rules cached for the given DocumentType and then recursivley flushes rules cached
475    * for all children DocumentTypes.
476    */
 
477  0 toggle protected void notifyCacheOfDocumentTypeChangeFromParent(DocumentType documentType) {
478  0 flushDocumentTypeFromCache(documentType.getName());
479  0 for (Iterator iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
480  0 notifyCacheOfDocumentTypeChangeFromParent((DocumentType) iter.next());
481    }
482    }
483   
484    /**
485    * Flushes rules cached from the root of the DocumentType hierarchy (at the given root DocumentType). Stops
486    * when it hits the given DocumentType. This method exists because of the nature of
487    * DocumentTypeService.findRootDocumentType(...). Whenever we have a modification to child document type
488    * and we call findRootDocumentType(...) on it, we end up getting back a version of the root document type
489    * which is cached in the OJB transaction cache and doesn't have the appropriate child document type attached.
490    * A better way to handle this would be to go into the DocumentType service and fix how it versions document
491    * types in versionAndSave to prevent this issue from occurring.
492    *
493    * <p>If such a fix was made then we could simply pass the root DocumentType into notifyCacheOfDocumentTypeChange
494    * and be gauranteed that we will see all appropriate children as we call getChildrenDocTypes().
495    *
496    * <p>One last note, we don't necesarily have to stop this cache flusing at the given DocumentType but there's
497    * no reason to duplicate the work that is going to be done in notifyCacheOfDocumentTypeChangeFromParent.
498    */
 
499  0 toggle protected void notifyCacheOfDocumentTypeChangeFromRoot(DocumentType rootDocumentType, DocumentType documentType) {
500  0 if (rootDocumentType.getName().equals(documentType.getName())) {
501  0 return;
502    }
503  0 flushDocumentTypeFromCache(rootDocumentType.getName());
504  0 for (Iterator iter = rootDocumentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
505  0 notifyCacheOfDocumentTypeChangeFromRoot((DocumentType) iter.next(), documentType);
506    }
507    }
508   
 
509  0 toggle public void notifyCacheOfRuleChange(RuleBaseValues rule, DocumentType documentType) {
510  0 Boolean cachingRules = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, USING_RULE_CACHE_IND);
511   
512  0 LOG.info("Entering notifyCacheOfRuleChange. CachingRules: " + cachingRules + " ; ruleID: " + rule.getRuleBaseValuesId());
513  0 if (!cachingRules.booleanValue()) {
514  0 return;
515    }
516    // named rules may be templateless, and therefore cannot be mapped into the cache by templatename/doctype key
517    // but we still need to make sure that if there was a previous version with a template, that the cache is blown away
518  0 String ruleTemplateName = null;
519  0 if (rule.getRuleTemplate() == null) {
520  0 if (rule.getPreviousVersion() != null) {
521  0 RuleBaseValues prev = rule.getPreviousVersion();
522  0 if (prev.getRuleTemplate() != null) {
523  0 ruleTemplateName = prev.getRuleTemplate().getName();
524    }
525    }
526    } else {
527  0 ruleTemplateName = rule.getRuleTemplate().getName();
528    }
529   
530  0 if (documentType == null) {
531  0 documentType = getDocumentTypeService().findByName(rule.getDocTypeName());
532    // if it's a delegate rule, we need to look at the parent's template
533  0 if (Boolean.TRUE.equals(rule.getDelegateRule())) {
534  0 List delegations = getRuleDelegationService().findByDelegateRuleId(rule.getRuleBaseValuesId());
535  0 for (Iterator iterator = delegations.iterator(); iterator.hasNext();) {
536  0 RuleDelegation ruleDelegation = (RuleDelegation) iterator.next();
537  0 RuleBaseValues parentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
538  0 if (Boolean.TRUE.equals(parentRule.getCurrentInd())) {
539  0 ruleTemplateName = parentRule.getRuleTemplate().getName();
540  0 break;
541    }
542    }
543    }
544    }
545  0 flushListFromCache(ruleTemplateName, documentType.getName());
546   
547    // if (getListFromCache(ruleTemplateName, documentType.getName()) != null) {
548    // eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentType.getName())));
549    // }
550    //}
551    //walk the down the document hierarchy when refreshing the cache. The
552    // rule could be cached through more than one path
553    //HREDOC could be cached under HREDOC.child and HREDOC.child1
554  0 for (Iterator iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext();) {
555  0 DocumentType childDocumentType = (DocumentType) iter.next();
556    //SpringServiceLocator.getCacheAdministrator().flushEntry(getRuleCacheKey(ruleTemplateName, childDocumentType.getName()));
557    // if (getListFromCache(rule.getRuleTemplate().getName(), childDocumentType.getName()) != null) {
558    // eventGenerator.notify(new CacheDataModifiedEvent(RULE_CACHE_NAME, getRuleCacheKey(rule.getRuleTemplate().getName(), childDocumentType.getName())));
559    // }
560  0 notifyCacheOfRuleChange(rule, childDocumentType);
561    }
562  0 LOG.info("Leaving notifyCacheOfRuleChange. CachingRules: " + cachingRules + " ; ruleID: " + rule.getRuleBaseValuesId() + " ; documentType: " + documentType.getDocumentTypeId());
563   
564   
565   
566    }
567   
568    /**
569    * Returns the key of the rule cache.
570    */
 
571  0 toggle protected String getRuleCacheKey(String ruleTemplateName, String docTypeName) {
572  0 return "RuleCache:" + ruleTemplateName + "_" + docTypeName;
573    }
574   
575    /*
576    * Return the cache group name for the given DocumentType
577    */
 
578  0 toggle protected String getDocumentTypeRuleCacheGroupName(String documentTypeName) {
579  0 return "DocumentTypeRuleCache:"+documentTypeName;
580    }
581   
 
582  0 toggle protected List<RuleBaseValues> getListFromCache(String ruleTemplateName, String documentTypeName) {
583  0 LOG.debug("Retrieving List of Rules from cache for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
584  0 return (List) KEWServiceLocator.getCacheAdministrator().getFromCache(getRuleCacheKey(ruleTemplateName, documentTypeName));
585    //return (List) SpringServiceLocator.getCache().getCachedObjectById(RULE_CACHE_NAME, getRuleCacheKey(ruleTemplateName, documentTypeName));
586    }
587   
 
588  0 toggle protected void putListInCache(String ruleTemplateName, String documentTypeName, List<RuleBaseValues> rules) {
589  0 assert(ruleTemplateName != null) : "putListInCache was called with a null ruleTemplateName";
590  0 LOG.info("Caching " + rules.size() + " rules for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
591  0 String groups[] = new String[] { getDocumentTypeRuleCacheGroupName(documentTypeName), RULE_GROUP_CACHE };
592  0 KEWServiceLocator.getCacheAdministrator().putInCache(getRuleCacheKey(ruleTemplateName, documentTypeName), rules, groups);
593    }
594   
 
595  0 toggle protected void flushDocumentTypeFromCache(String documentTypeName) {
596  0 LOG.info("Flushing DocumentType from Cache for the given name: " + documentTypeName);
597  0 KEWServiceLocator.getCacheAdministrator().flushGroup(getDocumentTypeRuleCacheGroupName(documentTypeName));
598    }
599   
 
600  0 toggle protected void flushListFromCache(String ruleTemplateName, String documentTypeName) {
601  0 LOG.info("Flushing rules from Cache for ruleTemplate='" + ruleTemplateName + "' and documentType='" + documentTypeName + "'");
602  0 KEWServiceLocator.getCacheAdministrator().flushEntry(getRuleCacheKey(ruleTemplateName, documentTypeName));
603    }
604   
 
605  0 toggle public void flushRuleCache() {
606  0 LOG.info("Flushing entire Rule Cache.");
607  0 KEWServiceLocator.getCacheAdministrator().flushGroup(RULE_GROUP_CACHE);
608    }
609   
 
610  0 toggle private Set getResponsibilityIdsFromGraph(RuleBaseValues rule, boolean isRuleCollecting) {
611  0 Set responsibilityIds = new HashSet();
612  0 for (Object element : rule.getResponsibilities()) {
613  0 RuleResponsibility responsibility = (RuleResponsibility) element;
614  0 if (isRuleCollecting) {
615  0 responsibilityIds.add(responsibility.getResponsibilityId());
616    }
617    }
618  0 return responsibilityIds;
619    }
620   
621    /**
622    * Returns the responsibility IDs that were modified between the 2 given versions of the rule. Any added
623    * or removed responsibilities are also included in the returned Set.
624    */
 
625  0 toggle private Set<Long> getModifiedResponsibilityIds(RuleBaseValues oldRule, RuleBaseValues newRule) {
626  0 Map<Long, RuleResponsibility> modifiedResponsibilityMap = new HashMap<Long, RuleResponsibility>();
627  0 for (Object element : oldRule.getResponsibilities()) {
628  0 RuleResponsibility responsibility = (RuleResponsibility) element;
629  0 modifiedResponsibilityMap.put(responsibility.getResponsibilityId(), responsibility);
630    }
631  0 for (Object element : newRule.getResponsibilities()) {
632  0 RuleResponsibility responsibility = (RuleResponsibility) element;
633  0 RuleResponsibility oldResponsibility = modifiedResponsibilityMap.get(responsibility.getResponsibilityId());
634  0 if (oldResponsibility == null) {
635    // if there's no old responsibility then it's a new responsibility, add it
636  0 modifiedResponsibilityMap.put(responsibility.getResponsibilityId(), responsibility);
637  0 } else if (!hasResponsibilityChanged(oldResponsibility, responsibility)) {
638    // if it hasn't been modified, remove it from the collection of modified ids
639  0 modifiedResponsibilityMap.remove(responsibility.getResponsibilityId());
640    }
641    }
642  0 return modifiedResponsibilityMap.keySet();
643    }
644   
645    /**
646    * Determines if the given responsibilities are different or not.
647    */
 
648  0 toggle private boolean hasResponsibilityChanged(RuleResponsibility oldResponsibility, RuleResponsibility newResponsibility) {
649  0 return !ObjectUtils.equals(oldResponsibility.getActionRequestedCd(), newResponsibility.getActionRequestedCd()) ||
650    !ObjectUtils.equals(oldResponsibility.getApprovePolicy(), newResponsibility.getActionRequestedCd()) ||
651    !ObjectUtils.equals(oldResponsibility.getPriority(), newResponsibility.getPriority()) ||
652    !ObjectUtils.equals(oldResponsibility.getRole(), newResponsibility.getRole()) ||
653    !ObjectUtils.equals(oldResponsibility.getRuleResponsibilityName(), newResponsibility.getRuleResponsibilityName()) ||
654    !ObjectUtils.equals(oldResponsibility.getRuleResponsibilityType(), newResponsibility.getRuleResponsibilityType());
655    }
656   
657    /*
658    private Map findOldDelegationRules(RuleBaseValues oldRule, RuleBaseValues newRule, PerformanceLogger performanceLogger) {
659    Map oldRules = new HashMap();
660    performanceLogger.log("Begin to get delegation rules.");
661    for (Iterator iterator = oldRule.getResponsibilities().iterator(); iterator.hasNext();) {
662    RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
663    for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
664    RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
665    RuleBaseValues delegateRule = ruleDelegation.getDelegationRuleBaseValues();
666    performanceLogger.log("Found delegate rule: "+ delegateRule.getRuleBaseValuesId());
667    oldRules.put(ruleDelegation.getDelegateRuleId(), delegateRule);
668    }
669    }
670    performanceLogger.log("Begin removing rule delegations from new rule.");
671    for (Iterator iterator = newRule.getResponsibilities().iterator(); iterator.hasNext();) {
672    RuleResponsibility responsibility = (RuleResponsibility) iterator.next();
673    for (Iterator delIterator = responsibility.getDelegationRules().iterator(); delIterator.hasNext();) {
674    RuleDelegation ruleDelegation = (RuleDelegation) delIterator.next();
675    performanceLogger.log("Removing rule delegation: "+ ruleDelegation.getDelegateRuleId()+" from new rule.");
676    oldRules.remove(ruleDelegation.getDelegateRuleId());
677    }
678    }
679    return oldRules;
680    }
681    */
682    /**
683    * This method will find any old delegation rules on the previous version of the parent rule which are not on the
684    * new version of the rule so that they can be marked non-current.
685    */
 
686  0 toggle private List findOldDelegationRules(RuleBaseValues oldRule, RuleBaseValues newRule, PerformanceLogger performanceLogger) {
687  0 performanceLogger.log("Begin to get delegation rules.");
688  0 List oldDelegations = getRuleDAO().findOldDelegations(oldRule, newRule);
689  0 performanceLogger.log("Located "+oldDelegations.size()+" old delegation rules.");
690  0 return oldDelegations;
691    }
692   
 
693  0 toggle public Long routeRuleWithDelegate(Long routeHeaderId, RuleBaseValues parentRule, RuleBaseValues delegateRule, KimPrincipal principal, String annotation, boolean blanketApprove) throws Exception {
694  0 if (parentRule == null) {
695  0 throw new IllegalArgumentException("Cannot route a delegate without a parent rule.");
696    }
697  0 if (parentRule.getDelegateRule().booleanValue()) {
698  0 throw new IllegalArgumentException("Parent rule cannot be a delegate.");
699    }
700  0 if (parentRule.getPreviousVersionId() == null && delegateRule.getPreviousVersionId() == null) {
701  0 throw new IllegalArgumentException("Previous rule version required.");
702    }
703   
704    // if the parent rule is new, unsaved, then save it
705    // boolean isRoutingParent = parentRule.getRuleBaseValuesId() == null;
706    // if (isRoutingParent) {
707    // // it's very important that we do not save delegations here (that's what the false parameter is for)
708    // // this is because, if we save the delegations, the existing delegations on our parent rule will become
709    // // saved as "non current" before the rule is approved!!!
710    // save2(parentRule, null, false);
711    // //save2(parentRule, null, true);
712    // }
713   
714    // XXX: added when the RuleValidation stuff was added, basically we just need to get the RuleDelegation
715    // that points to our delegate rule, this rule code is scary...
716  0 RuleDelegation ruleDelegation = getRuleDelegation(parentRule, delegateRule);
717   
718  0 save2(delegateRule, ruleDelegation, true);
719   
720    // if the parent rule is new, unsaved, then save it
721    // It's important to save the parent rule after the delegate rule is saved, that way we can ensure that any new rule
722    // delegations have a valid, saved, delegation rule to point to (otherwise we end up with a null constraint violation)
723  0 boolean isRoutingParent = parentRule.getRuleBaseValuesId() == null;
724  0 if (isRoutingParent) {
725    // it's very important that we do not save delegations here (that's what the false parameter is for)
726    // this is because, if we save the delegations, the existing delegations on our parent rule will become
727    // saved as "non current" before the rule is approved!!!
728  0 save2(parentRule, null, false);
729    //save2(parentRule, null, true);
730    }
731   
732  0 WorkflowDocument workflowDocument = null;
733  0 if (routeHeaderId != null) {
734  0 workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), routeHeaderId);
735    } else {
736  0 List rules = new ArrayList();
737  0 rules.add(delegateRule);
738  0 rules.add(parentRule);
739  0 workflowDocument = new WorkflowDocument(new WorkflowIdDTO(principal.getPrincipalId()), getRuleDocmentTypeName(rules));
740    }
741  0 workflowDocument.setTitle(generateTitle(parentRule, delegateRule));
742  0 delegateRule.setRouteHeaderId(workflowDocument.getRouteHeaderId());
743  0 workflowDocument.addAttributeDefinition(new RuleRoutingDefinition(parentRule.getDocTypeName()));
744  0 getRuleDAO().save(delegateRule);
745  0 if (isRoutingParent) {
746  0 parentRule.setRouteHeaderId(workflowDocument.getRouteHeaderId());
747  0 getRuleDAO().save(parentRule);
748    }
749  0 if (blanketApprove) {
750  0 workflowDocument.blanketApprove(annotation);
751    } else {
752  0 workflowDocument.routeDocument(annotation);
753    }
754  0 return workflowDocument.getRouteHeaderId();
755    }
756   
757    /**
758    * Gets the RuleDelegation object from the parentRule that points to the delegateRule.
759    */
 
760  0 toggle private RuleDelegation getRuleDelegation(RuleBaseValues parentRule, RuleBaseValues delegateRule) throws Exception {
761  0 for (Object element : parentRule.getResponsibilities()) {
762  0 RuleResponsibility responsibility = (RuleResponsibility) element;
763  0 for (Object element2 : responsibility.getDelegationRules()) {
764  0 RuleDelegation ruleDelegation = (RuleDelegation) element2;
765    // they should be the same object in memory
766  0 if (ruleDelegation.getDelegationRuleBaseValues().equals(delegateRule)) {
767  0 return ruleDelegation;
768    }
769    }
770    }
771  0 return null;
772    }
773   
 
774  0 toggle private String generateTitle(RuleBaseValues parentRule, RuleBaseValues delegateRule) {
775  0 StringBuffer title = new StringBuffer();
776  0 if (delegateRule.getPreviousVersionId() != null) {
777  0 title.append("Editing Delegation Rule '").append(delegateRule.getDescription()).append("' on '");
778    } else {
779  0 title.append("Adding Delegation Rule '").append(delegateRule.getDescription()).append("' to '");
780    }
781  0 title.append(parentRule.getDescription()).append("'");
782  0 return title.toString();
783    }
784   
 
785  0 toggle public void validate(RuleBaseValues ruleBaseValues, List errors) {
786  0 if (errors == null) {
787  0 errors = new ArrayList();
788    }
789  0 if (getDocumentTypeService().findByName(ruleBaseValues.getDocTypeName()) == null) {
790  0 errors.add(new WorkflowServiceErrorImpl("Document Type Invalid", "doctype.documenttypeservice.doctypename.required"));
791    }
792  0 if (ruleBaseValues.getToDate().before(ruleBaseValues.getFromDate())) {
793  0 errors.add(new WorkflowServiceErrorImpl("From Date is later than to date", "routetemplate.ruleservice.daterange.fromafterto"));
794    }
795  0 if (ruleBaseValues.getActiveInd() == null) {
796  0 errors.add(new WorkflowServiceErrorImpl("Active Indicator is required", "routetemplate.ruleservice.activeind.required"));
797    }
798  0 if (ruleBaseValues.getDescription() == null || ruleBaseValues.getDescription().equals("")) {
799  0 errors.add(new WorkflowServiceErrorImpl("Description is required", "routetemplate.ruleservice.description.required"));
800    }
801  0 if (ruleBaseValues.getForceAction() == null) {
802  0 errors.add(new WorkflowServiceErrorImpl("Force Action is required", "routetemplate.ruleservice.forceAction.required"));
803    }
804  0 if (ruleBaseValues.getResponsibilities().isEmpty()) {
805  0 errors.add(new WorkflowServiceErrorImpl("A responsibility is required", "routetemplate.ruleservice.responsibility.required"));
806    } else {
807  0 for (Object element : ruleBaseValues.getResponsibilities()) {
808  0 RuleResponsibility responsibility = (RuleResponsibility) element;
809  0 if (responsibility.getRuleResponsibilityName() != null && KEWConstants.RULE_RESPONSIBILITY_GROUP_ID.equals(responsibility.getRuleResponsibilityType())) {
810  0 if (getIdentityManagementService().getGroup(responsibility.getRuleResponsibilityName()) == null) {
811  0 errors.add(new WorkflowServiceErrorImpl("Workgroup is invalid", "routetemplate.ruleservice.workgroup.invalid"));
812    }
813  0 } else if (responsibility.getPrincipal() == null && responsibility.getRole() == null) {
814  0 errors.add(new WorkflowServiceErrorImpl("User is invalid", "routetemplate.ruleservice.user.invalid"));
815    }
816    }
817    }
818  0 if (!errors.isEmpty()) {
819  0 throw new WorkflowServiceErrorException("RuleBaseValues validation errors", errors);
820    }
821    }
822   
 
823  0 toggle public void validate2(RuleBaseValues ruleBaseValues, RuleDelegation ruleDelegation, List errors) {
824  0 if (errors == null) {
825  0 errors = new ArrayList();
826    }
827  0 if (getDocumentTypeService().findByName(ruleBaseValues.getDocTypeName()) == null) {
828  0 errors.add(new WorkflowServiceErrorImpl("Document Type Invalid", "doctype.documenttypeservice.doctypename.required"));
829  0 LOG.error("Document Type Invalid");
830    }
831  0 if (ruleBaseValues.getToDate() == null) {
832  0 try {
833  0 ruleBaseValues.setToDate(new Timestamp(RiceConstants.getDefaultDateFormat().parse("01/01/2100").getTime()));
834    } catch (ParseException e) {
835  0 LOG.error("Error date-parsing default date");
836  0 throw new WorkflowServiceErrorException("Error parsing default date.", e);
837    }
838    }
839  0 if (ruleBaseValues.getFromDate() == null) {
840  0 ruleBaseValues.setFromDate(new Timestamp(System.currentTimeMillis()));
841    }
842  0 if (ruleBaseValues.getToDate().before(ruleBaseValues.getFromDate())) {
843  0 errors.add(new WorkflowServiceErrorImpl("From Date is later than to date", "routetemplate.ruleservice.daterange.fromafterto"));
844  0 LOG.error("From Date is later than to date");
845    }
846  0 if (ruleBaseValues.getActiveInd() == null) {
847  0 errors.add(new WorkflowServiceErrorImpl("Active Indicator is required", "routetemplate.ruleservice.activeind.required"));
848  0 LOG.error("Active Indicator is missing");
849    }
850  0 if (ruleBaseValues.getDescription() == null || ruleBaseValues.getDescription().equals("")) {
851  0 errors.add(new WorkflowServiceErrorImpl("Description is required", "routetemplate.ruleservice.description.required"));
852  0 LOG.error("Description is missing");
853    }
854  0 if (ruleBaseValues.getForceAction() == null) {
855  0 errors.add(new WorkflowServiceErrorImpl("Force Action is required", "routetemplate.ruleservice.forceAction.required"));
856  0 LOG.error("Force Action is missing");
857    }
858   
859  0 for (Object element : ruleBaseValues.getResponsibilities()) {
860  0 RuleResponsibility responsibility = (RuleResponsibility) element;
861  0 if (responsibility.getRuleResponsibilityName() != null && KEWConstants.RULE_RESPONSIBILITY_GROUP_ID.equals(responsibility.getRuleResponsibilityType())) {
862  0 if (getIdentityManagementService().getGroup(responsibility.getRuleResponsibilityName()) == null) {
863  0 errors.add(new WorkflowServiceErrorImpl("Workgroup is invalid", "routetemplate.ruleservice.workgroup.invalid"));
864  0 LOG.error("Workgroup is invalid");
865    }
866  0 } else if (responsibility.getPrincipal() == null && responsibility.getRole() == null) {
867  0 errors.add(new WorkflowServiceErrorImpl("User is invalid", "routetemplate.ruleservice.user.invalid"));
868  0 LOG.error("User is invalid");
869  0 } else if (responsibility.isUsingRole()) {
870  0 if (responsibility.getApprovePolicy() == null || !(responsibility.getApprovePolicy().equals(KEWConstants.APPROVE_POLICY_ALL_APPROVE) || responsibility.getApprovePolicy().equals(KEWConstants.APPROVE_POLICY_FIRST_APPROVE))) {
871  0 errors.add(new WorkflowServiceErrorImpl("Approve Policy is Invalid", "routetemplate.ruleservice.approve.policy.invalid"));
872  0 LOG.error("Approve Policy is Invalid");
873    }
874    }
875    }
876   
877  0 if (ruleBaseValues.getRuleTemplate() != null) {
878  0 for (Object element : ruleBaseValues.getRuleTemplate().getActiveRuleTemplateAttributes()) {
879  0 RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) element;
880  0 if (!templateAttribute.isRuleValidationAttribute()) {
881  0 continue;
882    }
883  0 RuleValidationAttribute attribute = templateAttribute.getRuleValidationAttribute();
884  0 UserSession userSession = GlobalVariables.getUserSession();
885  0 try {
886  0 RuleValidationContext validationContext = new RuleValidationContext(ruleBaseValues, ruleDelegation, userSession);
887  0 ValidationResults results = attribute.validate(validationContext);
888  0 if (results != null && !results.getValidationResults().isEmpty()) {
889  0 errors.add(results);
890    }
891    } catch (Exception e) {
892  0 if (e instanceof RuntimeException) {
893  0 throw (RuntimeException)e;
894    }
895  0 throw new RuntimeException("Problem validation rule.", e);
896    }
897   
898    }
899    }
900  0 if (ruleBaseValues.getRuleExpressionDef() != null) {
901    // rule expressions do not require parse-/save-time validation
902    }
903   
904  0 if (!errors.isEmpty()) {
905  0 throw new WorkflowServiceErrorException("RuleBaseValues validation errors", errors);
906    }
907    }
908   
 
909  0 toggle public List findByRouteHeaderId(Long routeHeaderId) {
910  0 return getRuleDAO().findByRouteHeaderId(routeHeaderId);
911    }
912   
 
913  0 toggle public List search(String docTypeName, Long ruleId, Long ruleTemplateId, String ruleDescription, String groupId, String principalId,
914    Boolean delegateRule, Boolean activeInd, Map extensionValues, String workflowIdDirective) {
915  0 return getRuleDAO().search(docTypeName, ruleId, ruleTemplateId, ruleDescription, groupId, principalId, delegateRule,
916    activeInd, extensionValues, workflowIdDirective);
917    }
918   
 
919  0 toggle public List search(String docTypeName, String ruleTemplateName, String ruleDescription, String groupId, String principalId,
920    Boolean workgroupMember, Boolean delegateRule, Boolean activeInd, Map extensionValues, Collection<String> actionRequestCodes) {
921   
922  0 if ( (StringUtils.isEmpty(docTypeName)) &&
923    (StringUtils.isEmpty(ruleTemplateName)) &&
924    (StringUtils.isEmpty(ruleDescription)) &&
925    (StringUtils.isEmpty(groupId)) &&
926    (StringUtils.isEmpty(principalId)) &&
927    (extensionValues.isEmpty()) &&
928    (actionRequestCodes.isEmpty()) ) {
929    // all fields are empty
930  0 throw new IllegalArgumentException("At least one criterion must be sent");
931    }
932   
933  0 RuleTemplate ruleTemplate = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
934  0 Long ruleTemplateId = null;
935  0 if (ruleTemplate != null) {
936  0 ruleTemplateId = ruleTemplate.getRuleTemplateId();
937    }
938   
939  0 if ( ( (extensionValues != null) && (!extensionValues.isEmpty()) ) &&
940    (ruleTemplateId == null) ) {
941    // cannot have extensions without a correct template
942  0 throw new IllegalArgumentException("A Rule Template Name must be given if using Rule Extension values");
943    }
944   
945  0 Collection<String> workgroupIds = new ArrayList<String>();
946  0 if (principalId != null) {
947  0 KEWServiceLocator.getIdentityHelperService().validatePrincipalId(principalId);
948  0 if ( (workgroupMember == null) || (workgroupMember.booleanValue()) ) {
949  0 workgroupIds = getIdentityManagementService().getGroupIdsForPrincipal(principalId);
950    } else {
951    // user was passed but workgroups should not be parsed... do nothing
952    }
953  0 } else if (groupId != null) {
954  0 Group group = KEWServiceLocator.getIdentityHelperService().getGroup(groupId);
955  0 if (group == null) {
956  0 throw new IllegalArgumentException("Group does not exist in for given group id: " + groupId);
957    } else {
958  0 workgroupIds.add(group.getGroupId());
959    }
960    }
961   
962  0 return getRuleDAO().search(docTypeName, ruleTemplateId, ruleDescription, workgroupIds, principalId,
963    delegateRule,activeInd, extensionValues, actionRequestCodes);
964    }
965   
 
966  0 toggle public void delete(Long ruleBaseValuesId) {
967  0 getRuleDAO().delete(ruleBaseValuesId);
968    }
969   
 
970  0 toggle public RuleBaseValues findRuleBaseValuesById(Long ruleBaseValuesId) {
971  0 return getRuleDAO().findRuleBaseValuesById(ruleBaseValuesId);
972    }
973   
 
974  0 toggle public RuleResponsibility findRuleResponsibility(Long responsibilityId) {
975  0 return getRuleDAO().findRuleResponsibility(responsibilityId);
976    }
977   
 
978  0 toggle public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType, boolean ignoreCache) {
979  0 PerformanceLogger performanceLogger = new PerformanceLogger();
980  0 Boolean cachingRules = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KEWConstants.KEW_NAMESPACE, KNSConstants.DetailTypes.RULE_DETAIL_TYPE, USING_RULE_CACHE_IND);
981  0 if (cachingRules.booleanValue()) {
982    //Cache cache = SpringServiceLocator.getCache();
983  0 List<RuleBaseValues> rules = getListFromCache(ruleTemplateName, documentType);
984  0 if (rules != null && !ignoreCache) {
985  0 performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " cached.");
986  0 return rules;
987    }
988  0 RuleTemplate ruleTemplate = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
989  0 if (ruleTemplate == null) {
990  0 return Collections.EMPTY_LIST;
991    }
992  0 Long ruleTemplateId = ruleTemplate.getRuleTemplateId();
993    //RuleListCache translatedRules = new RuleListCache();
994    //translatedRules.setId(getRuleCacheKey(ruleTemplateName, documentType));
995  0 rules = getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType));
996    //translatedRules.addAll(rules);
997  0 putListInCache(ruleTemplateName, documentType, rules);
998    //cache.add(RULE_CACHE_NAME, translatedRules);
999  0 performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " cache refreshed.");
1000  0 return rules;
1001    } else {
1002  0 Long ruleTemplateId = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName).getRuleTemplateId();
1003  0 performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " not caching.");
1004  0 return getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType));
1005    }
1006    }
1007   
 
1008  0 toggle public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType) {
1009  0 return fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateName, documentType, false);
1010    }
1011   
 
1012  0 toggle public List fetchAllCurrentRulesForTemplateDocCombination(String ruleTemplateName, String documentType, Timestamp effectiveDate){
1013  0 Long ruleTemplateId = getRuleTemplateService().findByRuleTemplateName(ruleTemplateName).getRuleTemplateId();
1014  0 PerformanceLogger performanceLogger = new PerformanceLogger();
1015  0 performanceLogger.log("Time to fetchRules by template " + ruleTemplateName + " not caching.");
1016  0 return getRuleDAO().fetchAllCurrentRulesForTemplateDocCombination(ruleTemplateId, getDocGroupAndTypeList(documentType), effectiveDate);
1017    }
 
1018  0 toggle public List fetchAllRules(boolean currentRules) {
1019  0 return getRuleDAO().fetchAllRules(currentRules);
1020    }
1021   
 
1022  0 toggle private List getDocGroupAndTypeList(String documentType) {
1023  0 List docTypeList = new ArrayList();
1024  0 DocumentTypeService docTypeService = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
1025  0 DocumentType docType = docTypeService.findByName(documentType);
1026  0 while (docType != null) {
1027  0 docTypeList.add(docType.getName());
1028  0 docType = docType.getParentDocType();
1029    }
1030  0 return docTypeList;
1031    }
1032   
 
1033  0 toggle private Integer getNextVersionNumber(RuleBaseValues currentRule) {
1034  0 List candidates = new ArrayList();
1035  0 candidates.add(currentRule.getVersionNbr());
1036  0 List pendingRules = ruleDAO.findByPreviousVersionId(currentRule.getRuleBaseValuesId());
1037  0 for (Iterator iterator = pendingRules.iterator(); iterator.hasNext();) {
1038  0 RuleBaseValues pendingRule = (RuleBaseValues) iterator.next();
1039  0 candidates.add(pendingRule.getVersionNbr());
1040    }
1041  0 Collections.sort(candidates);
1042  0 Integer maxVersionNumber = (Integer) candidates.get(candidates.size() - 1);
1043  0 if (maxVersionNumber == null) {
1044  0 return Integer.valueOf(0);
1045    }
1046  0 return Integer.valueOf(maxVersionNumber.intValue() + 1);
1047    }
1048   
1049    /**
1050    * Determines if the given rule is locked for routing.
1051    *
1052    * In the case of a root rule edit, this method will take the rule id of the rule being edited.
1053    *
1054    * In the case of a new delegate rule or a delegate rule edit, this method will take the id of it's parent.
1055    */
 
1056  0 toggle public Long isLockedForRouting(Long currentRuleBaseValuesId) {
1057    // checks for any other versions of the given rule, essentially, if this is a rule edit we want to see how many other
1058    // pending edits are out there
1059  0 List pendingRules = ruleDAO.findByPreviousVersionId(currentRuleBaseValuesId);
1060  0 boolean isDead = true;
1061  0 for (Iterator iterator = pendingRules.iterator(); iterator.hasNext();) {
1062  0 RuleBaseValues pendingRule = (RuleBaseValues) iterator.next();
1063   
1064  0 if (pendingRule.getRouteHeaderId() != null && pendingRule.getRouteHeaderId().longValue() != 0) {
1065  0 DocumentRouteHeaderValue routeHeader = getRouteHeaderService().getRouteHeader(pendingRule.getRouteHeaderId());
1066    // the pending edit is considered dead if it's been disapproved or cancelled and we are allowed to proceed with our own edit
1067  0 isDead = routeHeader.isDisaproved() || routeHeader.isCanceled();
1068  0 if (!isDead) {
1069  0 return pendingRule.getRouteHeaderId();
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.getRouteHeaderId() != null && pendingDelegateRule.getRouteHeaderId().longValue() != 0) {
1080  0 DocumentRouteHeaderValue routeHeader = getRouteHeaderService().getRouteHeader(pendingDelegateRule.getRouteHeaderId());
1081  0 isDead = routeHeader.isDisaproved() || routeHeader.isCanceled();
1082  0 if (!isDead) {
1083  0 return pendingDelegateRule.getRouteHeaderId();
1084    }
1085    }
1086    }
1087    }
1088    }
1089    }
1090  0 return null;
1091    }
1092   
 
1093  0 toggle 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  0 toggle 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    }
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  0 toggle public void setRuleDAO(RuleDAO ruleDAO) {
1165  0 this.ruleDAO = ruleDAO;
1166    }
1167   
 
1168  0 toggle public RuleDAO getRuleDAO() {
1169  0 return ruleDAO;
1170    }
1171   
 
1172  0 toggle public void deleteRuleResponsibilityById(Long ruleResponsibilityId) {
1173  0 getRuleResponsibilityDAO().delete(ruleResponsibilityId);
1174    }
1175   
 
1176  0 toggle public RuleResponsibility findByRuleResponsibilityId(Long ruleResponsibilityId) {
1177  0 return getRuleResponsibilityDAO().findByRuleResponsibilityId(ruleResponsibilityId);
1178    }
1179   
 
1180  0 toggle public List findRuleBaseValuesByResponsibilityReviewer(String reviewerName, String type) {
1181  0 return getRuleDAO().findRuleBaseValuesByResponsibilityReviewer(reviewerName, type);
1182    }
1183   
 
1184  0 toggle public List findRuleBaseValuesByResponsibilityReviewerTemplateDoc(String ruleTemplateName, String documentType, String reviewerName, String type) {
1185  0 return getRuleDAO().findRuleBaseValuesByResponsibilityReviewerTemplateDoc(ruleTemplateName, documentType, reviewerName, type);
1186    }
1187   
 
1188  0 toggle public RuleTemplateService getRuleTemplateService() {
1189  0 return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
1190    }
1191   
 
1192  0 toggle public DocumentTypeService getDocumentTypeService() {
1193  0 return (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
1194    }
1195   
 
1196  0 toggle public IdentityManagementService getIdentityManagementService() {
1197  0 return KIMServiceLocator.getIdentityManagementService();
1198    }
1199   
 
1200  0 toggle public ActionRequestService getActionRequestService() {
1201  0 return (ActionRequestService) KEWServiceLocator.getService(KEWServiceLocator.ACTION_REQUEST_SRV);
1202    }
1203   
 
1204  0 toggle private ResponsibilityIdService getResponsibilityIdService() {
1205  0 return (ResponsibilityIdService) KEWServiceLocator.getService(KEWServiceLocator.RESPONSIBILITY_ID_SERVICE);
1206    }
1207   
 
1208  0 toggle private RuleDelegationService getRuleDelegationService() {
1209  0 return (RuleDelegationService) KEWServiceLocator.getService(KEWServiceLocator.RULE_DELEGATION_SERVICE);
1210    }
1211   
 
1212  0 toggle 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    public class RuleDelegationSorter implements Comparator {
 
1220  0 toggle 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  0 toggle public void loadXml(InputStream inputStream, String principalId) {
1233  0 RuleXmlParser parser = new RuleXmlParser();
1234  0 try {
1235  0 parser.parseRules(inputStream);
1236    } 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    }
1242    }
1243   
 
1244  0 toggle public Element export(ExportDataSet dataSet) {
1245  0 RuleXmlExporter exporter = new RuleXmlExporter(XmlConstants.RULE_NAMESPACE);
1246  0 return exporter.export(dataSet);
1247    }
1248   
 
1249  0 toggle @Override
1250    public boolean supportPrettyPrint() {
1251  0 return true;
1252    }
1253   
 
1254  0 toggle protected List<RuleBaseValues> loadRules(List<Long> ruleIds) {
1255  0 List<RuleBaseValues> rules = new ArrayList<RuleBaseValues>();
1256  0 for (Long ruleId : ruleIds) {
1257  0 RuleBaseValues rule = KEWServiceLocator.getRuleService().findRuleBaseValuesById(ruleId);
1258  0 rules.add(rule);
1259    }
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  0 toggle protected boolean shouldChangeRuleInvolvement(Long 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 Long 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  0 toggle 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    }
1291    }
1292  0 return null;
1293    }
1294   
 
1295  0 toggle 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    }
1312   
 
1313  0 toggle protected RuleBaseValues createNewRuleVersion(RuleBaseValues existingRule, Long 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.setRouteHeaderId(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    }
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    }
1367    }
1368  0 return rule;
1369    }
1370   
 
1371    private static class RuleVersion {
1372    public RuleBaseValues rule;
1373    public RuleBaseValues parent;
1374    public RuleDelegation delegation;
1375    }
1376   
 
1377    private static class RuleRoutingConfig {
1378    private List configs = new ArrayList();
 
1379  0 toggle public static RuleRoutingConfig parse() {
1380  0 RuleRoutingConfig config = new RuleRoutingConfig();
1381  0 String constant = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KEWConstants.KEW_NAMESPACE, KNSConstants.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  0 toggle 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    }
1415  0 return null;
1416    }
1417    }
1418   
 
1419  0 toggle public Long 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    }
1441  0 return null;
1442    }
1443   
 
1444  0 toggle private void generateRuleNameIfNeeded(RuleBaseValues rule) {
1445  0 if (StringUtils.isBlank(rule.getName())) {
1446  0 rule.setName(UUID.randomUUID().toString());
1447    }
1448    }
1449   
 
1450  0 toggle 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    }
1457   
 
1458  0 toggle 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  0 toggle 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  0 toggle 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  0 toggle 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  0 toggle public Long findResponsibilityIdForRule(String ruleName, String ruleResponsibilityName, String ruleResponsibilityType) {
1495  0 return getRuleDAO().findResponsibilityIdForRule(ruleName, ruleResponsibilityName, ruleResponsibilityType);
1496    }
1497   
1498    }