1 /*
2 * Copyright 2007-2008 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 package org.kuali.rice.kew.rule;
17
18 import java.text.ParseException;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.log4j.Logger;
24 import org.kuali.rice.kew.engine.RouteContext;
25 import org.kuali.rice.kew.exception.WorkflowException;
26
27
28 /**
29 * Expression implementation for "meta rules". A "meta rule" consists of a sequence of
30 * subordinate rule evaluations each processed according to an associated modifier:
31 * <dl>
32 * <dt>next<dt>
33 * <dd>proceed with rule evaluation</dd>
34 * <dt>true</dt>
35 * <dd>if this rule evaluates to true, then return the responsibilities associated with the rule</dd>
36 * <dt>false</dt>
37 * <dd>if this rule evaluates to false, then return the responsibilities associated with the rule</dd>
38 * </dl>
39 * E.g.
40 * <div><tt>bizRule1: next; bizRule2: true; bizRule3: false</tt></div>
41 * @author Kuali Rice Team (rice.collab@kuali.org)
42 */
43 public class MetaRuleExpression extends AccumulatingBSFRuleExpression {
44 private static final Logger LOG = Logger.getLogger(MetaRuleExpression.class);
45
46 @Override
47 public RuleExpressionResult evaluate(Rule rule, RouteContext context) throws WorkflowException {
48 RuleBaseValues ruleDefinition = rule.getDefinition();
49 RuleExpressionDef exprDef = ruleDefinition.getRuleExpressionDef();
50 if (exprDef == null) {
51 throw new WorkflowException("No expression defined in rule definition: " + ruleDefinition);
52 }
53 String expression = exprDef.getExpression();
54 if (StringUtils.isEmpty(expression)) {
55 throw new WorkflowException("Empty expression in rule definition: " + ruleDefinition);
56 }
57
58 String lang = parseLang(ruleDefinition.getRuleExpressionDef().getType(), null);
59 if (lang == null) {
60 // if no language qualifier is specified, parse it as a built-in meta rule expression
61 return evaluateBuiltinExpression(expression, rule, context);
62 } else {
63 return super.evaluate(rule, context);
64 }
65 }
66
67 /**
68 * Evaluates the builtin "meta" rule expression
69 * @param expression the builtin meta rule expression
70 * @param rule the rule
71 * @param context the route context
72 * @return RuleExpressionResult the result
73 * @throws WorkflowException
74 */
75 private RuleExpressionResult evaluateBuiltinExpression(String expression, Rule rule, RouteContext context) throws WorkflowException {
76 try {
77 KRAMetaRuleEngine engine = new KRAMetaRuleEngine(expression);
78
79 int responsibilityPriority = 0; // responsibility priority, lower value means higher priority (due to sort)...increment as we go
80 RuleExpressionResult result = null;
81 boolean success = false;
82 List<RuleResponsibility> responsibilities = new ArrayList<RuleResponsibility>();
83 while (!engine.isDone()) {
84 result = engine.processSingleStatement(context);
85 if (result.isSuccess() && result.getResponsibilities() != null) {
86 // accumulate responsibilities if the evaluation was successful
87 // make sure to reduce priority for each subsequent rule in order for sequential activation to work as desired
88 for (RuleResponsibility responsibility: result.getResponsibilities()) {
89 responsibility.setPriority(Integer.valueOf(responsibilityPriority));
90 responsibilities.add(responsibility);
91 }
92 // decrement responsibilityPriority for next rule expression result responsibilities
93 responsibilityPriority++;
94 success = true;
95 }
96 }
97 result = new RuleExpressionResult(rule, success, responsibilities);
98 LOG.debug("KRAMetaRuleExpression returning result: " + result);
99 return result;
100 } catch (ParseException pe) {
101 throw new WorkflowException("Error parsing expression", pe);
102 }
103 }
104 }