KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > java > ScriptStackTrace


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.java;
31
32 import com.caucho.bytecode.Attribute;
33 import com.caucho.bytecode.ByteCodeParser;
34 import com.caucho.bytecode.JavaClass;
35 import com.caucho.bytecode.OpaqueAttribute;
36 import com.caucho.loader.SimpleLoader;
37 import com.caucho.util.L10N;
38 import com.caucho.util.Log;
39 import com.caucho.vfs.ReadStream;
40 import com.caucho.vfs.Vfs;
41
42 import java.io.ByteArrayInputStream JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.io.InputStream JavaDoc;
45 import java.io.PrintWriter JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.WeakHashMap JavaDoc;
48 import java.util.logging.Level JavaDoc;
49 import java.util.logging.Logger JavaDoc;
50
51 /**
52  * Prints a stack trace using JSR-45
53  */

54 public class ScriptStackTrace {
55   private static final L10N L = new L10N(ScriptStackTrace.class);
56   private static final Logger JavaDoc log = Log.open(ScriptStackTrace.class);
57   
58   private static WeakHashMap JavaDoc<Class JavaDoc,LineMap> _scriptMap =
59     new WeakHashMap JavaDoc<Class JavaDoc,LineMap>();
60   
61   /**
62    * Filter a stack trace, replacing names.
63    */

64   public static void printStackTrace(Throwable JavaDoc e, PrintWriter JavaDoc out)
65   {
66     StackTraceElement JavaDoc lastHead = null;
67
68     ClassLoader JavaDoc loader = SimpleLoader.create(WorkDir.getLocalWorkDir());
69     
70     while (true) {
71       if (e.getMessage() != null)
72     out.println(e.getClass().getName() + ": " + e.getMessage());
73       else
74     out.println(e.getClass().getName());
75
76       StackTraceElement JavaDoc []trace = e.getStackTrace();
77       StackTraceElement JavaDoc nextHead = trace.length > 0 ? trace[0] : null;
78
79       for (int i = 0; i < trace.length; i++) {
80     if (trace[i].equals(lastHead))
81       break;
82     
83     out.print("\tat ");
84
85     printStackTraceElement(trace[i], out, loader);
86       }
87
88       lastHead = nextHead;
89
90       Throwable JavaDoc cause = e.getCause();
91
92       if (cause != null) {
93     out.print("Caused by: ");
94     e = cause;
95       }
96       else
97     break;
98     }
99   }
100
101   /**
102    * Prints a single stack trace element.
103    */

104   private static void printStackTraceElement(StackTraceElement JavaDoc trace,
105                          PrintWriter JavaDoc out,
106                          ClassLoader JavaDoc loader)
107   {
108     try {
109       LineMap map = getScriptLineMap(trace.getClassName(), loader);
110
111       if (map != null) {
112     LineMap.Line line = map.getLine(trace.getLineNumber());
113     if (line != null) {
114       out.print(trace.getClassName() + "." + trace.getMethodName());
115       out.print("(" + line.getSourceFilename() + ":");
116       out.println(line.getSourceLine(trace.getLineNumber()) + ")");
117       return;
118     }
119       }
120     } catch (Throwable JavaDoc e) {
121     }
122     
123     out.println(trace);
124   }
125
126   /**
127    * Loads the local line map for a class.
128    */

129   public static LineMap getScriptLineMap(String JavaDoc className, ClassLoader JavaDoc loader)
130   {
131     try {
132       Class JavaDoc cl = loader.loadClass(className);
133
134       LineMap map = _scriptMap.get(cl);
135
136       if (map == null) {
137     map = loadScriptMap(cl);
138     _scriptMap.put(cl, map);
139       }
140
141       return map;
142     } catch (Throwable JavaDoc e) {
143       return null;
144     }
145   }
146   
147
148   /**
149    * Loads the script map for a class
150    */

151   private static LineMap loadScriptMap(Class JavaDoc cl)
152   {
153     ClassLoader JavaDoc loader = cl.getClassLoader();
154
155     if (loader == null)
156       return new LineMap(); // null map
157

158     try {
159       String JavaDoc pathName = cl.getName().replace('.', '/') + ".class";
160
161       InputStream JavaDoc is = loader.getResourceAsStream(pathName);
162
163       if (is == null)
164     return null;
165       
166       try {
167     JavaClass jClass = new ByteCodeParser().parse(is);
168
169     Attribute attr = jClass.getAttribute("SourceDebugExtension");
170
171     if (attr == null) {
172       int p = cl.getName().indexOf('$');
173       
174       if (p > 0) {
175         String JavaDoc className = cl.getName().substring(0, p);
176
177         return loadScriptMap(loader.loadClass(className));
178       }
179
180       return new LineMap();
181     }
182     else if (attr instanceof OpaqueAttribute) {
183       byte []value = ((OpaqueAttribute) attr).getValue();
184
185       ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(value);
186
187       ReadStream rs = Vfs.openRead(bis);
188       rs.setEncoding("UTF-8");
189
190       try {
191         return parseSmap(rs);
192       } finally {
193         rs.close();
194       }
195     }
196     else
197       throw new IllegalStateException JavaDoc(L.l("Expected opaque attribute at '{0}'",
198                           attr));
199       } finally {
200     if (is != null)
201       is.close();
202       }
203     } catch (Throwable JavaDoc e) {
204       log.log(Level.FINER, e.toString(), e);
205
206       return new LineMap(); // null map
207
}
208   }
209
210   /**
211    * Parses the SMAP file.
212    */

213   private static LineMap parseSmap(ReadStream is)
214     throws IOException JavaDoc
215   {
216     String JavaDoc smap = is.readln();
217
218     if (! smap.equals("SMAP"))
219       throw new IOException JavaDoc(L.l("Illegal header"));
220       
221
222     String JavaDoc outputFile = is.readln().trim();
223     String JavaDoc defaultStratum = is.readln().trim();
224
225     String JavaDoc stratum = defaultStratum;
226     HashMap JavaDoc<String JavaDoc,String JavaDoc> fileMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
227
228     LineMap lineMap = new LineMap(outputFile);
229       
230     loop:
231     while (true) {
232       int ch = is.read();
233
234       if (ch < 0)
235     break;
236
237       if (ch != '*')
238     throw new IOException JavaDoc(L.l("unexpected character '{0}'",
239                   String.valueOf((char) ch)));
240
241       int code = is.read();
242       String JavaDoc value = is.readln();
243
244       switch (code) {
245       case 'E':
246     break loop;
247
248       case 'S':
249     stratum = value.trim();
250     break;
251
252       case 'F':
253     while ((ch = is.read()) > 0 && ch != '*') {
254       if (ch == '+') {
255         String JavaDoc first = is.readln().trim();
256         String JavaDoc second = is.readln().trim();
257
258         int p = first.indexOf(' ');
259         String JavaDoc key = first.substring(0, p);
260         String JavaDoc file = first.substring(p + 1).trim();
261
262         if (fileMap.size() == 0)
263           fileMap.put("", second);
264
265         fileMap.put(key, second);
266       }
267       else {
268         String JavaDoc first = is.readln().trim();
269       
270         int p = first.indexOf(' ');
271         String JavaDoc key = first.substring(0, p);
272         String JavaDoc file = first.substring(p + 1).trim();
273
274         if (fileMap.size() == 0)
275           fileMap.put("", file);
276
277         fileMap.put(key, file);
278       }
279     }
280     if (ch == '*')
281       is.unread();
282     break;
283
284       case 'L':
285     while ((ch = is.read()) != '*' && ch > 0) {
286       is.unread();
287       
288       String JavaDoc line = is.readln().trim();
289
290       addMap(line, fileMap, lineMap);
291     }
292     if (ch == '*')
293       is.unread();
294     break;
295     
296       default:
297     while ((ch = is.read()) != '*') {
298       is.readln();
299     }
300     if (ch == '*')
301       is.unread();
302     break;
303       }
304     }
305     
306     
307     return lineMap;
308   }
309
310   private static void addMap(String JavaDoc line,
311                  HashMap JavaDoc<String JavaDoc,String JavaDoc> fileMap,
312                  LineMap lineMap)
313   {
314     int colon = line.indexOf(':');
315
316     if (colon < 0)
317       return;
318
319     int hash = line.indexOf('#');
320     int startLine = 0;
321     String JavaDoc fileId = "";
322     int repeatCount = 1;
323
324     if (hash < 0)
325       startLine = Integer.parseInt(line.substring(0, colon));
326     else {
327       startLine = Integer.parseInt(line.substring(0, hash));
328
329       int comma = line.indexOf(',', hash);
330
331       if (comma > 0 && comma < colon) {
332     fileId = line.substring(hash + 1, comma).trim();
333     repeatCount = Integer.parseInt(line.substring(comma + 1, colon));
334       }
335       else
336     fileId = line.substring(hash + 1, colon).trim();
337     }
338
339     int outputLine = -1;
340     int outputIncrement = 1;
341
342     int comma = line.indexOf(',', colon);
343
344     if (comma > 0) {
345       outputLine = Integer.parseInt(line.substring(colon + 1, comma));
346       outputIncrement = Integer.parseInt(line.substring(comma + 1));
347     }
348     else
349       outputLine = Integer.parseInt(line.substring(colon + 1));
350
351     String JavaDoc file = fileMap.get(fileId);
352
353     lineMap.addLine(startLine, file, repeatCount, outputLine, outputIncrement);
354   }
355 }
356
Popular Tags