KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > flow > javascript > LocationTrackingDebugger


1 /*
2  * Copyright 2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.components.flow.javascript;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.List JavaDoc;
20
21 import org.apache.cocoon.ProcessingException;
22 import org.apache.cocoon.util.location.Location;
23 import org.apache.cocoon.util.location.LocationImpl;
24 import org.apache.cocoon.util.location.LocationUtils;
25 import org.apache.commons.lang.exception.ExceptionUtils;
26 import org.mozilla.javascript.Context;
27 import org.mozilla.javascript.EcmaError;
28 import org.mozilla.javascript.JavaScriptException;
29 import org.mozilla.javascript.Scriptable;
30 import org.mozilla.javascript.debug.DebugFrame;
31 import org.mozilla.javascript.debug.DebuggableScript;
32 import org.mozilla.javascript.debug.Debugger;
33
34 /**
35  * A Rhino debugger that tracks location information when an exception is raised in some JavaScript code.
36  * It's purpose is to build a {@link org.apache.cocoon.ProcessingException} that holds the stacktrace
37  * in the JavaScript code.
38  * <p>
39  * This debugger implementation is designed to be as lightweight and fast as possible, in order to have a
40  * negligible impact on the performances of the Rhino interpreter.
41  *
42  * @since 2.1.8
43  * @version $Id: LocationTrackingDebugger.java 280807 2005-09-14 09:38:48Z sylvain $
44  */

45 public class LocationTrackingDebugger implements Debugger {
46     
47     // Strong reference to the location finder
48
private static final LocationUtils.LocationFinder rhinoLocFinder = new LocationUtils.LocationFinder() {
49
50         public Location getLocation(Object JavaDoc obj, String JavaDoc description) {
51             if (obj instanceof EcmaError) {
52                 EcmaError ex = (EcmaError)obj;
53                 if (ex.getSourceName() != null) {
54                     return new LocationImpl(ex.getName(), ex.getSourceName(), ex.getLineNumber(), ex.getColumnNumber());
55                 } else {
56                     return Location.UNKNOWN;
57                 }
58     
59             } else if (obj instanceof JavaScriptException) {
60                 JavaScriptException ex = (JavaScriptException)obj;
61                 if (ex.sourceName() != null) {
62                     return new LocationImpl(description, ex.sourceName(), ex.lineNumber(), -1);
63                 } else {
64                     return Location.UNKNOWN;
65                 }
66             }
67             
68             return null;
69         }
70     };
71
72     
73     static {
74         // Register what's needed to analyze exceptions produced by Rhino
75
ExceptionUtils.addCauseMethodName("getWrappedException");
76         LocationUtils.addFinder(rhinoLocFinder);
77     }
78     
79     private List JavaDoc locations;
80     private Throwable JavaDoc throwable;
81
82     /**
83      * Rhino+cont API
84      */

85     public void handleCompilationDone(Context cx, DebuggableScript fnOrScript, StringBuffer JavaDoc source) {
86         // ignore
87
}
88
89     /**
90      * Rhino+cont API
91      */

92     public DebugFrame enterFrame(Context cx, Scriptable scope, Scriptable thisObj, Object JavaDoc[] args, DebuggableScript fnOrScript) {
93         return new StackTrackingFrame(fnOrScript);
94     }
95     
96     /**
97      * Rhino 1.6 API
98      */

99     public void handleCompilationDone(Context cx, DebuggableScript fnOrScript, String JavaDoc source) {
100         // nothing
101
}
102
103     /**
104      * Rhino 1.6 API
105      */

106     public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) {
107         // Rhino 1.6 API
108
return new StackTrackingFrame(fnOrScript);
109     }
110
111     /**
112      * Get an exception that reflects the known location stack
113      *
114      * @param description a description for the exception
115      * @param originalException the original exception
116      *
117      * @return a suitable exception to throw
118      * @see ProcessingException#throwLocated(String, Throwable, Location)
119      */

120     public Exception JavaDoc getException(String JavaDoc description, Exception JavaDoc originalException) throws ProcessingException {
121         if (throwable == null || locations == null) {
122             // Cannot to better for now
123
return originalException;
124         }
125
126         // Unwrap original exception, if any, wrapped by Rhino (the wrapping
127
// class is different in Rhino+cont and Rhino 1.6)
128
Throwable JavaDoc cause = ExceptionUtils.getCause(throwable);
129         if (cause != null)
130             throwable = cause;
131
132         return ProcessingException.throwLocated(description, throwable, locations);
133     }
134
135     private class StackTrackingFrame implements DebugFrame {
136         
137         DebuggableScript script;
138         int line;
139
140         public StackTrackingFrame(DebuggableScript script) {
141             this.script = script;
142         }
143         
144         public void onEnter(Context cx, Scriptable activation, Scriptable thisObj, Object JavaDoc[] args) {
145             // Rhino 1.6 specific
146
}
147         
148         // Rhino+cont API
149
public void onLineChange(Context cx, int lineNumber, boolean breakpoint) {
150             line = lineNumber;
151         }
152
153         // Rhino 1.6 API
154
public void onLineChange(Context cx, int lineNumber) {
155             line = lineNumber;
156         }
157
158         public void onExceptionThrown(Context cx, Throwable JavaDoc ex) {
159             throwable = ex;
160         }
161
162         public void onExit(Context cx, boolean byThrow, Object JavaDoc resultOrException) {
163             if (byThrow) {
164                   String JavaDoc name = null;
165 // Revisit: Rhino+cont and Rhino 1.6 have different debugger APIs, and we currently don't use this information
166
// Scriptable obj = script.getScriptable();
167
// name = obj instanceof NativeFunction ? ((NativeFunction)obj).getFunctionName() : "Top-level script";
168
// if (name == null || name.length() == 0) {
169
// name = "[unnamed]";
170
// }
171

172                 if (locations == null) {
173                     locations = new ArrayList JavaDoc(1); // start small
174
}
175
176                 locations.add(new LocationImpl(name, script.getSourceName(), line, -1));
177
178             } else if (locations != null) {
179                 // The exception was handled by the script: clear any recorded locations
180
locations = null;
181             }
182         }
183     }
184 }
185
186
Popular Tags