001: /*
002: * $Id: OfbizBshBsfEngine.java,v 1.4 2003/09/18 16:01:21 jonesde Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.base.util;
025:
026: /*
027: This file is associated with the BeanShell Java Scripting language
028: distribution (http://www.beanshell.org/).
029:
030: This file is hereby placed into the public domain... You may copy,
031: modify, and redistribute it without restriction.
032:
033: */
034:
035: import java.io.StringReader;
036: import java.util.HashMap;
037: import java.util.Map;
038: import java.util.Vector;
039:
040: import bsh.BshClassManager;
041: import bsh.EvalError;
042: import bsh.Interpreter;
043: import bsh.InterpreterError;
044: import bsh.NameSpace;
045: import bsh.TargetError;
046:
047: import com.ibm.bsf.BSFDeclaredBean;
048: import com.ibm.bsf.BSFException;
049: import com.ibm.bsf.BSFManager;
050: import com.ibm.bsf.util.BSFEngineImpl;
051:
052: /**
053: * This is the BeanShell adapter for IBM's Bean Scripting Famework.
054: * It is an implementation of the BSFEngine class, allowing BSF aware
055: * applications to use BeanShell as a scripting language.
056: * <p>
057: *
058: * I believe this implementation is complete (with some hesitation about the
059: * the usefullness of the compileXXX() style methods - provided by the base
060: * utility class).
061: *
062: * @author Pat Niemeyer
063: * @author David E. Jones
064: */
065: public class OfbizBshBsfEngine extends BSFEngineImpl {
066:
067: public static final String module = OfbizBshBsfEngine.class
068: .getName();
069:
070: protected static Map masterClassManagers = new HashMap();
071: protected Interpreter interpreter;
072: protected boolean installedApplyMethod;
073:
074: public static UtilCache parsedScripts = new UtilCache(
075: "script.BshBsfParsedCache", 0, 0, false);
076:
077: public void initialize(BSFManager mgr, String lang,
078: Vector declaredBeans) throws BSFException {
079: super .initialize(mgr, lang, declaredBeans);
080:
081: ClassLoader classLoader = Thread.currentThread()
082: .getContextClassLoader();
083:
084: //find the "master" BshClassManager for this classpath
085: BshClassManager master = (BshClassManager) masterClassManagers
086: .get(classLoader);
087: if (master == null) {
088: synchronized (OfbizBshBsfEngine.class) {
089: master = (BshClassManager) masterClassManagers
090: .get(classLoader);
091: if (master == null) {
092: master = BshClassManager.createClassManager();
093: master.setClassLoader(classLoader);
094: masterClassManagers.put(classLoader, master);
095: }
096: }
097: }
098:
099: if (master != null) {
100: interpreter = new Interpreter(new StringReader(""),
101: System.out, System.err, false, new NameSpace(
102: master, "global"), null, null);
103: } else {
104: interpreter = new Interpreter();
105: interpreter.setClassLoader(classLoader);
106: }
107:
108: // declare the bsf manager for callbacks, etc.
109: try {
110: interpreter.set("bsf", mgr);
111: } catch (EvalError e) {
112: throw new BSFException("bsh internal error: "
113: + e.toString());
114: }
115:
116: for (int i = 0; i < declaredBeans.size(); i++) {
117: BSFDeclaredBean bean = (BSFDeclaredBean) declaredBeans
118: .get(i);
119: declareBean(bean);
120: }
121: }
122:
123: public void setDebug(boolean debug) {
124: Interpreter.DEBUG = debug;
125: }
126:
127: /**
128: * Invoke method name on the specified bsh scripted object.
129: * The object may be null to indicate the global namespace of the
130: * interpreter.
131: * @param object may be null for the global namespace.
132: */
133: public Object call(Object object, String name, Object[] args)
134: throws BSFException {
135: if (object == null) {
136: try {
137: object = interpreter.get("global");
138: } catch (EvalError e) {
139: throw new BSFException("bsh internal error: "
140: + e.toString());
141: }
142: }
143:
144: if (object instanceof bsh.This) {
145: try {
146: return ((bsh.This) object).invokeMethod(name, args);
147: } catch (InterpreterError e) {
148: throw new BSFException(
149: "BeanShell interpreter internal error: " + e);
150: } catch (TargetError e2) {
151: throw new BSFException(
152: "The application script threw an exception: "
153: + e2.getTarget());
154: } catch (EvalError e3) {
155: throw new BSFException("BeanShell script error: " + e3);
156: }
157: } else {
158: throw new BSFException("Cannot invoke method: " + name
159: + ". Object: " + object
160: + " is not a BeanShell scripted object.");
161: }
162: }
163:
164: /**
165: * A helper BeanShell method that implements the anonymous method apply
166: * proposed by BSF. Note that the script below could use the standard
167: * bsh eval() method to set the variables and apply the text, however
168: * then I'd have to escape quotes, etc.
169: */
170: final static String bsfApplyMethod = "_bsfApply(_bsfNames, _bsfArgs, _bsfText) {"
171: + "for(i=0;i<_bsfNames.length;i++)"
172: + "this.namespace.setVariable(_bsfNames[i], _bsfArgs[i]);"
173: + "return this.interpreter.eval(_bsfText, this.namespace);"
174: + "}";
175:
176: /**
177: * This is an implementation of the BSF apply() method.
178: * It exectutes the funcBody text in an "anonymous" method call with
179: * arguments.
180: */
181: public Object apply(String source, int lineNo, int columnNo,
182: Object funcBody, Vector namesVec, Vector argsVec)
183: throws BSFException {
184: if (namesVec.size() != argsVec.size())
185: throw new BSFException("number of params/names mismatch");
186: if (!(funcBody instanceof String))
187: throw new BSFException(
188: "apply: function body must be a string");
189:
190: String[] names = new String[namesVec.size()];
191: namesVec.copyInto(names);
192: Object[] args = new String[argsVec.size()];
193: argsVec.copyInto(args);
194:
195: try {
196: if (!installedApplyMethod) {
197: interpreter.eval(bsfApplyMethod);
198: installedApplyMethod = true;
199: }
200:
201: bsh.This global = (bsh.This) interpreter.get("global");
202: return global.invokeMethod("_bsfApply", new Object[] {
203: names, args, (String) funcBody });
204:
205: } catch (InterpreterError e) {
206: throw new BSFException(
207: "BeanShell interpreter internal error: " + e
208: + sourceInfo(source, lineNo, columnNo));
209: } catch (TargetError e2) {
210: throw new BSFException(
211: "The application script threw an exception: "
212: + e2.getTarget()
213: + sourceInfo(source, lineNo, columnNo));
214: } catch (EvalError e3) {
215: throw new BSFException("BeanShell script error: " + e3
216: + sourceInfo(source, lineNo, columnNo));
217: }
218: }
219:
220: public Object eval(String source, int lineNo, int columnNo,
221: Object expr) throws BSFException {
222: if (!(expr instanceof String))
223: throw new BSFException(
224: "BeanShell expression must be a string");
225:
226: try {
227: //return interpreter.eval(((String) expr));
228:
229: Interpreter.ParsedScript script = null;
230:
231: if (source != null && source.length() > 0) {
232: script = (Interpreter.ParsedScript) parsedScripts
233: .get(source);
234: if (script == null) {
235: synchronized (OfbizBshBsfEngine.class) {
236: script = (Interpreter.ParsedScript) parsedScripts
237: .get(source);
238: if (script == null) {
239: script = interpreter.parseScript(source,
240: new StringReader((String) expr));
241: Debug.logVerbose("Caching BSH script at: "
242: + source, module);
243: parsedScripts.put(source, script);
244: }
245: }
246: }
247: } else {
248: script = interpreter.parseScript(source,
249: new StringReader((String) expr));
250: }
251:
252: return interpreter.evalParsedScript(script);
253: } catch (InterpreterError e) {
254: throw new BSFException(
255: "BeanShell interpreter internal error: " + e
256: + sourceInfo(source, lineNo, columnNo));
257: } catch (TargetError e2) {
258: Debug.logError(e2,
259: "Error thrown in BeanShell script called through BSF at: "
260: + sourceInfo(source, lineNo, columnNo),
261: module);
262: //Debug.logError(e2.getTarget(), module);
263: throw new BSFException(
264: "The application script threw an exception: " + e2
265: + " "
266: + sourceInfo(source, lineNo, columnNo));
267: } catch (EvalError e3) {
268: throw new BSFException("BeanShell script error: " + e3
269: + sourceInfo(source, lineNo, columnNo));
270: }
271: }
272:
273: public void exec(String source, int lineNo, int columnNo,
274: Object script) throws BSFException {
275: eval(source, lineNo, columnNo, script);
276: }
277:
278: /*
279: public void compileApply (String source, int lineNo, int columnNo,
280: Object funcBody, Vector paramNames, Vector arguments, CodeBuffer cb)
281: throws BSFException;
282:
283: public void compileExpr (String source, int lineNo, int columnNo,
284: Object expr, CodeBuffer cb) throws BSFException;
285:
286: public void compileScript (String source, int lineNo, int columnNo,
287: Object script, CodeBuffer cb) throws BSFException;
288: */
289:
290: public void declareBean(BSFDeclaredBean bean) throws BSFException {
291: try {
292: interpreter.set(bean.name, bean.bean);
293: } catch (EvalError e) {
294: throw new BSFException("error declaring bean: " + bean.name
295: + " : " + e.toString());
296: }
297: }
298:
299: public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
300: try {
301: interpreter.unset(bean.name);
302: } catch (EvalError e) {
303: throw new BSFException("bsh internal error: "
304: + e.toString());
305: }
306: }
307:
308: public void terminate() {
309: }
310:
311: private String sourceInfo(String source, int lineNo, int columnNo) {
312: return "BSF info: " + source + " at line: " + lineNo
313: + " column: " + columnNo;
314: }
315: }
|