1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.bsf;
47
48 import groovy.lang.Closure;
49 import groovy.lang.GroovyShell;
50 import org.apache.bsf.BSFDeclaredBean;
51 import org.apache.bsf.BSFException;
52 import org.apache.bsf.BSFManager;
53 import org.apache.bsf.util.BSFEngineImpl;
54 import org.apache.bsf.util.BSFFunctions;
55 import org.codehaus.groovy.runtime.InvokerHelper;
56
57 import java.util.Vector;
58
59 /***
60 * A BSF Engine for the <a href="http://groovy.codehaus.org/">Groovy</a>
61 * scripting language.
62 * <p/>
63 * It's derived from the Jython / JPython engine
64 *
65 * @author James Strachan
66 */
67 public class GroovyEngine extends BSFEngineImpl {
68 private static final String[] EMPTY_ARGS = {
69 };
70
71 protected GroovyShell shell;
72
73 /***
74 * Convert a non java class name to a java classname
75 * This is used to convert a script name to a name
76 * that can be used as a classname with the script is
77 * loaded in GroovyClassloader#load()
78 * The method simply replaces any invalid characters
79 * with "_".
80 */
81 private String convertToValidJavaClassname(String inName) {
82 if (inName == null || inName.equals("")) {
83 return "_";
84 }
85 StringBuffer output = new StringBuffer(inName.length());
86 boolean firstChar = true;
87 for (int i = 0; i < inName.length(); ++i) {
88 char ch = inName.charAt(i);
89 if (firstChar && !Character.isJavaIdentifierStart(ch)) {
90 ch = '_';
91 } else if (!firstChar
92 && !(Character.isJavaIdentifierPart(ch) || ch == '.')) {
93 ch = '_';
94 }
95 firstChar = (ch == '.');
96 output.append(ch);
97 }
98 return output.toString();
99 }
100
101 /***
102 * Allow an anonymous function to be declared and invoked
103 */
104 public Object apply(java.lang.String source,
105 int lineNo,
106 int columnNo,
107 Object funcBody,
108 Vector paramNames,
109 Vector arguments)
110 throws BSFException {
111
112 Object object = eval(source, lineNo, columnNo, funcBody);
113 if (object instanceof Closure) {
114
115
116 /*** @todo we could turn the 2 vectors into a Map */
117 Closure closure = (Closure) object;
118 return closure.call(arguments.toArray());
119 }
120 return object;
121 }
122
123 /***
124 * Call the named method of the given object.
125 */
126 public Object call(Object object, String method, Object[] args) throws BSFException {
127 return InvokerHelper.invokeMethod(object, method, args);
128 }
129
130 /***
131 * Declare a bean
132 */
133 public void declareBean(BSFDeclaredBean bean) throws BSFException {
134
135 shell.setVariable(bean.name, bean.bean);
136 }
137
138 /***
139 * Evaluate an expression.
140 */
141 public Object eval(String source, int lineNo, int columnNo, Object script) throws BSFException {
142 try {
143 source = convertToValidJavaClassname(source);
144 Object result = getEvalShell().evaluate(script.toString(), source);
145 return result;
146 } catch (Exception e) {
147 throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
148 }
149 }
150
151 /***
152 * Execute a script.
153 */
154 public void exec(String source, int lineNo, int columnNo, Object script) throws BSFException {
155 try {
156
157 source = convertToValidJavaClassname(source);
158 getEvalShell().evaluate(script.toString(), source);
159
160 } catch (Exception e) {
161 throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
162 }
163 }
164
165 /***
166 * Initialize the engine.
167 */
168 public void initialize(BSFManager mgr, String lang, Vector declaredBeans) throws BSFException {
169 super.initialize(mgr, lang, declaredBeans);
170
171
172 shell = new GroovyShell(mgr.getClassLoader());
173
174
175 shell.setVariable("bsf", new BSFFunctions(mgr, this));
176
177 int size = declaredBeans.size();
178 for (int i = 0; i < size; i++) {
179 declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
180 }
181 }
182
183 /***
184 * Undeclare a previously declared bean.
185 */
186 public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
187 shell.setVariable(bean.name, null);
188 }
189
190 /***
191 * @return a newly created GroovyShell using the same variable scope but a new class loader
192 */
193 protected GroovyShell getEvalShell() {
194 return new GroovyShell(shell);
195 }
196 }