001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kew.rule; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020import org.kuali.rice.core.api.exception.RiceIllegalStateException; 021import org.kuali.rice.kew.api.rule.RuleExpressionContract; 022import org.kuali.rice.kew.engine.RouteContext; 023import org.kuali.rice.kew.api.exception.WorkflowException; 024 025import java.text.ParseException; 026import java.util.ArrayList; 027import java.util.List; 028 029 030/** 031 * Expression implementation for "meta rules". A "meta rule" consists of a sequence of 032 * subordinate rule evaluations each processed according to an associated modifier: 033 * <dl> 034 * <dt>next<dt> 035 * <dd>proceed with rule evaluation</dd> 036 * <dt>true</dt> 037 * <dd>if this rule evaluates to true, then return the responsibilities associated with the rule</dd> 038 * <dt>false</dt> 039 * <dd>if this rule evaluates to false, then return the responsibilities associated with the rule</dd> 040 * </dl> 041 * E.g. 042 * <div><tt>bizRule1: next; bizRule2: true; bizRule3: false</tt></div> 043 * @author Kuali Rice Team (rice.collab@kuali.org) 044 */ 045public class MetaRuleExpression extends AccumulatingBSFRuleExpression { 046 private static final Logger LOG = Logger.getLogger(MetaRuleExpression.class); 047 048 @Override 049 public RuleExpressionResult evaluate(Rule rule, RouteContext context) { 050 org.kuali.rice.kew.api.rule.RuleContract ruleDefinition = rule.getDefinition(); 051 RuleExpressionContract exprDef = ruleDefinition.getRuleExpressionDef(); 052 if (exprDef == null) { 053 throw new RiceIllegalStateException("No expression defined in rule definition: " + ruleDefinition); 054 } 055 String expression = exprDef.getExpression(); 056 if (StringUtils.isEmpty(expression)) { 057 throw new RiceIllegalStateException("Empty expression in rule definition: " + ruleDefinition); 058 } 059 060 String lang = parseLang(ruleDefinition.getRuleExpressionDef().getType(), null); 061 if (lang == null) { 062 // if no language qualifier is specified, parse it as a built-in meta rule expression 063 return evaluateBuiltinExpression(expression, rule, context); 064 } else { 065 return super.evaluate(rule, context); 066 } 067 } 068 069 /** 070 * Evaluates the builtin "meta" rule expression 071 * @param expression the builtin meta rule expression 072 * @param rule the rule 073 * @param context the route context 074 * @return RuleExpressionResult the result 075 * @throws WorkflowException 076 */ 077 private RuleExpressionResult evaluateBuiltinExpression(String expression, Rule rule, RouteContext context) { 078 try { 079 KRAMetaRuleEngine engine = new KRAMetaRuleEngine(expression); 080 081 int responsibilityPriority = 0; // responsibility priority, lower value means higher priority (due to sort)...increment as we go 082 RuleExpressionResult result = null; 083 boolean success = false; 084 List<org.kuali.rice.kew.api.rule.RuleResponsibility> responsibilities = new ArrayList<org.kuali.rice.kew.api.rule.RuleResponsibility>(); 085 while (!engine.isDone()) { 086 result = engine.processSingleStatement(context); 087 if (result.isSuccess() && result.getResponsibilities() != null) { 088 // accumulate responsibilities if the evaluation was successful 089 // make sure to reduce priority for each subsequent rule in order for sequential activation to work as desired 090 for (org.kuali.rice.kew.api.rule.RuleResponsibility responsibility: result.getResponsibilities()) { 091 org.kuali.rice.kew.api.rule.RuleResponsibility.Builder builder = 092 org.kuali.rice.kew.api.rule.RuleResponsibility.Builder.create(responsibility); 093 builder.setPriority(Integer.valueOf(responsibilityPriority)); 094 responsibilities.add(builder.build()); 095 } 096 // decrement responsibilityPriority for next rule expression result responsibilities 097 responsibilityPriority++; 098 success = true; 099 } 100 } 101 result = new RuleExpressionResult(rule, success, responsibilities); 102 LOG.debug("MetaRuleExpression returning result: " + result); 103 return result; 104 } catch (ParseException pe) { 105 throw new RiceIllegalStateException("Error parsing expression", pe); 106 } 107 } 108}