KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bsf > engines > javascript > JavaScriptEngine


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2002 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if
20  * any, must include the following acknowlegement:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowlegement may appear in the software itself,
24  * if and wherever such third-party acknowlegements normally appear.
25  *
26  * 4. The names "Apache BSF", "Apache", and "Apache Software Foundation"
27  * must not be used to endorse or promote products derived from
28  * this software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache"
32  * nor may "Apache" appear in their names without prior written
33  * permission of the Apache Group.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many individuals
50  * on behalf of the Apache Software Foundation and was originally created by
51  * Sanjiva Weerawarana and others at International Business Machines
52  * Corporation. For more information on the Apache Software Foundation,
53  * please see <http://www.apache.org/>.
54  */

55
56 package org.apache.bsf.engines.javascript;
57
58 import java.rmi.RemoteException JavaDoc;
59 import java.io.InputStream JavaDoc;
60 import java.io.IOException JavaDoc;
61 import java.lang.reflect.InvocationTargetException JavaDoc;
62 import java.util.Vector JavaDoc;
63
64 import org.mozilla.javascript.Script;
65 import org.mozilla.javascript.ClassDefinitionException;
66 import org.mozilla.javascript.Context;
67 import org.mozilla.javascript.EvaluatorException;
68 import org.mozilla.javascript.JavaScriptException;
69 import org.mozilla.javascript.PropertyException;
70 import org.mozilla.javascript.NativeJavaObject;
71 import org.mozilla.javascript.Scriptable;
72 import org.mozilla.javascript.ScriptableObject;
73 import org.mozilla.javascript.ScriptRuntime;
74 import org.mozilla.javascript.WrappedException;
75 import org.mozilla.javascript.Wrapper;
76 import org.mozilla.javascript.ImporterTopLevel;
77
78 import org.mozilla.javascript.debug.*;
79
80 import org.apache.bsf.*;
81 import org.apache.bsf.util.*;
82
83 /**
84  * This is the interface to Netscape's Rhino (JavaScript) from the
85  * Bean Scripting Framework.
86  * <p>
87  * The original version of this code was first written by Adam Peller
88  * for use in LotusXSL. Sanjiva took his code and adapted it for BSF.
89  *
90  * @author Adam Peller <peller@lotus.com>
91  * @author Sanjiva Weerawarana
92  * @author Matthew J. Duftler
93  * @author Norris Boyd
94  */

