View Javadoc

1   /**
2    * Copyright 2005-2012 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.core.api.exception.RiceIllegalStateException;
19  import org.kuali.rice.kew.api.KewApiServiceLocator;
20  import org.kuali.rice.kew.api.WorkflowRuntimeException;
21  import org.kuali.rice.kew.api.exception.WorkflowException;
22  import org.kuali.rice.kew.engine.RouteContext;
23  
24  import javax.script.ScriptEngine;
25  import javax.script.ScriptEngineManager;
26  import javax.script.ScriptException;
27  
28  /**
29   * A rule expression implementation that uses Bean Scripting Framework.
30   * The language is given by the type qualifier, e.g.:
31   * <expression type="BSF:groovy">...
32   *
33   * @author Kuali Rice Team (rice.collab@kuali.org)
34   */
35  //TODO: this should really be renamed since it is no longer using apache BSF
36  public class BSFRuleExpression implements RuleExpression {
37      public RuleExpressionResult evaluate(Rule rule, RouteContext context) {
38          org.kuali.rice.kew.api.rule.RuleContract ruleDefinition = rule.getDefinition();
39          String type = ruleDefinition.getRuleExpressionDef().getType();
40          String lang = parseLang(type, "groovy");
41          String expression = ruleDefinition.getRuleExpressionDef().getExpression();
42          RuleExpressionResult result;
43          ScriptEngineManager factory = new ScriptEngineManager();
44          ScriptEngine engine = factory.getEngineByName(lang);
45          try {
46              declareBeans(engine, rule, context);
47              result = (RuleExpressionResult) engine.eval(expression);
48          } catch (ScriptException e) {
49              throw new RiceIllegalStateException("Error evaluating " + type + " expression: '" + expression + "'", e);
50          }
51          if (result == null) {
52              return new RuleExpressionResult(rule, false);
53          } else {
54              return result;
55          }
56      }
57  
58      /**
59       * Parses the language component from the type string
60       * @param type the type string
61       * @param deflt the default language if none is present in the type string
62       * @return the language component or null
63       */
64      protected String parseLang(String type, String deflt) {
65          int colon = type.indexOf(':');
66          if (colon > -1) {
67              return type.substring(colon + 1);
68          } else {
69              return deflt;
70          }
71      }
72  
73      /**
74       * Populates the BSFManager with beans that are accessible to BSF scripts.  May be overridden by
75       * subclasses.  The standard implementation exposes the rule and routeContext
76       * @param manager the BSFManager
77       * @param rule the current Rule object
78       * @param context the current RouteContext
79       */
80      protected void declareBeans(ScriptEngine engine, Rule rule, RouteContext context) throws ScriptException {
81          engine.put("rule", rule);
82          engine.put("routeContext", context);
83          engine.put("workflow", new WorkflowRuleAPI(context));
84      }
85  
86      /**
87       * A helper bean that is declared for use by BSF scripts.
88       * This functionality should really be part of a single internal API that can be exposed
89       * to various pieces of code that are plugged into KEW.  For comparison EDocLite also
90       * has its own such API that it exposes. 
91       */
92      protected static final class WorkflowRuleAPI {
93          private final RouteContext context;
94          WorkflowRuleAPI(RouteContext context) {
95              this.context = context;
96          }
97          /**
98           * Evaluates a named rule
99           * @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 }