001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.base.util;
019:
020: /*
021: * Based on code that started with this header/license:
022: This file is associated with the BeanShell Java Scripting language
023: distribution (http://www.beanshell.org/).
024:
025: This file is hereby placed into the public domain... You may copy,
026: modify, and redistribute it without restriction.
027:
028: */
029:
030: import java.io.StringReader;
031: import java.util.Vector;
032:
033: import bsh.EvalError;
034: import bsh.Interpreter;
035: import bsh.InterpreterError;
036: import bsh.TargetError;
037:
038: import org.apache.bsf.BSFDeclaredBean;
039: import org.apache.bsf.BSFException;
040: import org.apache.bsf.BSFManager;
041: import org.apache.bsf.util.BSFEngineImpl;
042:
043: import org.ofbiz.base.util.cache.UtilCache;
044:
045: /**
046: * This is the BeanShell adapter for IBM's Bean Scripting Famework.
047: * It is an implementation of the BSFEngine class, allowing BSF aware
048: * applications to use BeanShell as a scripting language.
049: * <p>
050: *
051: * I believe this implementation is complete (with some hesitation about the
052: * the usefullness of the compileXXX() style methods - provided by the base
053: * utility class).
054: *
055: */
056: public class OfbizBshBsfEngine extends BSFEngineImpl {
057:
058: public static final String module = OfbizBshBsfEngine.class
059: .getName();
060:
061: protected Interpreter interpreter;
062: protected boolean installedApplyMethod;
063:
064: public static UtilCache parsedScripts = new UtilCache(
065: "script.BshBsfParsedCache", 0, 0, false);
066:
067: public void initialize(BSFManager mgr, String lang,
068: Vector declaredBeans) throws BSFException {
069: super .initialize(mgr, lang, declaredBeans);
070:
071: interpreter = BshUtil.getMasterInterpreter(null);
072:
073: // declare the bsf manager for callbacks, etc.
074: try {
075: interpreter.set("bsf", mgr);
076: } catch (EvalError e) {
077: throw new BSFException("bsh internal error: "
078: + e.toString());
079: }
080:
081: for (int i = 0; i < declaredBeans.size(); i++) {
082: BSFDeclaredBean bean = (BSFDeclaredBean) declaredBeans
083: .get(i);
084: declareBean(bean);
085: }
086: }
087:
088: public void setDebug(boolean debug) {
089: Interpreter.DEBUG = debug;
090: }
091:
092: /**
093: * Invoke method name on the specified bsh scripted object.
094: * The object may be null to indicate the global namespace of the
095: * interpreter.
096: * @param object may be null for the global namespace.
097: */
098: public Object call(Object object, String name, Object[] args)
099: throws BSFException {
100: if (object == null) {
101: try {
102: object = interpreter.get("global");
103: } catch (EvalError e) {
104: throw new BSFException("bsh internal error: "
105: + e.toString());
106: }
107: }
108:
109: if (object instanceof bsh.This) {
110: try {
111: return ((bsh.This) object).invokeMethod(name, args);
112: } catch (InterpreterError e) {
113: throw new BSFException(
114: "BeanShell interpreter internal error: " + e);
115: } catch (TargetError e2) {
116: throw new BSFException(
117: "The application script threw an exception: "
118: + e2.getTarget());
119: } catch (EvalError e3) {
120: throw new BSFException("BeanShell script error: " + e3);
121: }
122: } else {
123: throw new BSFException("Cannot invoke method: " + name
124: + ". Object: " + object
125: + " is not a BeanShell scripted object.");
126: }
127: }
128:
129: /**
130: * A helper BeanShell method that implements the anonymous method apply
131: * proposed by BSF. Note that the script below could use the standard
132: * bsh eval() method to set the variables and apply the text, however
133: * then I'd have to escape quotes, etc.
134: */
135: final static String bsfApplyMethod = "_bsfApply(_bsfNames, _bsfArgs, _bsfText) {"
136: + "for(i=0;i<_bsfNames.length;i++)"
137: + "this.namespace.setVariable(_bsfNames[i], _bsfArgs[i]);"
138: + "return this.interpreter.eval(_bsfText, this.namespace);"
139: + "}";
140:
141: /**
142: * This is an implementation of the BSF apply() method.
143: * It exectutes the funcBody text in an "anonymous" method call with
144: * arguments.
145: */
146: public Object apply(String source, int lineNo, int columnNo,
147: Object funcBody, Vector namesVec, Vector argsVec)
148: throws BSFException {
149: if (namesVec.size() != argsVec.size())
150: throw new BSFException("number of params/names mismatch");
151: if (!(funcBody instanceof String))
152: throw new BSFException(
153: "apply: function body must be a string");
154:
155: String[] names = new String[namesVec.size()];
156: namesVec.copyInto(names);
157: Object[] args = new String[argsVec.size()];
158: argsVec.copyInto(args);
159:
160: try {
161: if (!installedApplyMethod) {
162: interpreter.eval(bsfApplyMethod);
163: installedApplyMethod = true;
164: }
165:
166: bsh.This global = (bsh.This) interpreter.get("global");
167: return global.invokeMethod("_bsfApply", new Object[] {
168: names, args, (String) funcBody });
169:
170: } catch (InterpreterError e) {
171: throw new BSFException(
172: "BeanShell interpreter internal error: " + e
173: + sourceInfo(source, lineNo, columnNo));
174: } catch (TargetError e2) {
175: throw new BSFException(
176: "The application script threw an exception: "
177: + e2.getTarget()
178: + sourceInfo(source, lineNo, columnNo));
179: } catch (EvalError e3) {
180: throw new BSFException("BeanShell script error: " + e3
181: + sourceInfo(source, lineNo, columnNo));
182: }
183: }
184:
185: public Object eval(String source, int lineNo, int columnNo,
186: Object expr) throws BSFException {
187: if (!(expr instanceof String))
188: throw new BSFException(
189: "BeanShell expression must be a string");
190:
191: try {
192: //return interpreter.eval(((String) expr));
193:
194: Interpreter.ParsedScript script = null;
195:
196: if (source != null && source.length() > 0) {
197: script = (Interpreter.ParsedScript) parsedScripts
198: .get(source);
199: if (script == null) {
200: synchronized (OfbizBshBsfEngine.class) {
201: script = (Interpreter.ParsedScript) parsedScripts
202: .get(source);
203: if (script == null) {
204: script = interpreter.parseScript(source,
205: new StringReader((String) expr));
206: Debug.logVerbose("Caching BSH script at: "
207: + source, module);
208: parsedScripts.put(source, script);
209: }
210: }
211: }
212: } else {
213: script = interpreter.parseScript(source,
214: new StringReader((String) expr));
215: }
216:
217: return interpreter.evalParsedScript(script);
218: } catch (InterpreterError e) {
219: throw new BSFException(
220: "BeanShell interpreter internal error: " + e
221: + sourceInfo(source, lineNo, columnNo));
222: } catch (TargetError e2) {
223: Debug.logError(e2,
224: "Error thrown in BeanShell script called through BSF at: "
225: + sourceInfo(source, lineNo, columnNo),
226: module);
227: //Debug.logError(e2.getTarget(), module);
228: throw new BSFException(
229: "The application script threw an exception: " + e2
230: + " "
231: + sourceInfo(source, lineNo, columnNo));
232: } catch (EvalError e3) {
233: throw new BSFException("BeanShell script error: " + e3
234: + sourceInfo(source, lineNo, columnNo));
235: }
236: }
237:
238: public void exec(String source, int lineNo, int columnNo,
239: Object script) throws BSFException {
240: eval(source, lineNo, columnNo, script);
241: }
242:
243: /*
244: public void compileApply (String source, int lineNo, int columnNo,
245: Object funcBody, Vector paramNames, Vector arguments, CodeBuffer cb)
246: throws BSFException;
247:
248: public void compileExpr (String source, int lineNo, int columnNo,
249: Object expr, CodeBuffer cb) throws BSFException;
250:
251: public void compileScript (String source, int lineNo, int columnNo,
252: Object script, CodeBuffer cb) throws BSFException;
253: */
254:
255: public void declareBean(BSFDeclaredBean bean) throws BSFException {
256: try {
257: interpreter.set(bean.name, bean.bean);
258: } catch (EvalError e) {
259: throw new BSFException("error declaring bean: " + bean.name
260: + " : " + e.toString());
261: }
262: }
263:
264: public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
265: try {
266: interpreter.unset(bean.name);
267: } catch (EvalError e) {
268: throw new BSFException("bsh internal error: "
269: + e.toString());
270: }
271: }
272:
273: public void terminate() {
274: }
275:
276: private String sourceInfo(String source, int lineNo, int columnNo) {
277: return "BSF info: " + source + " at line: " + lineNo
278: + " column: " + columnNo;
279: }
280: }
|