View Javadoc

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 }