package com.waldura.util; import java.io.PrintWriter; import java.io.StringWriter; /** * This exception allows for error chaining. It embeds ("nests") another * exception, assigned at construction time. The nested exception is used * for the {@link #getMessage() error message} generated by this class, * as well as its {@link #getChainedStackTrace() stack trace}. *
* Use this class to promote encapsulation and loose coupling between
* sub-systems.
* IMO, every logical subsystem should have very few "exit points" for propagating
* errors, and these points should re-type errors to their own type
* before propagating them.
* Doing so by creating a new exception and throwing it results in lost
* information; the ChainingException class lets you propagate
* the error as a new type without losing the original error.
*
* This class is declared abstract; while it doesn't actually
* have any abstract methods,
* it is meant to be extended and used as base for a custom exception.
* For example, a database management subsystem could
* throw its own DatabaseException and chain to the actual
* SQLException that generated the error.
* The DatabaseException class could be written like so:
*
* class DatabaseException extends ChainingException
* {
* public DatabaseException() {}
* public DatabaseException(String mesg) { super(mesg); }
* public DatabaseException(SQLException chainedError) { super(chainedError); }
* public DatabaseException(String mesg, SQLException chainedError) { super(mesg, chainedError); }
* }
*
* * Note 1 *
* This class, contrarily to the basic {@link java.lang.Exception Exception} * class, is fully serializable. The nested exception's stack trace is * saved and can be retrieved by remote users of this class. *
* Note 2 *
* This class has been integrated in JDK 1.4.
*
* @author Renaud Waldura 7/11/00
* @author Quenio dos Santos 10/01/01
*/
public abstract class ChainingException
extends Exception
{
/**
* The error that originally caused this Exception object to be thrown.
*/
private Throwable chainedException;
/**
* Instantiates this exception with no message and no chained exception.
*/
public ChainingException()
{
this(null, null);
}
/**
* Instantiates this exception with a message, but no chained exception.
*
* @param message The message that explains what is this exception.
*/
public ChainingException(String message)
{
this(message, null);
}
/**
* Instantiates this exception with a chained exception, but no message.
*
* @param nestedException the error that originally caused
* this Exception object to be thrown.
*/
public ChainingException(Throwable chainedException)
{
this(null, chainedException);
}
/**
* Instantiates this exception with a message and a chained exception.
*
* @param message The message that explains what is this exception.
* @param nestedException The error that originally caused
* this Exception object to be thrown.
*/
public ChainingException(String message, Throwable chainedException)
{
super(message);
this.chainedException = chainedException;
}
/**
* @return the Exception object that originally caused this
* Exception object to be thrown.
*/
public Throwable getChainedException()
{
return chainedException;
}
/**
* Returns the stack trace of all chained exceptions, showing the stack
* trace of this exception (which is the outermost exception) first and
* the innermost stack trace last.
*/
public String getChainedStackTrace()
{
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
super.printStackTrace(printWriter);
if (chainedException != null)
{
printWriter.println("<><><><><>< chained to ><><><><><>");
chainedException.printStackTrace(printWriter);
}
return stringWriter.toString();
}
/**
* Print this Throwable and its stack trace to the standard
* error stream.
*/
public void printStackTrace()
{
printStackTrace(System.err);
}
/**
* Prints this exception and its backtrace to the specified
* print stream.
*/
public void printStackTrace(java.io.PrintStream s)
{
s.println(getChainedStackTrace());
}
/**
* Prints this exception and its backtrace to the specified
* print writer.
*/
public void printStackTrace(java.io.PrintWriter s)
{
s.println(getChainedStackTrace());
}
/**
* Overrides {@link Exception#getMessage() Exception.getMessage} to
* return a concatenation of all of the chained exceptions' messages.
*/
public String getMessage()
{
String superMesg = super.getMessage();
// default
if (chainedException == null) return superMesg;
StringBuffer mesg = new StringBuffer();
// get the chained exception's message
String chainedMesg = chainedException.getMessage();
if (superMesg != null)
mesg.append(superMesg).append(": ").append(chainedMesg);
else
mesg.append(chainedMesg);
return mesg.toString();
}
}