File: AbstractRuntimeException.java

package info (click to toggle)
emma-coverage 2.0.5312%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,000 kB
  • ctags: 3,667
  • sloc: java: 23,109; xml: 414; makefile: 22
file content (329 lines) | stat: -rw-r--r-- 11,622 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/* 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
// ----------------------------------------------------------------------------