001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.core.util;
017:
018: import javax.servlet.ServletException;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.impl.Log4JLogger;
022: import org.apache.log4j.Logger;
023:
024: /**
025: * Adapts Exception.print stack trace to print its output to a Logger.
026: *
027: *
028: */
029: public class ExceptionUtils {
030:
031: /**
032: * Logs the stack trace of the given throwable to the given logger.
033: *
034: * @param logger
035: * @param t
036: */
037: public static void logStackTrace(Logger logger, Throwable t) {
038: Log log = new Log4JLogger(logger);
039: logStackTrace(log, t);
040: }
041:
042: /**
043: * Logs the stack trace of the given throwable to the given logger.
044: *
045: * @param log
046: * @param t
047: */
048: public static void logStackTrace(Log log, Throwable t) {
049: StackTraceElement[] elements = t.getStackTrace();
050:
051: StringBuffer trace = new StringBuffer();
052: trace.append(t.getClass().getName());
053:
054: if (t.getMessage() != null) {
055: trace.append(": ");
056: trace.append(t.getMessage());
057: }
058:
059: trace.append("\n");
060:
061: for (int i = 0; i < elements.length; ++i) {
062: StackTraceElement element = elements[i];
063:
064: trace.append(" at ");
065: trace.append(describeStackTraceElement(element));
066: trace.append("\n");
067: }
068:
069: log.error(trace.toString());
070: }
071:
072: /**
073: * @param level
074: * @return String containing the name of the method at the given level from the top of the stack
075: */
076: public static String describeStackLevel(Throwable t, int level) {
077: return describeStackLevels(t, level + 1, level + 1);
078: }
079:
080: /**
081: * @param fromLevel
082: * @param toLevel
083: * @return String containing the names of the methods at the given levels from the top of the stack
084: */
085: public static String describeStackLevels(Throwable t,
086: int fromLevel, int toLevel) {
087: if (fromLevel <= 0) {
088: throw new IllegalArgumentException("invalid fromLevel ("
089: + fromLevel + " < 0)");
090: }
091: if (fromLevel > toLevel) {
092: throw new IllegalArgumentException(
093: "invalid levels (fromLevel " + fromLevel
094: + " > toLevel " + toLevel + ")");
095: }
096:
097: StackTraceElement[] elements = t.getStackTrace();
098: int stackHeight = elements.length;
099: if (toLevel >= elements.length) {
100: throw new IllegalArgumentException("invalid toLevel ("
101: + toLevel + " >= " + stackHeight + ")");
102: }
103:
104: StringBuffer result = new StringBuffer();
105: for (int level = fromLevel; level <= toLevel; level++) {
106: if (result.length() > 0) {
107: result.append(" from ");
108: }
109: result.append(describeStackTraceElement(elements[level]));
110: }
111: return result.toString();
112: }
113:
114: /**
115: * @param level
116: * @return String containing the name of the method at the given level from the top of the stack (not including this method)
117: */
118: public static String describeStackLevel(int level) {
119: return describeStackLevels(level + 1, level + 1);
120: }
121:
122: /**
123: * @param fromLevel
124: * @param toLevel
125: * @return String containing the names of the methods at the given levels from the top of the stack (not including this method)
126: */
127: public static String describeStackLevels(int fromLevel, int toLevel) {
128: String description = null;
129: try {
130: throw new RuntimeException("hack");
131: } catch (RuntimeException e) {
132: description = describeStackLevels(e, fromLevel + 1,
133: toLevel + 1);
134: }
135:
136: return description;
137: }
138:
139: /**
140: * @param element
141: * @return String describing the given StackTraceElement
142: */
143: private static String describeStackTraceElement(
144: StackTraceElement element) {
145: if (element == null) {
146: throw new IllegalArgumentException("invalid (null) element");
147: }
148:
149: StringBuffer description = new StringBuffer();
150:
151: description.append(element.getClassName());
152: description.append(".");
153: description.append(element.getMethodName());
154: description.append("(");
155: description.append(element.getFileName());
156: description.append(":");
157: description.append(element.getLineNumber());
158: description.append(")");
159:
160: return description.toString();
161: }
162:
163: /**
164: * Initializes the JDK 1.4 cause of any ServletExceptions in the given cause chain. This is a work-around for the lack of
165: * support in the Servlet 2.4 API and Tomcat 5. It allows anything using Throwable.printStackTrace() (e.g., log4j) to include
166: * the cause chain. If a ServletException has a rootCause but it's JDK 1.4 cause has already been initialized to null, then the
167: * chain ends there. I think Tomcat's exception logging goes beyond this, to follow cause or rootCause depending on the
168: * Exception's type and log each one individually instead of using Throwable.printStackTrace(). But that only helps Tomcat's log
169: * file.
170: *
171: * @param t the head of the cause chain to initialize
172: */
173: public void initServletExceptionCauses(Throwable t) {
174: while (t != null) {
175: if (t instanceof ServletException) {
176: ServletException se = (ServletException) t;
177: try {
178: // Convert Servlet 2.4 API cause to JDK 1.4 cause.
179: se.initCause(se.getRootCause());
180: } catch (IllegalStateException e) {
181: // Okay, the cause was already initialized.
182: // (IllegalStateException is the only way to distinguish from being initialized to null.)
183: }
184: }
185: t = t.getCause();
186: }
187: }
188: }
|