001 /*
002 * Copyright 2007-2008 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.rule;
017
018 import java.text.ParseException;
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.apache.log4j.Logger;
024 import org.kuali.rice.kew.engine.RouteContext;
025 import org.kuali.rice.kew.exception.WorkflowException;
026
027
028 /**
029 * Expression implementation for "meta rules". A "meta rule" consists of a sequence of
030 * subordinate rule evaluations each processed according to an associated modifier:
031 * <dl>
032 * <dt>next<dt>
033 * <dd>proceed with rule evaluation</dd>
034 * <dt>true</dt>
035 * <dd>if this rule evaluates to true, then return the responsibilities associated with the rule</dd>
036 * <dt>false</dt>
037 * <dd>if this rule evaluates to false, then return the responsibilities associated with the rule</dd>
038 * </dl>
039 * E.g.
040 * <div><tt>bizRule1: next; bizRule2: true; bizRule3: false</tt></div>
041 * @author Kuali Rice Team (rice.collab@kuali.org)
042 */
043 public class MetaRuleExpression extends AccumulatingBSFRuleExpression {
044 private static final Logger LOG = Logger.getLogger(MetaRuleExpression.class);
045
046 @Override
047 public RuleExpressionResult evaluate(Rule rule, RouteContext context) throws WorkflowException {
048 RuleBaseValues ruleDefinition = rule.getDefinition();
049 RuleExpressionDef exprDef = ruleDefinition.getRuleExpressionDef();
050 if (exprDef == null) {
051 throw new WorkflowException("No expression defined in rule definition: " + ruleDefinition);
052 }
053 String expression = exprDef.getExpression();
054 if (StringUtils.isEmpty(expression)) {
055 throw new WorkflowException("Empty expression in rule definition: " + ruleDefinition);
056 }
057
058 String lang = parseLang(ruleDefinition.getRuleExpressionDef().getType(), null);
059 if (lang == null) {
060 // if no language qualifier is specified, parse it as a built-in meta rule expression
061 return evaluateBuiltinExpression(expression, rule, context);
062 } else {
063 return super.evaluate(rule, context);
064 }
065 }
066
067 /**
068 * Evaluates the builtin "meta" rule expression
069 * @param expression the builtin meta rule expression
070 * @param rule the rule
071 * @param context the route context
072 * @return RuleExpressionResult the result
073 * @throws WorkflowException
074 */
075 private RuleExpressionResult evaluateBuiltinExpression(String expression, Rule rule, RouteContext context) throws WorkflowException {
076 try {
077 KRAMetaRuleEngine engine = new KRAMetaRuleEngine(expression);
078
079 int responsibilityPriority = 0; // responsibility priority, lower value means higher priority (due to sort)...increment as we go
080 RuleExpressionResult result = null;
081 boolean success = false;
082 List<RuleResponsibility> responsibilities = new ArrayList<RuleResponsibility>();
083 while (!engine.isDone()) {
084 result = engine.processSingleStatement(context);
085 if (result.isSuccess() && result.getResponsibilities() != null) {
086 // accumulate responsibilities if the evaluation was successful
087 // make sure to reduce priority for each subsequent rule in order for sequential activation to work as desired
088 for (RuleResponsibility responsibility: result.getResponsibilities()) {
089 responsibility.setPriority(Integer.valueOf(responsibilityPriority));
090 responsibilities.add(responsibility);
091 }
092 // decrement responsibilityPriority for next rule expression result responsibilities
093 responsibilityPriority++;
094 success = true;
095 }
096 }
097 result = new RuleExpressionResult(rule, success, responsibilities);
098 LOG.debug("KRAMetaRuleExpression returning result: " + result);
099 return result;
100 } catch (ParseException pe) {
101 throw new WorkflowException("Error parsing expression", pe);
102 }
103 }
104 }