95 public class JavaScriptEngine extends BSFEngineImpl {
96     /**
97      * The global script object, where all embedded functions are defined,
98      * as well as the standard ECMA "core" objects.
99      */

100     private Scriptable global;
101
102     private RhinoEngineDebugger m_rhinoDbg;
103
104     public void disconnectedDebuggerNotify() {
105         m_rhinoDbg.disconnectedDebuggerNotify();
106     }
107     
108     BSFDebugManagerImpl getDebugManager() {
109         return dbgmgr;
110     }
111
112     public void placeBreakpointAtLine(int brkptid, String JavaDoc docname, int lineno)
113         throws BSFException {
114         m_rhinoDbg.placeBreakpointAtLine(brkptid, docname, lineno);
115     }
116
117     public void placeBreakpointAtOffset(int brkptid, String JavaDoc docname,
118                                         int offset) throws BSFException {
119         m_rhinoDbg.placeBreakpointAtOffset(brkptid, docname, offset);
120     }
121
122     public void removeBreakpoint(String JavaDoc docname, int brkptid)
123         throws BSFException {
124         m_rhinoDbg.removeBreakpoint(docname, brkptid);
125     }
126
127     public void setEntryExit(String JavaDoc docname, boolean on)
128         throws BSFException {
129         m_rhinoDbg.setEntryExit(docname, on);
130     }
131
132     /**
133      * Return an object from an extension.
134      * @param object Object on which to make the call (ignored).
135      * @param method The name of the method to call.
136      * @param args an array of arguments to be
137      * passed to the extension, which may be either
138      * Vectors of Nodes, or Strings.
139      */

140     public Object JavaDoc call(Object JavaDoc object, String JavaDoc method, Object JavaDoc[] args)
141         throws BSFException {
142         Object JavaDoc theReturnValue = null;
143         DebuggableEngine engine;
144         Context cx;
145         try {
146
147             cx = Context.enter();
148
149             //REMIND: convert arg list Vectors here?
150

151             Object JavaDoc fun = global.get(method, global);
152             if (fun == Scriptable.NOT_FOUND) {
153                 throw new JavaScriptException("function " + method + " not found.");
154             }
155             if (dbgmgr != null) {
156                 // Force interpretive mode---otherwise
157
// debugging is not supported by Rhino.
158
cx.setGeneratingDebug(true);
159                 cx.setGeneratingSource(true);
160
161                 cx.setOptimizationLevel(-1);
162
163                 engine = cx.getDebuggableEngine();
164                 engine.setDebugger(m_rhinoDbg);
165
166                 theReturnValue = ScriptRuntime.call(cx, fun, global, args,
167                                                     null);
168
169             }
170             else {
171                 cx.setOptimizationLevel(-1);
172
173                 cx.setGeneratingDebug(false);
174                 cx.setGeneratingSource(false);
175
176                 cx.setOptimizationLevel(0);
177
178                 engine = cx.getDebuggableEngine();
179                 engine.setDebugger(null);
180
181                 theReturnValue = ScriptRuntime.call(cx, fun, global, args,
182                                                     null);
183             }
184             if (theReturnValue instanceof Wrapper) {
185                 theReturnValue = ((Wrapper) theReturnValue).unwrap();
186             }
187         } catch (Throwable JavaDoc t) {
188             handleError(t);
189         } finally {
190             Context.exit();
191         }
192         return theReturnValue;
193     }
194
195     public void declareBean(BSFDeclaredBean bean) throws BSFException {
196         // Must wrap non-scriptable objects before presenting to Rhino
197
Scriptable wrapped = Context.toObject(bean.bean, global);
198         global.put(bean.name, global, wrapped);
199     }
200
201     /**
202      * This is used by an application to evaluate a string containing
203      * some expression.
204      */

205     public Object JavaDoc eval(String JavaDoc source, int lineNo, int columnNo, Object JavaDoc oscript)
206         throws BSFException {
207
208         String JavaDoc scriptText = oscript.toString();
209         Object JavaDoc retval = null;
210         DocumentCell cell;
211         FnOrScript fnOrScript;
212         Script script;
213         DebuggableEngine engine;
214         Context cx;
215
216         try {
217             cx = Context.enter();
218
219             cell = m_rhinoDbg.loadDocumentNotify(source);
220             fnOrScript = (FnOrScript) cell.registerFnOrScriptLines(scriptText,
221                                                                    lineNo,
222                                                                    columnNo);
223
224             m_rhinoDbg.setCompilingFnOrScript(fnOrScript);
225
226             if (dbgmgr != null) {
227                 // Force interpretive mode---otherwise
228
// debugging is not supported by Rhino.
229
cx.setGeneratingDebug(true);
230                 cx.setGeneratingSource(true);
231
232                 cx.setOptimizationLevel(-1);
233
234                 engine = cx.getDebuggableEngine();
235                 engine.setDebugger(m_rhinoDbg);
236
237                 // Muck w/ this iff someone else hasn't already got it true
238
if (!engine.getBreakNextLine()) {
239                     engine.setBreakNextLine(cell.getEntryExit());
240                 }
241
242                 fnOrScript.compile(cx, global);
243                 m_rhinoDbg.setCompilingFnOrScript(null);
244                 script = fnOrScript.getScript();
245
246                 if (script != null) retval = script.exec(cx, global);
247                 else retval = null;
248             }
249             else {
250                 cx.setOptimizationLevel(-1);
251
252                 cx.setGeneratingDebug(false);
253                 cx.setGeneratingSource(false);
254
255                 cx.setOptimizationLevel(0);
256
257                 engine = cx.getDebuggableEngine();
258                 engine.setDebugger(null);
259
260                 retval = cx.evaluateString(global, scriptText,
261                                            source, lineNo,
262                                            null);
263             }
264
265             if (retval instanceof NativeJavaObject)
266                 retval = ((NativeJavaObject) retval).unwrap();
267
268         } catch (Throwable JavaDoc t) { // includes JavaScriptException, rethrows Errors
269
handleError(t);
270         } finally {
271             Context.exit();
272         }
273         return retval;
274     }
275
276     public Object JavaDoc getSpecificDebuggingInterface() {
277         if (m_rhinoDbg != null) return m_rhinoDbg.getDebugInterface();
278         return null;
279     }
280
281     private void handleError(Throwable JavaDoc t) throws BSFException {
282         if (t instanceof WrappedException) {
283             t = (Throwable JavaDoc) ((WrappedException) t).unwrap();
284         }
285
286         String JavaDoc message = null;
287         Throwable JavaDoc target = t;
288
289         if (t instanceof JavaScriptException) {
290             message = t.getLocalizedMessage();
291
292             // Is it an exception wrapped in a JavaScriptException?
293
Object JavaDoc value = ((JavaScriptException) t).getValue();
294             if (value instanceof Throwable JavaDoc) {
295                 // likely a wrapped exception from a LiveConnect call.
296
// Display its stack trace as a diagnostic
297
target = (Throwable JavaDoc) value;
298             }
299         }
300         else if (t instanceof EvaluatorException ||
301                  t instanceof SecurityException JavaDoc) {
302             message = t.getLocalizedMessage();
303         }
304         else if (t instanceof RuntimeException JavaDoc) {
305             message = "Internal Error: " + t.toString();
306         }
307         else if (t instanceof StackOverflowError JavaDoc) {
308             message = "Stack Overflow";
309         }
310
311         if (message == null) {
312             message = t.toString();
313         }
314
315         //REMIND: can we recover the line number here? I think
316
// Rhino does this by looking up the stack for bytecode
317
// see Context.getSourcePositionFromStack()
318
// but I don't think this would work in interpreted mode
319

320         if (t instanceof Error JavaDoc && !(t instanceof StackOverflowError JavaDoc)) {
321             // Re-throw Errors because we're supposed to let the JVM see it
322
// Don't re-throw StackOverflows, because we know we've
323
// corrected the situation by aborting the loop and
324
// a long stacktrace would end up on the user's console
325
throw (Error JavaDoc) t;
326         }
327         else {
328             throw new BSFException(BSFException.REASON_OTHER_ERROR,
329                                    "JavaScript Error: " + message,
330                                    target);
331         }
332     }
333
334     /**
335      * initialize the engine. put the manager into the context -> manager
336      * map hashtable too.
337      */

338     public void initialize(BSFManager mgr, String JavaDoc lang, Vector JavaDoc declaredBeans)
339         throws BSFException {
340         try {
341             m_rhinoDbg = new RhinoEngineDebugger(this);
342         } catch (RemoteException JavaDoc re) {
343             m_rhinoDbg = null;
344         }
345         super.initialize(mgr, lang, declaredBeans);
346
347         // Initialize context and global scope object
348
try {
349             Context cx = Context.enter();
350             global = new ImporterTopLevel(cx);
351             Scriptable bsf = cx.toObject(new BSFFunctions(mgr, this), global);
352             global.put("bsf", global, bsf);
353
354             int size = declaredBeans.size();
355             for (int i = 0; i < size; i++) {
356                 declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
357             }
358         } catch (Throwable JavaDoc t) {
359
360         } finally {
361             Context.exit();
362         }
363     }
364
365     public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
366         global.delete(bean.name);
367     }
368 }
369
Popular Tags