/* * Copyright 2010 Outerthought bvba * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.lilyproject.util.exception; import java.io.PrintStream; import java.util.Arrays; import java.util.List; /** * Print stack traces with knowledge about {@link RemoteThrowableInfo}. */ public class StackTracePrinter { private StackTracePrinter() { } public static void printStackTrace(Throwable throwable) { printStackTrace(throwable, System.err); } public static void printStackTrace(Throwable throwable, PrintStream ps) { ps.println(getClassName(throwable) + ": " + getMessage(throwable)); printRemoteWarning(throwable, ps); List<StackTraceElement> trace = getStackTrace(throwable); for (StackTraceElement aTrace : trace) { ps.println("\tat " + aTrace); } printNestedStackTrace(throwable, ps); } private static void printNestedStackTrace(Throwable throwable, PrintStream ps) { Throwable cause = throwable.getCause(); if (cause == null) { return; } ps.println(getClassName(cause) + ": " + getMessage(cause)); printRemoteWarning(cause, ps); List<StackTraceElement> parentTrace = getStackTrace(throwable); List<StackTraceElement> causeTrace = getStackTrace(cause); int i = parentTrace.size() - 1; int j = causeTrace.size() - 1; for (; i >= 0 && j >= 0; i--, j--) { if (!parentTrace.get(i).equals(causeTrace.get(j))) { break; } } for (int k = 0; k < j + 1; k++) { ps.println("\tat " + causeTrace.get(k)); } int common = parentTrace.size() - (i + 1); if (common > 0) { ps.println("\t... " + common + " more"); } printNestedStackTrace(cause, ps); } private static void printRemoteWarning(Throwable throwable, PrintStream ps) { if (throwable instanceof RemoteThrowableInfo) { ps.println("\tWARNING: This is reproduced information of a remote exception."); ps.println("\t This exception did not occur in this JVM!"); } } private static List<StackTraceElement> getStackTrace(Throwable throwable) { if (throwable instanceof RemoteThrowableInfo) { return ((RemoteThrowableInfo)throwable).getOriginalStackTrace(); } else { return Arrays.asList(throwable.getStackTrace()); } } private static String getClassName(Throwable throwable) { if (throwable instanceof RemoteThrowableInfo) { return ((RemoteThrowableInfo)throwable).getOriginalClass(); } else { return throwable.getClass().getName(); } } private static String getMessage(Throwable throwable) { if (throwable instanceof RemoteThrowableInfo) { return ((RemoteThrowableInfo)throwable).getOriginalMessage(); } else { return throwable.getMessage(); } } }