1 16 17 package org.springframework.scripting.bsh; 18 19 import java.lang.reflect.InvocationHandler ; 20 import java.lang.reflect.Method ; 21 import java.lang.reflect.Proxy ; 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 40 public abstract class BshScriptUtils { 41 42 50 public static Object createBshObject(String scriptSource) throws EvalError { 51 return createBshObject(scriptSource, null, null); 52 } 53 54 69 public static Object createBshObject(String scriptSource, Class [] scriptInterfaces) throws EvalError { 70 return createBshObject(scriptSource, scriptInterfaces, ClassUtils.getDefaultClassLoader()); 71 } 72 73 87 public static Object createBshObject(String scriptSource, Class [] scriptInterfaces, ClassLoader classLoader) 88 throws EvalError { 89 90 Object result = evaluateBshScript(scriptSource, scriptInterfaces, classLoader); 91 if (result instanceof Class ) { 92 Class clazz = (Class ) result; 93 try { 94 return clazz.newInstance(); 95 } 96 catch (Throwable ex) { 97 throw new IllegalStateException ("Could not instantiate script class [" + 98 clazz.getName() + "]. Root cause is " + ex); 99 } 100 } 101 else { 102 return result; 103 } 104 } 105 106 116 static Class determineBshObjectType(String scriptSource) throws EvalError { 117 Assert.hasText(scriptSource, "Script source must not be empty"); 118 Interpreter interpreter = new Interpreter(); 119 Object result = interpreter.eval(scriptSource); 120 if (result instanceof Class ) { 121 return (Class ) result; 122 } 123 else if (result != null) { 124 return result.getClass(); 125 } 126 else { 127 return null; 128 } 129 } 130 131 146 static Object evaluateBshScript(String scriptSource, Class [] scriptInterfaces, ClassLoader classLoader) 147 throws EvalError { 148 149 Assert.hasText(scriptSource, "Script source must not be empty"); 150 Interpreter interpreter = new Interpreter(); 151 Object result = interpreter.eval(scriptSource); 152 if (result != null) { 153 return result; 154 } 155 else { 156 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 168 private static class BshObjectInvocationHandler implements InvocationHandler { 169 170 private final XThis xt; 171 172 public BshObjectInvocationHandler(XThis xt) { 173 this.xt = xt; 174 } 175 176 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 177 if (AopUtils.isEqualsMethod(method)) { 178 return (isProxyForSameBshObject(args[0]) ? Boolean.TRUE : Boolean.FALSE); 179 } 180 if (AopUtils.isHashCodeMethod(method)) { 181 return new Integer (this.xt.hashCode()); 182 } 183 if (AopUtils.isToStringMethod(method)) { 184 return "BeanShell object [" + this.xt + "]"; 185 } 186 try { 187 Object 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 other) { 202 if (!Proxy.isProxyClass(other.getClass())) { 203 return false; 204 } 205 InvocationHandler ih = Proxy.getInvocationHandler(other); 206 return (ih instanceof BshObjectInvocationHandler && 207 this.xt.equals(((BshObjectInvocationHandler) ih).xt)); 208 } 209 } 210 211 212 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 |