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