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 }