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