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