1 /*
2 * Copyright 2007 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.kuali.rice.kew.rule;
17
18 import org.kuali.rice.kew.api.WorkflowRuntimeException;
19 import org.kuali.rice.kew.engine.RouteContext;
20 import org.kuali.rice.kew.exception.WorkflowException;
21 import org.kuali.rice.kew.service.KEWServiceLocator;
22
23 import javax.script.ScriptEngine;
24 import javax.script.ScriptEngineManager;
25 import javax.script.ScriptException;
26
27 /**
28 * A rule expression implementation that uses Bean Scripting Framework.
29 * The language is given by the type qualifier, e.g.:
30 * <expression type="BSF:groovy">...
31 *
32 * @author Kuali Rice Team (rice.collab@kuali.org)
33 */
34 //TODO: this should really be renamed since it is no longer using apache BSF
35 public class BSFRuleExpression implements RuleExpression {
36 public RuleExpressionResult evaluate(Rule rule, RouteContext context) throws WorkflowException {
37 RuleBaseValues ruleDefinition = rule.getDefinition();
38 String type = ruleDefinition.getRuleExpressionDef().getType();
39 String lang = parseLang(type, "groovy");
40 String expression = ruleDefinition.getRuleExpressionDef().getExpression();
41 RuleExpressionResult result;
42 ScriptEngineManager factory = new ScriptEngineManager();
43 ScriptEngine engine = factory.getEngineByName(lang);
44 try {
45 declareBeans(engine, rule, context);
46 result = (RuleExpressionResult) engine.eval(expression);
47 } catch (ScriptException e) {
48 throw new WorkflowException("Error evaluating " + type + " expression: '" + expression + "'", e);
49 }
50 if (result == null) {
51 return new RuleExpressionResult(rule, false);
52 } else {
53 return result;
54 }
55 }
56
57 /**
58 * Parses the language component from the type string
59 * @param type the type string
60 * @param deflt the default language if none is present in the type string
61 * @return the language component or null
62 */
63 protected String parseLang(String type, String deflt) {
64 int colon = type.indexOf(':');
65 if (colon > -1) {
66 return type.substring(colon + 1);
67 } else {
68 return deflt;
69 }
70 }
71
72 /**
73 * Populates the BSFManager with beans that are accessible to BSF scripts. May be overridden by
74 * subclasses. The standard implementation exposes the rule and routeContext
75 * @param manager the BSFManager
76 * @param rule the current Rule object
77 * @param context the current RouteContext
78 */
79 protected void declareBeans(ScriptEngine engine, Rule rule, RouteContext context) throws ScriptException {
80 engine.put("rule", rule);
81 engine.put("routeContext", context);
82 engine.put("workflow", new WorkflowRuleAPI(context));
83 }
84
85 /**
86 * A helper bean that is declared for use by BSF scripts.
87 * This functionality should really be part of a single internal API that can be exposed
88 * to various pieces of code that are plugged into KEW. For comparison EDocLite also
89 * has its own such API that it exposes.
90 */
91 protected static final class WorkflowRuleAPI {
92 private final RouteContext context;
93 WorkflowRuleAPI(RouteContext context) {
94 this.context = context;
95 }
96 /**
97 * Evaluates a named rule
98 * @param name the rule name
99 * @return the RuleExpressionResult
100 * @throws WorkflowException
101 */
102 public RuleExpressionResult invokeRule(String name) throws WorkflowException {
103 RuleBaseValues rbv = KEWServiceLocator.getRuleService().getRuleByName(name);
104 if (rbv == null) throw new WorkflowRuntimeException("Could not find rule named \"" + name + "\"");
105 Rule r = new RuleImpl(rbv);
106 return r.evaluate(r, context);
107 }
108 }
109 }