| /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under |
| * the terms of the Common Public License v1.0 which accompanies this distribution, |
| * and is available at http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * $Id: AbstractRuntimeException.java,v 1.1.1.1 2004/05/09 16:57:57 vlad_r Exp $ |
| */ |
| package com.vladium.util.exception; |
| |
| import java.io.IOException; |
| import java.io.ObjectOutputStream; |
| import java.io.PrintStream; |
| import java.io.PrintWriter; |
| |
| // ---------------------------------------------------------------------------- |
| /** |
| * Based on code published by me in <a href="http://www.fawcette.com/javapro/2002_12/online/exception_vroubtsov_12_16_02/default_pf.asp">JavaPro, 2002</a>.<P> |
| * |
| * This unchecked exception class is designed as a base/expansion point for the |
| * entire hierarchy of unchecked exceptions in a project.<P> |
| * |
| * It provides the following features: |
| * <UL> |
| * <LI> ability to take in compact error codes that map to full text messages |
| * in a resource bundle loaded at this class' instantiation time. This avoids |
| * hardcoding the error messages in product code and allows for easy |
| * localization of such text if required. Additionally, these messages |
| * can be parametrized in the java.text.MessageFormat style; |
| * <LI> exception chaining in J2SE versions prior to 1.4 |
| * </UL> |
| * |
| * See {@link AbstractException} for a checked version of the same class.<P> |
| * |
| * TODO: javadoc |
| * |
| * Each constructor that accepts a String 'message' parameter accepts an error |
| * code as well. You are then responsible for ensuring that either the root |
| * <CODE>com.vladium.exception.exceptions</CODE> resource bundle |
| * or your project/exception class-specific resource bundle [see |
| * <A HREF="#details">below</A> for details] contains a mapping for this error |
| * code. When this lookup fails the passed String value itself will be used as |
| * the error message.<P> |
| * |
| * All constructors taking an 'arguments' parameter supply parameters to the error |
| * message used as a java.text.MessageFormat pattern.<P> |
| * |
| * Example: |
| * <PRE><CODE> |
| * File file = ... |
| * try |
| * ... |
| * catch (Exception e) |
| * { |
| * throw new AbstractRuntimeException ("FILE_NOT_FOUND", new Object[] {file, e}, e); |
| * } |
| * </CODE></PRE> |
| * where <CODE>com.vladium.util.exception.exceptions</CODE> contains: |
| * <PRE><CODE> |
| * FILE_NOT_FOUND: file {0} could not be opened: {1} |
| * </CODE></PRE> |
| * |
| * To log exception data use {@link #getMessage} or <CODE>printStackTrace</CODE> |
| * family of methods. You should never have to use toString().<P> |
| * |
| * <A NAME="details"> It is also possible to use project- or exception |
| * subhierarchy-specific message resource bundles without maintaining all error |
| * codes in <CODE>com.vladium.exception.exceptions</CODE>. To do so, create a |
| * custom resource bundle and add the following static initializer code to your |
| * base exception class: |
| * <PRE><CODE> |
| * static |
| * { |
| * addExceptionResource (MyException.class, "my_custom_resource_bundle"); |
| * } |
| * </CODE></PRE> |
| * The bundle name is relative to MyException package. This step can omitted if |
| * the bundle name is "exceptions". |
| * |
| * Note that the implementation correctly resolves error code name collisions |
| * across independently developed exception families, as long as resource bundles |
| * use unique names. Specifically, error codes follow inheritance and hiding rules |
| * similar to Java class static methods. See {@link ExceptionCommon#addExceptionResource} |
| * for further details. |
| * |
| * @author Vlad Roubtsov, (C) 2002 |
| */ |
| public |
| abstract class AbstractRuntimeException extends RuntimeException implements ICodedException, IThrowableWrapper |
| { |
| // public: ................................................................ |
| |
| /** |
| * Constructs an exception with null message and null cause. |
| */ |
| public AbstractRuntimeException () |
| { |
| m_cause = null; |
| m_arguments = null; |
| } |
| |
| /** |
| * Constructs an exception with given error message/code and null cause. |
| * |
| * @param message the detail message [can be null] |
| */ |
| public AbstractRuntimeException (final String message) |
| { |
| super (message); |
| m_cause = null; |
| m_arguments = null; |
| } |
| |
| /** |
| * Constructs an exception with given error message/code and null cause. |
| * |
| * @param message the detail message [can be null] |
| * @param arguments message format parameters [can be null or empty] |
| * |
| * @see java.text.MessageFormat |
| */ |
| public AbstractRuntimeException (final String message, final Object [] arguments) |
| { |
| super (message); |
| m_cause = null; |
| m_arguments = arguments == null ? null : (Object []) arguments.clone (); |
| } |
| |
| /** |
| * Constructs an exception with null error message/code and given cause. |
| * |
| * @param cause the cause [nested exception] [can be null] |
| */ |
| public AbstractRuntimeException (final Throwable cause) |
| { |
| super (); |
| m_cause = cause; |
| m_arguments = null; |
| } |
| |
| /** |
| * Constructs an exception with given error message/code and given cause. |
| * |
| * @param message the detail message [can be null] |
| * @param cause the cause [nested exception] [can be null] |
| */ |
| public AbstractRuntimeException (final String message, final Throwable cause) |
| { |
| super (message); |
| m_cause = cause; |
| m_arguments = null; |
| } |
| |
| /** |
| * Constructs an exception with given error message/code and given cause. |
| * |
| * @param message the detail message [can be null] |
| * @param arguments message format parameters [can be null or empty] |
| * @param cause the cause [nested exception] [can be null] |
| * |
| * @see java.text.MessageFormat |
| */ |
| public AbstractRuntimeException (final String message, final Object [] arguments, final Throwable cause) |
| { |
| super (message); |
| m_cause = cause; |
| m_arguments = arguments == null ? null : (Object []) arguments.clone (); |
| } |
| |
| |
| /** |
| * Overrides base method to support error code lookup and avoid returning nulls. |
| * Note that this does not recurse into any 'cause' for message lookup, it only |
| * uses the data passed into the constructor. Subclasses cannot override.<P> |
| * |
| * Equivalent to {@link #getLocalizedMessage}. |
| * |
| * @return String error message provided at construction time or the result |
| * of toString() if no/null message was provided [never null]. |
| */ |
| public final String getMessage () |
| { |
| if (m_message == null) // not synchronized by design |
| { |
| String msg; |
| final String supermsg = super.getMessage (); |
| final Class _class = getClass (); |
| |
| if (m_arguments == null) |
| { |
| msg = ExceptionCommon.getMessage (_class, supermsg); |
| } |
| else |
| { |
| msg = ExceptionCommon.getMessage (_class, supermsg, m_arguments); |
| } |
| |
| if (msg == null) |
| { |
| // this is the same as what's done in Throwable.toString() [copied here to be independent of future JDK changes] |
| final String className = _class.getName (); |
| |
| msg = (supermsg != null) ? (className + ": " + supermsg) : className; |
| } |
| |
| m_message = msg; |
| } |
| |
| return m_message; |
| } |
| |
| /** |
| * Overrides base method for the sole purpose of making it final.<P> |
| * |
| * Equivalent to {@link #getMessage}. |
| */ |
| public final String getLocalizedMessage () |
| { |
| // this is the same as what's done in Throwable |
| // [copied here to be independent of future JDK changes] |
| return getMessage (); |
| } |
| |
| /** |
| * Overrides Exception.printStackTrace() to (a) force the output to go |
| * to System.out and (b) handle nested exceptions in JDKs prior to 1.4.<P> |
| * |
| * Subclasses cannot override. |
| */ |
| public final void printStackTrace () |
| { |
| // NOTE: unlike the JDK implementation, force the output to go to System.out: |
| ExceptionCommon.printStackTrace (this, System.out); |
| } |
| |
| /** |
| * Overrides Exception.printStackTrace() to handle nested exceptions in JDKs prior to 1.4.<P> |
| * |
| * Subclasses cannot override. |
| */ |
| public final void printStackTrace (final PrintStream s) |
| { |
| ExceptionCommon.printStackTrace (this, s); |
| } |
| |
| /** |
| * Overrides Exception.printStackTrace() to handle nested exceptions in JDKs prior to 1.4.<P> |
| * |
| * Subclasses cannot override. |
| */ |
| public final void printStackTrace (final PrintWriter s) |
| { |
| ExceptionCommon.printStackTrace (this, s); |
| } |
| |
| // ICodedException: |
| |
| /** |
| * Returns the String that was passed as 'message' constructor argument. |
| * Can be null. |
| * |
| * @return message code string [can be null] |
| */ |
| public final String getErrorCode () |
| { |
| return super.getMessage (); |
| } |
| |
| // IThrowableWrapper: |
| |
| /** |
| * This implements {@link IThrowableWrapper} |
| * and also overrides the base method in JDK 1.4+. |
| */ |
| public final Throwable getCause () |
| { |
| return m_cause; |
| } |
| |
| public void __printStackTrace (final PrintStream ps) |
| { |
| super.printStackTrace (ps); |
| } |
| |
| public void __printStackTrace (final PrintWriter pw) |
| { |
| super.printStackTrace (pw); |
| } |
| |
| /** |
| * Equivalent to {@link ExceptionCommon#addExceptionResource}, repeated here for |
| * convenience. Subclasses should invoke from static initializers <I>only</I>. |
| * 'namespace' should be YourException.class. |
| */ |
| public static void addExceptionResource (final Class namespace, |
| final String messageResourceBundleName) |
| { |
| // note: 'namespace' will be the most derived class; it is possible to |
| // auto-detect that in a static method but that requires some security |
| // permissions |
| ExceptionCommon.addExceptionResource (namespace, messageResourceBundleName); |
| } |
| |
| // protected: ............................................................. |
| |
| // package: ............................................................... |
| |
| // private: ............................................................... |
| |
| |
| /* |
| * Ensures that this instance can be serialized even if some message parameters |
| * are not serializable objects. |
| */ |
| private void writeObject (final ObjectOutputStream out) |
| throws IOException |
| { |
| getMessage (); // transform this instance to serializable form |
| out.defaultWriteObject (); |
| } |
| |
| |
| private String m_message; // marshalled/cached result of getMessage() |
| private transient final Object [] m_arguments; |
| // note: this field duplicates functionality available in stock Throwable in JRE 1.4+ |
| private final Throwable m_cause; |
| |
| } // end of class |
| // ---------------------------------------------------------------------------- |