001: /*
002: * @(#)ThrowableParser.java
003: *
004: * Copyright (C) 2002-2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Part of the GroboUtils package at:
009: * http://groboutils.sourceforge.net
010: *
011: * Permission is hereby granted, free of charge, to any person obtaining a
012: * copy of this software and associated documentation files (the "Software"),
013: * to deal in the Software without restriction, including without limitation
014: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
015: * and/or sell copies of the Software, and to permit persons to whom the
016: * Software is furnished to do so, subject to the following conditions:
017: *
018: * The above copyright notice and this permission notice shall be included in
019: * all copies or substantial portions of the Software.
020: *
021: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
022: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
023: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
024: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
025: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
026: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
027: * DEALINGS IN THE SOFTWARE.
028: */
029: package net.sourceforge.groboutils.util.throwable.v1;
030:
031: import java.io.StringWriter;
032: import java.io.PrintWriter;
033: import java.io.BufferedReader;
034: import java.io.StringReader;
035:
036: import java.util.Vector;
037:
038: import java.lang.reflect.Method;
039:
040: //import org.apache.log4j.Logger;
041:
042: /**
043: * Parses a Throwable's stack trace into its components.
044: *
045: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
046: * @since March 17, 2002
047: * @version $Date: 2003/09/23 19:54:07 $
048: */
049: public class ThrowableParser {
050: //private static final Logger LOG = Logger.getLogger(
051: // ThrowableParser.class.getName() );
052:
053: // JDK 1.1+
054: private BufferedReader traceReader;
055:
056: // JDK 1.4+
057: private Object[] traceList;
058: private int traceIndex;
059:
060: private static final String JDK14_GST_METHOD = "getStackTrace";
061: private static final Class[] JDK14_GST_METHOD_ARGS = new Class[0];
062:
063: private static final String JDK14_GC_METHOD = "getCause";
064: private static final Class[] JDK14_GC_METHOD_ARGS = new Class[0];
065:
066: /**
067: * Only piecemeal iterates through the stack-trace. Supports the JDK 1.4
068: * StackTraceElement class.
069: */
070: public ThrowableParser(Throwable t) {
071: if (t == null) {
072: throw new IllegalArgumentException("no null arguments");
073: }
074: parseThrowable(t);
075: }
076:
077: /**
078: * @return <tt>null</tt> if there are no more lines, or the next line
079: * in the list.
080: */
081: public synchronized StackTraceLineParser next() {
082: if (this .traceList != null) {
083: return next14();
084: }
085:
086: // else
087: return next11();
088: }
089:
090: //-------------------------------------------------------------------------
091:
092: /**
093: *
094: */
095: protected StackTraceLineParser next11() {
096: //LOG.debug( "finding next stack trace line for JDK 1.1+" );
097: while (true) {
098: String line;
099: try {
100: line = this .traceReader.readLine();
101: //LOG.debug("trace line = '"+line+"'");
102: } catch (java.io.IOException ioe) {
103: throw new IllegalStateException(
104: "Never supposed to happen: " + ioe);
105: }
106: if (line == null) {
107: //LOG.debug("end-of-stack trace.");
108: return null;
109: }
110: try {
111: StackTraceLineParser stlp = new StackTraceLineParser(
112: line);
113:
114: // found a valid line
115: return stlp;
116: } catch (Exception e) {
117: // not a valid line. Continue.
118: //LOG.debug(" - not a valid line",e);
119: }
120: }
121: }
122:
123: /**
124: *
125: */
126: protected StackTraceLineParser next14() {
127: //LOG.debug( "finding next stack trace line for JDK 1.4+" );
128: if (this .traceIndex >= this .traceList.length) {
129: return null;
130: }
131:
132: // this will throw an exception if the parser does not know this
133: // type. That's fine. That will show a bug in this implementation.
134: StackTraceLineParser stlp = new StackTraceLineParser(
135: this .traceList[this .traceIndex]);
136: ++this .traceIndex;
137:
138: return stlp;
139: }
140:
141: protected void parseThrowable(Throwable t) {
142: try {
143: // Construct the trace from the complete trace chain.
144: Vector trace = new Vector();
145: while (t != null) {
146: Class c = t.getClass();
147: Method m = c.getDeclaredMethod(JDK14_GST_METHOD,
148: JDK14_GST_METHOD_ARGS);
149: Object[] o = (Object[]) m.invoke(t, null);
150: if (o != null) {
151: for (int i = 0; i < o.length; ++i) {
152: trace.addElement(o[i]);
153: }
154: }
155:
156: // find cause of t
157: m = c.getDeclaredMethod(JDK14_GC_METHOD,
158: JDK14_GC_METHOD_ARGS);
159: t = (Throwable) m.invoke(t, null);
160: }
161:
162: Object[] o = new Object[trace.size()];
163: trace.copyInto(o);
164: this .traceList = o;
165: this .traceIndex = 0;
166:
167: //LOG.info("Parsing: using JDK 1.4 method.");
168: } catch (ThreadDeath td) {
169: // don't ever gulp these
170: throw td;
171: } catch (Throwable th) {
172: // use JDK 1.1+ compatible method
173: parseThrowableBuffer(t);
174: }
175: }
176:
177: protected void parseThrowableBuffer(Throwable t) {
178: //LOG.info("Parsing: reverted to JDK 1.1 compatible method.");
179:
180: StringWriter sw = new StringWriter();
181: t.printStackTrace(new PrintWriter(sw));
182: StringReader sr = new StringReader(sw.toString());
183: this .traceReader = new BufferedReader(sr);
184: }
185: }
|