KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.InputStream JavaDoc;
59 import java.io.IOException JavaDoc;
60 import java.io.StringReader JavaDoc;
61 import java.io.Reader JavaDoc;
62 import java.rmi.RemoteException JavaDoc;
63 import java.util.Vector JavaDoc;
64 import java.util.Enumeration JavaDoc;
65 import java.util.Hashtable JavaDoc;
66 import java.security.*;
67
68 import org.mozilla.javascript.*;
69 import org.mozilla.javascript.debug.*;
70
71 import org.apache.bsf.debug.util.DebugLog;
72 import org.apache.bsf.*;
73 import org.apache.bsf.util.*;
74 import org.apache.bsf.debug.*;
75 import org.apache.bsf.debug.jsdi.*;
76
77 public class RhinoEngineDebugger implements Debugger {
78
79     /** The global script object, where all embedded functions are defined,
80      * as well as the standard ECMA "core" objects.
81      */

82     private Scriptable global;
83     private JsObject globalstub;
84
85     private RhinoContextProxy m_rcp;
86     private Scriptable undefined;
87     private JsObject undefinedStub;
88
89     /**
90      * Hashtable allowing to find the stub for an object in the JavaScript
91      * environment if one exists.
92      * Typically: Scriptable, Function, Script, etc.
93      * This is not used for Context and DebugFrame.
94      * They typically contains JsObject associated to
95      * org.mozilla.javascript.ScriptableObject
96      */

97     private Hashtable JavaDoc stubs;
98
99     private JsCallbacks m_callbacks;
100     private JsEngineStub engineStub;
101
102     private FnOrScript m_compilingFnOrScript;
103     private JavaScriptEngine m_eng;
104
105     private Thread JavaDoc m_thread;
106
107     private Hashtable JavaDoc m_documents;
108
109     BSFDebugManagerImpl dbgmgr;
110
111     public RhinoEngineDebugger(JavaScriptEngine eng)
112         throws RemoteException JavaDoc {
113         super();
114         m_thread = Thread.currentThread();
115         m_eng = eng;
116         dbgmgr = eng.getDebugManager();
117
118         m_documents = new Hashtable JavaDoc();
119
120         stubs = new Hashtable JavaDoc();
121         m_callbacks = null;
122
123         engineStub = new JsEngineStub(this);
124
125     }
126
127     /**
128      * Called when our debugger has been disconnected.
129      */

130     public void disconnectedDebuggerNotify() {
131         m_callbacks = null;
132     }
133
134     void addStub(Context cx, RhinoContextProxy jscx) {
135         stubs.put(cx, jscx);
136     }
137
138     void addStub(DebugFrame frame, JsContextStub stub) {
139         stubs.put(frame, stub);
140     }
141
142     void addStub(Scriptable sobj, JsObject jsobj) {
143         stubs.put(sobj, jsobj);
144     }
145
146     void dropStub(Object JavaDoc key) {
147         stubs.remove(key);
148     }
149
150     public synchronized DocumentCell getDocumentCell(String JavaDoc name) {
151         return (DocumentCell) m_documents.get(name);
152     }
153
154     // Called upon creation of a BSFManager.
155
public synchronized DocumentCell loadDocumentNotify(String JavaDoc name) {
156         DocumentCell cell;
157
158         cell = (DocumentCell) m_documents.get(name);
159         if (cell == null) {
160             cell = new DocumentCell(this, name);
161             m_documents.put(name, cell);
162             if (dbgmgr!=null)
163                 dbgmgr.loadDocumentNotify(m_eng, name);
164         }
165         return cell;
166     }
167
168     public synchronized void placeBreakpointAtLine(int brkptid,
169                                                    String JavaDoc docname,
170                                                    int lineno) {
171
172         DocumentCell cell;
173         cell = (DocumentCell) m_documents.get(docname);
174         cell.addBreakpointAtLine(brkptid, lineno);
175     }
176
177     public synchronized void placeBreakpointAtOffset(int brkptid,
178                                                      String JavaDoc docname,
179                                                      int offset) {
180
181         DocumentCell cell;
182         cell = (DocumentCell) m_documents.get(docname);
183         cell.addBreakpointAtOffset(brkptid, offset);
184     }
185
186     public void removeBreakpoint(String JavaDoc docname, int brkptid)
187         throws BSFException {
188
189         DocumentCell cell;
190         cell = (DocumentCell) m_documents.get(docname);
191         cell.removeBreakpoint(brkptid);
192     }
193
194     public void setEntryExit(String JavaDoc docname, boolean on)
195         throws BSFException {
196
197         DocumentCell cell;
198         cell = (DocumentCell) m_documents.get(docname);
199         cell.setEntryExit(on);
200     }
201
202     public Object JavaDoc eval(String JavaDoc docname, String JavaDoc fnOrScript, int lineno)
203         throws RemoteException JavaDoc {
204         Object JavaDoc retval;
205         try {
206             retval = m_eng.eval(docname, lineno, -1, fnOrScript);
207             return marshallProperty(retval);
208         } catch (BSFException ex) {
209             throw new RemoteException JavaDoc("Failed eval", ex);
210         }
211     }
212
213     public JsContext getContext(int depth) {
214         if (m_rcp != null) return m_rcp.getContext(depth);
215         return null;
216     }
217
218     public int getContextCount() {
219         if (m_rcp != null) return m_rcp.getContextCount();
220         return -1;
221     }
222
223     /**
224      * Return the current debugger.
225      * @return the debugger, or null if none is attached.
226      */

227     public JsCallbacks getDebugger() {
228         return m_callbacks;
229     }
230
231     public Object JavaDoc getDebugInterface() {
232         return engineStub;
233     }
234
235     public JsObject getGlobalObject() {
236         return globalstub;
237     }
238
239     public RhinoContextProxy getRhinoContextProxy() {
240         return m_rcp;
241     }
242
243     RhinoContextProxy getStub(Context cx) {
244         return (RhinoContextProxy) stubs.get(cx);
245     }
246
247     JsContextStub getStub(DebugFrame frame) {
248         return (JsContextStub) stubs.get(frame);
249     }
250
251     JsObject getStub(Scriptable sobj) {
252         return (JsObject) stubs.get(sobj);
253     }
254
255     public JsObject getUndefinedValue() {
256         return undefinedStub;
257     }
258
259     public String JavaDoc getThread() {
260         String JavaDoc resultstr = "";
261
262         if (m_thread != null) {
263             try {
264                 final String JavaDoc resultstrf = (String JavaDoc)
265                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
266                         public Object JavaDoc run() throws Exception JavaDoc {
267                             return m_thread.getName();
268                         }
269                     });
270             resultstr = resultstrf;
271             }
272             catch (PrivilegedActionException prive) {
273                 resultstr = "Security Exception triggered. " +
274                     "Thread info unavailable";
275             }
276         }
277         return resultstr;
278     }
279
280     public String JavaDoc getThreadGroup() {
281         String JavaDoc resultstr = "";
282
283         if (m_thread != null) {
284             try {
285                 final String JavaDoc resultstrf = (String JavaDoc)
286                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
287                         public Object JavaDoc run() throws Exception JavaDoc {
288                             return m_thread.getThreadGroup().getName();
289                         }
290                     });
291             resultstr = resultstrf;
292             }
293             catch (PrivilegedActionException prive) {
294                 resultstr = "Security Exception triggered. " +
295                     "ThreadGroup info unavailable";
296             }
297         }
298         return resultstr;
299     }
300
301     //---------------------------------------------------------
302
// The Rhino engine stopped.
303
// It could be that it hit a breakpoint that we set or
304
// that it is in stepping mode. The stepping mode is used
305
// to implement STEP_IN, STEP_OUT, and STEP_OVER.
306
//---------------------------------------------------------
307

