001 /** 002 * Copyright 2005-2011 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 org.kuali.rice.core.api.exception.RiceIllegalStateException; 019 import org.kuali.rice.kew.api.KewApiServiceLocator; 020 import org.kuali.rice.kew.api.WorkflowRuntimeException; 021 import org.kuali.rice.kew.api.exception.WorkflowException; 022 import org.kuali.rice.kew.engine.RouteContext; 023 024 import javax.script.ScriptEngine; 025 import javax.script.ScriptEngineManager; 026 import javax.script.ScriptException; 027 028 /** 029 * A rule expression implementation that uses Bean Scripting Framework. 030 * The language is given by the type qualifier, e.g.: 031 * <expression type="BSF:groovy">... 032 * 033 * @author Kuali Rice Team (rice.collab@kuali.org) 034 */ 035 //TODO: this should really be renamed since it is no longer using apache BSF 036 public class BSFRuleExpression implements RuleExpression { 037 public RuleExpressionResult evaluate(Rule rule, RouteContext context) { 038 org.kuali.rice.kew.api.rule.RuleContract ruleDefinition = rule.getDefinition(); 039 String type = ruleDefinition.getRuleExpressionDef().getType(); 040 String lang = parseLang(type, "groovy"); 041 String expression = ruleDefinition.getRuleExpressionDef().getExpression(); 042 RuleExpressionResult result; 043 ScriptEngineManager factory = new ScriptEngineManager(); 044 ScriptEngine engine = factory.getEngineByName(lang); 045 try { 046 declareBeans(engine, rule, context); 047 result = (RuleExpressionResult) engine.eval(expression); 048 } catch (ScriptException e) { 049 throw new RiceIllegalStateException("Error evaluating " + type + " expression: '" + expression + "'", e); 050 } 051 if (result == null) { 052 return new RuleExpressionResult(rule, false); 053 } else { 054 return result; 055 } 056 } 057 058 /** 059 * Parses the language component from the type string 060 * @param type the type string 061 * @param deflt the default language if none is present in the type string 062 * @return the language component or null 063 */ 064 protected String parseLang(String type, String deflt) { 065 int colon = type.indexOf(':'); 066 if (colon > -1) { 067 return type.substring(colon + 1); 068 } else { 069 return deflt; 070 } 071 } 072 073 /** 074 * Populates the BSFManager with beans that are accessible to BSF scripts. May be overridden by 075 * subclasses. The standard implementation exposes the rule and routeContext 076 * @param manager the BSFManager 077 * @param rule the current Rule object 078 * @param context the current RouteContext 079 */ 080 protected void declareBeans(ScriptEngine engine, Rule rule, RouteContext context) throws ScriptException { 081 engine.put("rule", rule); 082 engine.put("routeContext", context); 083 engine.put("workflow", new WorkflowRuleAPI(context)); 084 } 085 086 /** 087 * A helper bean that is declared for use by BSF scripts. 088 * This functionality should really be part of a single internal API that can be exposed 089 * to various pieces of code that are plugged into KEW. For comparison EDocLite also 090 * has its own such API that it exposes. 091 */ 092 protected static final class WorkflowRuleAPI { 093 private final RouteContext context; 094 WorkflowRuleAPI(RouteContext context) { 095 this.context = context; 096 } 097 /** 098 * Evaluates a named rule 099 * @param name the rule name 100 * @return the RuleExpressionResult 101 * @throws WorkflowException 102 */ 103 public RuleExpressionResult invokeRule(String name) throws WorkflowException { 104 org.kuali.rice.kew.api.rule.Rule rbv = KewApiServiceLocator.getRuleService().getRuleByName(name); 105 if (rbv == null) throw new WorkflowRuntimeException("Could not find rule named \"" + name + "\""); 106 Rule r = new RuleImpl(rbv); 107 return r.evaluate(r, context); 108 } 109 } 110 }