KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > scripting > bsh > BshScriptUtils


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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
17 package org.springframework.scripting.bsh;
18
19 import java.lang.reflect.InvocationHandler JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.lang.reflect.Proxy JavaDoc;
22
23 import bsh.EvalError;
24 import bsh.Interpreter;
25 import bsh.Primitive;
26 import bsh.XThis;
27
28 import org.springframework.aop.support.AopUtils;
29 import org.springframework.core.NestedRuntimeException;
30 import org.springframework.util.Assert;
31 import org.springframework.util.ClassUtils;
32
33 /**
34  * Utility methods for handling BeanShell-scripted objects.
35  *
36  * @author Rob Harrop
37  * @author Juergen Hoeller
38  * @since 2.0
39  */

40 public abstract class BshScriptUtils {
41
42     /**
43      * Create a new BeanShell-scripted object from the given script source.
44      * <p>With this <code>createBshObject</code> variant, the script needs to
45      * declare a full class or return an actual instance of the scripted object.
46      * @param scriptSource the script source text
47      * @return the scripted Java object
48      * @throws EvalError in case of BeanShell parsing failure
49      */

50     public static Object JavaDoc createBshObject(String JavaDoc scriptSource) throws EvalError {
51         return createBshObject(scriptSource, null, null);
52     }
53
54     /**
55      * Create a new BeanShell-scripted object from the given script source,
56      * using the default ClassLoader.
57      * <p>The script may either be a simple script that needs a corresponding proxy
58      * generated (implementing the specified interfaces), or declare a full class
59      * or return an actual instance of the scripted object (in which case the
60      * specified interfaces, if any, need to be implemented by that class/instance).
61      * @param scriptSource the script source text
62      * @param scriptInterfaces the interfaces that the scripted Java object is
63      * supposed to implement (may be <code>null</code> or empty if the script itself
64      * declares a full class or returns an actual instance of the scripted object)
65      * @return the scripted Java object
66      * @throws EvalError in case of BeanShell parsing failure
67      * @see #createBshObject(String, Class[], ClassLoader)
68      */

69     public static Object JavaDoc createBshObject(String JavaDoc scriptSource, Class JavaDoc[] scriptInterfaces) throws EvalError {
70         return createBshObject(scriptSource, scriptInterfaces, ClassUtils.getDefaultClassLoader());
71     }
72
73     /**
74      * Create a new BeanShell-scripted object from the given script source.
75      * <p>The script may either be a simple script that needs a corresponding proxy
76      * generated (implementing the specified interfaces), or declare a full class
77      * or return an actual instance of the scripted object (in which case the
78      * specified interfaces, if any, need to be implemented by that class/instance).
79      * @param scriptSource the script source text
80      * @param scriptInterfaces the interfaces that the scripted Java object is
81      * supposed to implement (may be <code>null</code> or empty if the script itself
82      * declares a full class or returns an actual instance of the scripted object)
83      * @param classLoader the ClassLoader to create the script proxy with
84      * @return the scripted Java object
85      * @throws EvalError in case of BeanShell parsing failure
86      */

87     public static Object JavaDoc createBshObject(String JavaDoc scriptSource, Class JavaDoc[] scriptInterfaces, ClassLoader JavaDoc classLoader)
88             throws EvalError {
89
90         Object JavaDoc result = evaluateBshScript(scriptSource, scriptInterfaces, classLoader);
91         if (result instanceof Class JavaDoc) {
92             Class JavaDoc clazz = (Class JavaDoc) result;
93             try {
94                 return clazz.newInstance();
95             }
96             catch (Throwable JavaDoc ex) {
97                 throw new IllegalStateException JavaDoc("Could not instantiate script class [" +
98                         clazz.getName() + "]. Root cause is " + ex);
99             }
100         }
101         else {
102             return result;
103         }
104     }
105
106     /**
107      * Evaluate the specified BeanShell script based on the given script source,
108      * returning the Class defined by the script.
109      * <p>The script may either declare a full class or return an actual instance of
110      * the scripted object (in which case the Class of the object will be returned).
111      * In any other case, the returned Class will be <code>null</code>.
112      * @param scriptSource the script source text
113      * @return the scripted Java class, or <code>null</code> if none could be determined
114      * @throws EvalError in case of BeanShell parsing failure
115      */

116     static Class JavaDoc determineBshObjectType(String JavaDoc scriptSource) throws EvalError {
117         Assert.hasText(scriptSource, "Script source must not be empty");
118         Interpreter interpreter = new Interpreter();
119         Object JavaDoc result = interpreter.eval(scriptSource);
120         if (result instanceof Class JavaDoc) {
121             return (Class JavaDoc) result;
122         }
123         else if (result != null) {
124             return result.getClass();
125         }
126         else {
127             return null;
128         }
129     }
130
131     /**
132      * Evaluate the specified BeanShell script based on the given script source,
133      * keeping a returned script Class or script Object as-is.
134      * <p>The script may either be a simple script that needs a corresponding proxy
135      * generated (implementing the specified interfaces), or declare a full class
136      * or return an actual instance of the scripted object (in which case the
137      * specified interfaces, if any, need to be implemented by that class/instance).
138      * @param scriptSource the script source text
139      * @param scriptInterfaces the interfaces that the scripted Java object is
140      * supposed to implement (may be <code>null</code> or empty if the script itself
141      * declares a full class or returns an actual instance of the scripted object)
142      * @param classLoader the ClassLoader to create the script proxy with
143      * @return the scripted Java class or Java object
144      * @throws EvalError in case of BeanShell parsing failure
145      */

146     static Object JavaDoc evaluateBshScript(String JavaDoc scriptSource, Class JavaDoc[] scriptInterfaces, ClassLoader JavaDoc classLoader)
147             throws EvalError {
148
149         Assert.hasText(scriptSource, "Script source must not be empty");
150         Interpreter interpreter = new Interpreter();
151         Object JavaDoc result = interpreter.eval(scriptSource);
152         if (result != null) {
153             return result;
154         }
155         else {
156             // Simple BeanShell script: Let's create a proxy for it, implementing the given interfaces.
157
Assert.notEmpty(scriptInterfaces,
158                     "Given script requires a script proxy: At least one script interface is required.");
159             XThis xt = (XThis) interpreter.eval("return this");
160             return Proxy.newProxyInstance(classLoader, scriptInterfaces, new BshObjectInvocationHandler(xt));
161         }
162     }
163
164
165     /**
166      * InvocationHandler that invokes a BeanShell script method.
167      */

168     private static class BshObjectInvocationHandler implements InvocationHandler JavaDoc {
169
170         private final XThis xt;
171
172         public BshObjectInvocationHandler(XThis xt) {
173             this.xt = xt;
174         }
175
176         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
177             if (AopUtils.isEqualsMethod(method)) {
178                 return (isProxyForSameBshObject(args[0]) ? Boolean.TRUE : Boolean.FALSE);
179             }
180             if (AopUtils.isHashCodeMethod(method)) {
181                 return new Integer JavaDoc(this.xt.hashCode());
182             }
183             if (AopUtils.isToStringMethod(method)) {
184                 return "BeanShell object [" + this.xt + "]";
185             }
186             try {
187                 Object JavaDoc result = this.xt.invokeMethod(method.getName(), args);
188                 if (result == Primitive.NULL || result == Primitive.VOID) {
189                     return null;
190                 }
191                 if (result instanceof Primitive) {
192                     return ((Primitive) result).getValue();
193                 }
194                 return result;
195             }
196             catch (EvalError ex) {
197                 throw new BshExecutionException(ex);
198             }
199         }
200
201         private boolean isProxyForSameBshObject(Object JavaDoc other) {
202             if (!Proxy.isProxyClass(other.getClass())) {
203                 return false;
204             }
205             InvocationHandler JavaDoc ih = Proxy.getInvocationHandler(other);
206             return (ih instanceof BshObjectInvocationHandler &&
207                     this.xt.equals(((BshObjectInvocationHandler) ih).xt));
208         }
209     }
210
211
212     /**
213      * Exception to be thrown on script execution failure.
214      */

215     public static class BshExecutionException extends NestedRuntimeException {
216
217         private BshExecutionException(EvalError ex) {
218             super("BeanShell script execution failed", ex);
219         }
220     }
221
222 }
223
Popular Tags