001: /* ====================================================================
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1997-2003 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution,
020: * if any, must include the following acknowledgment:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowledgment may appear in the software
024: * itself, if and wherever such third-party acknowledgments
025: * normally appear.
026: *
027: * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
028: * must not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation. For more
052: * information on the Apache Software Foundation, please see
053: * <http://www.apache.org/>.
054: */
055: package org.apache.log.format;
056:
057: import java.io.PrintWriter;
058: import java.io.StringWriter;
059: import java.lang.reflect.Method;
060: import java.util.StringTokenizer;
061:
062: /**
063: * This class provides basic facilities for manipulating exceptions.
064: *
065: * Some exception handling stuff thieved from Turbine...
066: *
067: * @deprecated use org.apache.avalon.framework.ExceptionUtil instead
068: *
069: * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
070: * @version 1.0
071: */
072: final class ExceptionUtil {
073: private static final String LINE_SEPARATOR = System
074: .getProperty("line.separator");
075: private static final String GET_CAUSE_NAME = "getCause";
076: private static final Class[] GET_CAUSE_PARAMTYPES = new Class[0];
077: private static final Class CASCADING_INTERFACE;
078:
079: static {
080: Class klass = null;
081: try {
082: klass = Class
083: .forName("org.apache.avalon.framework.CascadingThrowable");
084: } catch (Exception e) {
085: // class not available
086: klass = null;
087: }
088:
089: CASCADING_INTERFACE = klass;
090: }
091:
092: /**
093: * Private constructor to prevent instantiation.
094: */
095: private ExceptionUtil() {
096: }
097:
098: /**
099: * Generate string for specified exception and the cause of
100: * this exception (if any).
101: * @param throwable a <code>Throwable</code>
102: * @return the stack trace as a <code>String</code>
103: */
104: public static String printStackTrace(final Throwable throwable) {
105: return printStackTrace(throwable, 0, true);
106: }
107:
108: /**
109: * Generate string for specified exception and if printCascading
110: * is true will print all cascading exceptions.
111: * @param throwable a <code>Throwable</code>
112: * @param printCascading if <code>true</code> will print all cascading exceptions
113: * @return the stack trace as a <code>String</code>
114: */
115: public static String printStackTrace(final Throwable throwable,
116: final boolean printCascading) {
117: return printStackTrace(throwable, 0, printCascading);
118: }
119:
120: /**
121: * Serialize the specified <code>Throwable</code> to a string.
122: * Restrict the number of frames printed out to the specified depth.
123: * If the depth specified is <code>0</code> then all the frames are
124: * converted into a string.
125: * @param throwable a <code>Throwable</code>
126: * @param depth number of stack trace frames to show
127: * @return the stack trace as a <code>String</code>
128: */
129: public static String printStackTrace(final Throwable throwable,
130: final int depth) {
131: int dp = depth;
132: final String[] lines = captureStackTrace(throwable);
133:
134: if (0 == dp || dp > lines.length) {
135: dp = lines.length;
136: }
137:
138: final StringBuffer sb = new StringBuffer();
139:
140: for (int i = 0; i < dp; i++) {
141: sb.append(lines[i]);
142: sb.append(LINE_SEPARATOR);
143: }
144:
145: return sb.toString();
146: }
147:
148: /**
149: * Generate exception string for specified exception to specified depth
150: * and all Cascading exceptions if printCascading is true.
151: * @param throwable a <code>Throwable</code>
152: * @param depth number of stack trace frames to show
153: * @param printCascading if <code>true</code> will print all cascading exceptions
154: * @return the stack trace as a <code>String</code>
155: */
156: public static String printStackTrace(final Throwable throwable,
157: final int depth, final boolean printCascading) {
158: return printStackTrace(throwable, depth, printCascading, true);
159: }
160:
161: /**
162: * Generate exception string for specified exception to specified depth
163: * and all Cascading exceptions if printCascading is true. If useReflection
164: * is true then the method will also attempt to use reflection to find a
165: * method with signature <code>Throwable getCause()</code>. This makes
166: * it compatible with JDK1.4 mechanisms for nesting exceptions.
167: * @param throwable a <code>Throwable</code>
168: * @param depth number of stack trace frames to show
169: * @param printCascading if <code>true</code> will print all cascading exceptions
170: * @param useReflection if <code>true</code> will use reflection to handle JDK1.4
171: * nested exceptions
172: * @return the stack trace as a <code>String</code>
173: */
174: public static String printStackTrace(final Throwable throwable,
175: final int depth, final boolean printCascading,
176: final boolean useReflection) {
177: final String result = printStackTrace(throwable, depth);
178:
179: if (!printCascading) {
180: return result;
181: } else {
182: final StringBuffer sb = new StringBuffer();
183: sb.append(result);
184:
185: Throwable cause = getCause(throwable, useReflection);
186:
187: while (null != cause) {
188: sb.append("rethrown from");
189: sb.append(LINE_SEPARATOR);
190: sb.append(printStackTrace(cause, depth));
191:
192: cause = getCause(cause, useReflection);
193: }
194:
195: return sb.toString();
196: }
197: }
198:
199: /**
200: * Utility method to get cause of exception.
201: * @param throwable a <code>Throwable</code>
202: * @param useReflection if <code>true</code> will use reflection to handle JDK1.4
203: * nested exceptions
204: * @return cause of specified exception
205: */
206: public static Throwable getCause(final Throwable throwable,
207: final boolean useReflection) {
208: if (useReflection
209: || (null != CASCADING_INTERFACE && CASCADING_INTERFACE
210: .isAssignableFrom(throwable.getClass()))) {
211: try {
212: final Class clazz = throwable.getClass();
213: final Method method = clazz.getMethod(GET_CAUSE_NAME,
214: GET_CAUSE_PARAMTYPES);
215: return (Throwable) method.invoke(throwable, null);
216: } catch (final Throwable t) {
217: return null;
218: }
219: } else {
220: return null;
221: }
222: }
223:
224: /**
225: * Captures the stack trace associated with this exception.
226: *
227: * @param throwable a <code>Throwable</code>
228: * @return an array of Strings describing stack frames.
229: */
230: public static String[] captureStackTrace(final Throwable throwable) {
231: final StringWriter sw = new StringWriter();
232: throwable.printStackTrace(new PrintWriter(sw, true));
233: return splitStringInternal(sw.toString(), LINE_SEPARATOR);
234: }
235:
236: /**
237: * Splits the string on every token into an array of stack frames.
238: *
239: * @param string the string to split
240: * @param onToken the token to split on
241: * @return the resultant array
242: * @deprecated This is an internal utility method that should not be used
243: */
244: public static String[] splitString(final String string,
245: final String onToken) {
246: return splitStringInternal(string, onToken);
247: }
248:
249: /**
250: * Splits the string on every token into an array of stack frames.
251: *
252: * @param string the string to split
253: * @param onToken the token to split on
254: * @return the resultant array
255: */
256: private static String[] splitStringInternal(final String string,
257: final String onToken) {
258: final StringTokenizer tokenizer = new StringTokenizer(string,
259: onToken);
260: final String[] result = new String[tokenizer.countTokens()];
261:
262: for (int i = 0; i < result.length; i++) {
263: result[i] = tokenizer.nextToken();
264: }
265:
266: return result;
267: }
268: }
|