308     public void handleBreakpointHit(Context cx) {
309         JsCallbacks debugger;
310         BreakPoint bp;
311         Enumeration JavaDoc e;
312         DocumentCell cell;
313         boolean breakpointFound=false;
314         String JavaDoc name;
315         int lineno;
316         boolean suspend=false;
317         
318         m_thread = Thread.currentThread();
319         DebugLog.stdoutPrintln("**** Handling a breakpoint hit...",
320                                DebugLog.BSF_LOG_L3);
321         m_rcp = getStub(cx);
322         if (m_rcp == null) {
323             m_rcp = new RhinoContextProxy(this, cx);
324             addStub(cx, m_rcp);
325         }
326         // if we have no callbacks... then just
327
// ignore the breakpoint hit, do a run
328
// so that execution resumes...
329
if (m_callbacks==null) {
330             DebugLog.stdoutPrintln(" No callbacks, resuming...", DebugLog.BSF_LOG_L3);
331             m_rcp.run();
332
333         } else {
334             // First, check that we didn't hit a known breakpoint.
335
// First, search if we have breakpoints for the current documents
336

337             name = m_rcp.getSourceName();
338             lineno = m_rcp.getLineNumber();
339
340             DebugLog.stdoutPrintln(" in "+name+" at "+lineno, DebugLog.BSF_LOG_L3);
341
342             cell = getDocumentCell(name);
343             if (cell != null)
344                 _handleBreakpointHit(cell,lineno);
345         }
346         m_rcp = null;
347     }
348
349     public void _handleBreakpointHit(DocumentCell cell, int lineno) {
350
351         JsCallbacks debugger;
352         BreakPoint bp;
353         Enumeration JavaDoc e;
354         JsContext stub=null;
355         boolean breakpointFound=false;
356         boolean suspend=false;
357         
358         try {
359             bp = cell.findBreakpointAtLine(lineno);
360         } catch (BSFException bsfex) {
361             bp = null;
362         }
363         if (bp != null) {
364             breakpointFound = true;
365             try {
366                 stub = m_rcp.hitBreakpoint();
367                 DebugLog.stdoutPrintln(" breakpoint callback...", DebugLog.BSF_LOG_L3);
368                 m_callbacks.createFuture(m_rcp);
369                 m_callbacks.handleBreakpointHit(stub);
370                 suspend = true;
371             } catch (RemoteException JavaDoc rex) {
372                 DebugLog.stderrPrintln(" EXCEPTION OCCURED DURING BREAKPOINT CALLBACK", DebugLog.BSF_LOG_L0);
373                 DebugLog.stderrPrintln(rex.getMessage(), DebugLog.BSF_LOG_L0);
374                 rex.printStackTrace();
375                 suspend = false;
376             }
377         } else {
378             DebugLog.stdoutPrintln(" didn't find a breakpoint...", DebugLog.BSF_LOG_L3);
379             breakpointFound = false;
380         }
381
382         if (!breakpointFound) {
383             // we haven't found a breakpoint at the current
384
// line in the current document, we must be stepping
385
// or in entry/exit mode
386
try {
387                 stub = m_rcp.stepping();
388                 FnOrScript current = cell.findFnOrScriptContaining(lineno);
389                 if (stub != null) {
390                     cell.setLastFnOrScript(current);
391                     DebugLog.stdoutPrintln(" stepping-done callback...",
392                                            DebugLog.BSF_LOG_L3);
393                     m_callbacks.createFuture(m_rcp);
394                     m_callbacks.handleSteppingDone(stub);
395                     suspend = true;
396                 }
397                 else if (cell.getEntryExit() &&
398                          (current != cell.getLastFnOrScript()) &&
399                          (m_rcp.getContextCount() == 0)) {
400                     cell.setLastFnOrScript(current);
401                     stub = m_rcp.entry_exit_mode();
402                     DebugLog.stdoutPrintln(" entry/exit mode...",
403                                            DebugLog.BSF_LOG_L3);
404                     m_callbacks.createFuture(m_rcp);
405                     m_callbacks.handleSteppingDone(stub);
406                     suspend = true;
407                 }
408                 else {
409                     DebugLog.stdoutPrintln(" No reason to suspend execution.", DebugLog.BSF_LOG_L3);
410                     suspend = false;
411                 }
412             } catch (RemoteException JavaDoc rex) {
413                 DebugLog.stderrPrintln(" EXCEPTION OCCURED DURING STEPPING-DONE CALLBACK", DebugLog.BSF_LOG_L0);
414                 DebugLog.stderrPrintln(rex.getMessage(), DebugLog.BSF_LOG_L0);
415                 rex.printStackTrace();
416                 suspend = false;
417             }
418         }
419         if (suspend) {
420             // now, suspend this thread... until
421
// we restart.
422
try {
423                 m_callbacks.suspendFuture(m_rcp);
424             } catch (Exception JavaDoc ex) {
425                 DebugLog.stdoutPrintln("Future creation failed... releasing the engine", DebugLog.BSF_LOG_L3);
426                 m_rcp.run();
427             }
428         }
429     }
430
431     public void run(JsEngineStub eng) throws Exception JavaDoc {
432         DebugLog.stdoutPrintln("RhinoEngineDebugger::run()...",
433                                DebugLog.BSF_LOG_L3);
434         m_rcp.run();
435         m_callbacks.completeFuture(m_rcp);
436     }
437
438     public void stepIn(JsEngineStub eng) throws Exception JavaDoc {
439         DebugLog.stdoutPrintln("RhinoEngineDebugger::stepIn()...",
440                                DebugLog.BSF_LOG_L3);
441         m_rcp.stepIn();
442         m_callbacks.completeFuture(m_rcp);
443     }
444
445     public void stepOut(JsEngineStub eng) throws Exception JavaDoc {
446         DebugLog.stdoutPrintln("RhinoEngineDebugger::stepOut()...",
447                                DebugLog.BSF_LOG_L3);
448         m_rcp.stepOut();
449         m_callbacks.completeFuture(m_rcp);
450     }
451     public void stepOver(JsEngineStub eng) throws Exception JavaDoc {
452
453         DebugLog.stdoutPrintln("RhinoEngineDebugger::stepOver()...",
454                                DebugLog.BSF_LOG_L3);
455         m_rcp.stepOver();
456         m_callbacks.completeFuture(m_rcp);
457     }
458     
459     public void handleCompilationDone(Context cx,
460                                       DebuggableScript fnOrScript,
461                                       StringBuffer JavaDoc source) {
462
463         m_thread = Thread.currentThread();
464         m_compilingFnOrScript.addCompilationUnit(cx, fnOrScript, source);
465     }
466
467     public void handleExceptionThrown(Context cx, Object JavaDoc exceptionThrown) {
468         JsContext stub;
469         JsCallbacks debugger;
470         BreakPoint bp;
471         Enumeration JavaDoc e;
472         DocumentCell cell;
473         String JavaDoc name,msg;
474         Exception JavaDoc ex;
475         int lineno;
476         NativeError error;
477         
478         m_thread = Thread.currentThread();
479         m_rcp = getStub(cx);
480         if (m_rcp == null) {
481             m_rcp = new RhinoContextProxy(this, cx);
482             addStub(cx, m_rcp);
483         }
484         try {
485             // if we have no callbacks... then just
486
// ignore the breakpoint hit, do a run
487
// so that execution resumes...
488
if (m_callbacks==null) {
489                 m_rcp.run();
490                 return;
491             }
492
493             // First, check that we didn't hit a known breakpoint.
494
// First, search if we have breakpoints for the current documents
495
name = m_rcp.getSourceName();
496             lineno = m_rcp.getLineNumber();
497             try {
498                 error = (NativeError)exceptionThrown;
499                 msg = error.getName() + ": " + error.getMessage();
500             } catch (ClassCastException JavaDoc ccex) {
501                 msg = "Unknown JavaScript Exception";
502             }
503             ex = new Exception JavaDoc(msg);
504
505             cell = getDocumentCell(name);
506             if (cell == null) return;
507
508             try {
509                 stub = m_rcp.exceptionThrown();
510                 m_callbacks.createFuture(m_rcp);
511                 m_callbacks.handleExceptionThrown(stub,ex);
512                 
513                 // now, suspend this thread... until
514
// we restart.
515
m_callbacks.suspendFuture(m_rcp);
516                 
517             } catch (Exception JavaDoc ex2) {
518                 m_rcp.run();
519                 
520             }
521         } finally {
522             m_rcp = null;
523         }
524     }
525
526     Object JavaDoc marshallProperty(Object JavaDoc prop) throws RemoteException JavaDoc {
527         if (prop == null)
528             return null;
529         if (prop == Scriptable.NOT_FOUND)
530             return null;
531         if (prop == Context.getUndefinedValue())
532             return undefinedStub;
533         if (prop instanceof Scriptable) {
534             JsObject stub;
535             Scriptable sprop = (Scriptable) prop;
536             stub = getStub(sprop);
537             if (stub == null) {
538                 stub = new JsObjectStub(this, sprop);
539                 this.addStub(sprop, stub);
540             }
541             return stub;
542         }
543         return prop;
544     }
545
546     JsObject marshallScriptable(Scriptable prop) throws RemoteException JavaDoc {
547         if (prop == null)
548             return null;
549         if (prop == Scriptable.NOT_FOUND)
550             return null;
551         if (prop == Context.getUndefinedValue())
552             return undefinedStub;
553
554         JsObject stub;
555         Scriptable sprop = (Scriptable) prop;
556         stub = getStub(sprop);
557         if (stub == null) {
558             stub = new JsObjectStub(this, sprop);
559             this.addStub(sprop, stub);
560         }
561         return stub;
562     }
563
564     /**
565      * Set whether the engine should break when it encounters
566      * the next line.
567      * <p>
568      * The engine will call the attached debugger's handleBreakpointHit
569      * method on the next line it executes if isLineStep is true.
570      * May be used from another thread to interrupt execution.
571      *
572      * @param isLineStep if true, break next line
573      */

574     public void setBreakNextLine(JsContext context, boolean isLineStep) {
575     }
576
577     void setCompilingFnOrScript(FnOrScript fnOrScript) {
578         m_compilingFnOrScript = fnOrScript;
579     }
580
581     /**
582      * Set the associated debugger.
583      * @param debugger the debugger to be used on callbacks from
584      * the engine.
585      */

586     public void setDebugger(JsCallbacks debugger) {
587         m_callbacks = debugger;
588     }
589 }
590
Popular Tags