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 }