package org.limewire.util; /** * A Runnable that keeps the stack trace from when * it was created, so that an exception thrown while * running from another thread can keep the created stack trace. */ public class DebugRunnable implements Runnable { private final Exception creationTime; private final Runnable delegate; public DebugRunnable(Runnable runner) { this.creationTime = new Exception("Debug Exception Creation"); this.delegate = runner; // Drop this line from the creationTime trace.. StackTraceElement[] trace = creationTime.getStackTrace(); StackTraceElement[] newTrace = new StackTraceElement[trace.length - 1]; System.arraycopy(trace, 1, newTrace, 0, newTrace.length); creationTime.setStackTrace(newTrace); } public final void run() { boolean setStackTrace = true; try { delegate.run(); } catch(Throwable t) { if(t.getCause() == null) { try { t.initCause(creationTime); setStackTrace = false; } catch (IllegalStateException ise) { // thrown if throwable was initialized with null cause for some reason } } if (setStackTrace) { // If it already had a cause, all we can do is manipulate the StackTraceElement[] StackTraceElement[] trace = t.getStackTrace(); StackTraceElement[] createdTrace = creationTime.getStackTrace(); StackTraceElement[] combinedTrace = new StackTraceElement[trace.length + createdTrace.length]; System.arraycopy(trace, 0, combinedTrace, 0, trace.length); System.arraycopy(createdTrace, 0, combinedTrace, trace.length, createdTrace.length); t.setStackTrace(combinedTrace); } if(t instanceof Error) throw (Error)t; else if(t instanceof RuntimeException) throw (RuntimeException)t; else throw new RuntimeException(t); } } }