View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math;
18  
19  import java.io.EOFException;
20  import java.io.IOException;
21  import java.io.PrintStream;
22  import java.io.PrintWriter;
23  import java.text.MessageFormat;
24  import java.text.ParseException;
25  import java.util.ConcurrentModificationException;
26  import java.util.Locale;
27  import java.util.MissingResourceException;
28  import java.util.NoSuchElementException;
29  import java.util.ResourceBundle;
30  
31  /**
32  * Base class for commons-math unchecked exceptions.
33  * 
34  * @version $Revision: 786478 $ $Date: 2009-06-19 08:33:36 -0400 (Fri, 19 Jun 2009) $
35  * @since 2.0
36  */
37  public class MathRuntimeException extends RuntimeException {
38      
39      /** Serializable version identifier. */
40      private static final long serialVersionUID = -5128983364075381060L;
41  
42      /**
43       * Pattern used to build the message.
44       */
45      private final String pattern;
46  
47      /**
48       * Arguments used to build the message.
49       */
50      private final Object[] arguments;
51  
52      /**
53       * Translate a string to a given locale.
54       * @param s string to translate
55       * @param locale locale into which to translate the string
56       * @return translated string or original string
57       * for unsupported locales or unknown strings
58       */
59      private static String translate(final String s, final Locale locale) {
60          try {
61              ResourceBundle bundle =
62                      ResourceBundle.getBundle("org.apache.commons.math.MessagesResources", locale);
63              if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
64                  // the value of the resource is the translated string
65                  return bundle.getString(s);
66              }
67              
68          } catch (MissingResourceException mre) {
69              // do nothing here
70          }
71  
72          // the locale is not supported or the resource is unknown
73          // don't translate and fall back to using the string as is
74          return s;
75  
76      }
77  
78      /**
79       * Builds a message string by from a pattern and its arguments.
80       * @param locale Locale in which the message should be translated
81       * @param pattern format specifier
82       * @param arguments format arguments
83       * @return a message string
84       */
85      private static String buildMessage(final Locale locale, final String pattern,
86                                         final Object ... arguments) {
87          return (pattern == null) ? "" : new MessageFormat(translate(pattern, locale), locale).format(arguments);        
88      }
89  
90      /**
91       * Constructs a new <code>MathRuntimeException</code> with specified
92       * formatted detail message.
93       * Message formatting is delegated to {@link java.text.MessageFormat}.
94       * @param pattern format specifier
95       * @param arguments format arguments
96       */
97      public MathRuntimeException(final String pattern, final Object ... arguments) {
98        super(buildMessage(Locale.US, pattern, arguments));
99        this.pattern   = pattern;
100       this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
101     }
102 
103     /**
104      * Constructs a new <code>MathRuntimeException</code> with specified
105      * nested <code>Throwable</code> root cause.
106      *
107      * @param rootCause  the exception or error that caused this exception
108      *                   to be thrown.
109      */
110     public MathRuntimeException(final Throwable rootCause) {
111         super(rootCause);
112         this.pattern   = getMessage();
113         this.arguments = new Object[0];
114     }
115     
116     /**
117      * Constructs a new <code>MathRuntimeException</code> with specified
118      * formatted detail message and nested <code>Throwable</code> root cause.
119      * Message formatting is delegated to {@link java.text.MessageFormat}.
120      * @param rootCause the exception or error that caused this exception
121      * to be thrown.
122      * @param pattern format specifier
123      * @param arguments format arguments
124      */
125     public MathRuntimeException(final Throwable rootCause,
126                                 final String pattern, final Object ... arguments) {
127       super(buildMessage(Locale.US, pattern, arguments), rootCause);
128       this.pattern   = pattern;
129       this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
130     }
131 
132     /** Gets the pattern used to build the message of this throwable.
133      *
134      * @return the pattern used to build the message of this throwable
135      */
136     public String getPattern() {
137         return pattern;
138     }
139 
140     /** Gets the arguments used to build the message of this throwable.
141      *
142      * @return the arguments used to build the message of this throwable
143      */
144     public Object[] getArguments() {
145         return arguments.clone();
146     }
147 
148     /** Gets the message in a specified locale.
149      *
150      * @param locale Locale in which the message should be translated
151      * 
152      * @return localized message
153      */
154     public String getMessage(final Locale locale) {
155         return buildMessage(locale, pattern, arguments);
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public String getLocalizedMessage() {
161         return getMessage(Locale.getDefault());
162     }
163 
164     /**
165      * Prints the stack trace of this exception to the standard error stream.
166      */
167     @Override
168     public void printStackTrace() {
169         printStackTrace(System.err);
170     }
171     
172     /**
173      * Prints the stack trace of this exception to the specified stream.
174      *
175      * @param out  the <code>PrintStream</code> to use for output
176      */
177     @Override
178     public void printStackTrace(final PrintStream out) {
179         synchronized (out) {
180             PrintWriter pw = new PrintWriter(out, false);
181             printStackTrace(pw);
182             // Flush the PrintWriter before it's GC'ed.
183             pw.flush();
184         }
185     }
186 
187     /**
188      * Constructs a new <code>ArithmeticException</code> with specified formatted detail message.
189      * Message formatting is delegated to {@link java.text.MessageFormat}.
190      * @param pattern format specifier
191      * @param arguments format arguments
192      * @return built exception
193      */
194     public static ArithmeticException createArithmeticException(final String pattern,
195                                                                 final Object ... arguments) {
196         return new ArithmeticException(buildMessage(Locale.US, pattern, arguments)) {
197 
198             /** Serializable version identifier. */
199             private static final long serialVersionUID = 7705628723242533939L;
200 
201             /** {@inheritDoc} */
202             @Override
203             public String getLocalizedMessage() {
204                 return buildMessage(Locale.getDefault(), pattern, arguments);
205             }
206 
207         };
208     }
209 
210     /**
211      * Constructs a new <code>ArrayIndexOutOfBoundsException</code> with specified formatted detail message.
212      * Message formatting is delegated to {@link java.text.MessageFormat}.
213      * @param pattern format specifier
214      * @param arguments format arguments
215      * @return built exception
216      */
217     public static ArrayIndexOutOfBoundsException createArrayIndexOutOfBoundsException(final String pattern,
218                                                                                       final Object ... arguments) {
219         return new ArrayIndexOutOfBoundsException(buildMessage(Locale.US, pattern, arguments)) {
220 
221             /** Serializable version identifier. */
222             private static final long serialVersionUID = -3394748305449283486L;
223 
224             /** {@inheritDoc} */
225             @Override
226             public String getLocalizedMessage() {
227                 return buildMessage(Locale.getDefault(), pattern, arguments);
228             }
229 
230         };
231     }
232 
233     /**
234      * Constructs a new <code>EOFException</code> with specified formatted detail message.
235      * Message formatting is delegated to {@link java.text.MessageFormat}.
236      * @param pattern format specifier
237      * @param arguments format arguments
238      * @return built exception
239      */
240     public static EOFException createEOFException(final String pattern,
241                                                   final Object ... arguments) {
242         return new EOFException(buildMessage(Locale.US, pattern, arguments)) {
243 
244             /** Serializable version identifier. */
245             private static final long serialVersionUID = 279461544586092584L;
246 
247             /** {@inheritDoc} */
248             @Override
249             public String getLocalizedMessage() {
250                 return buildMessage(Locale.getDefault(), pattern, arguments);
251             }
252 
253         };
254     }
255 
256     /**
257      * Constructs a new <code>IOException</code> with specified nested
258      * <code>Throwable</code> root cause.
259      * <p>This factory method allows chaining of other exceptions within an
260      * <code>IOException</code> even for Java 5. The constructor for
261      * <code>IOException</code> with a cause parameter was introduced only
262      * with Java 6.</p>
263      * @param rootCause the exception or error that caused this exception
264      * to be thrown.
265      * @return built exception
266      */
267     public static IOException createIOException(final Throwable rootCause) {
268         IOException ioe = new IOException(rootCause.getLocalizedMessage());
269         ioe.initCause(rootCause);
270         return ioe;
271     }
272 
273     /**
274      * Constructs a new <code>IllegalArgumentException</code> with specified formatted detail message.
275      * Message formatting is delegated to {@link java.text.MessageFormat}.
276      * @param pattern format specifier
277      * @param arguments format arguments
278      * @return built exception
279      */
280     public static IllegalArgumentException createIllegalArgumentException(final String pattern,
281                                                                           final Object ... arguments) {
282         return new IllegalArgumentException(buildMessage(Locale.US, pattern, arguments)) {
283 
284             /** Serializable version identifier. */
285             private static final long serialVersionUID = -6555453980658317913L;
286 
287             /** {@inheritDoc} */
288             @Override
289             public String getLocalizedMessage() {
290                 return buildMessage(Locale.getDefault(), pattern, arguments);
291             }
292 
293         };
294     }
295 
296     /**
297      * Constructs a new <code>IllegalArgumentException</code> with specified nested
298      * <code>Throwable</code> root cause.
299      * @param rootCause the exception or error that caused this exception
300      * to be thrown.
301      * @return built exception
302      */
303     public static IllegalArgumentException createIllegalArgumentException(final Throwable rootCause) {
304         IllegalArgumentException iae = new IllegalArgumentException(rootCause.getLocalizedMessage());
305         iae.initCause(rootCause);
306         return iae;
307     }
308 
309     /**
310      * Constructs a new <code>IllegalStateException</code> with specified formatted detail message.
311      * Message formatting is delegated to {@link java.text.MessageFormat}.
312      * @param pattern format specifier
313      * @param arguments format arguments
314      * @return built exception
315      */
316     public static IllegalStateException createIllegalStateException(final String pattern,
317                                                                     final Object ... arguments) {
318         return new IllegalStateException(buildMessage(Locale.US, pattern, arguments)) {
319 
320             /** Serializable version identifier. */
321             private static final long serialVersionUID = -95247648156277208L;
322 
323             /** {@inheritDoc} */
324             @Override
325             public String getLocalizedMessage() {
326                 return buildMessage(Locale.getDefault(), pattern, arguments);
327             }
328 
329         };
330     }
331 
332     /**
333      * Constructs a new <code>ConcurrentModificationException</code> with specified formatted detail message.
334      * Message formatting is delegated to {@link java.text.MessageFormat}.
335      * @param pattern format specifier
336      * @param arguments format arguments
337      * @return built exception
338      */
339     public static ConcurrentModificationException createConcurrentModificationException(final String pattern,
340                                                                                         final Object ... arguments) {
341         return new ConcurrentModificationException(buildMessage(Locale.US, pattern, arguments)) {
342 
343             /** Serializable version identifier. */
344             private static final long serialVersionUID = 6134247282754009421L;
345 
346             /** {@inheritDoc} */
347             @Override
348             public String getLocalizedMessage() {
349                 return buildMessage(Locale.getDefault(), pattern, arguments);
350             }
351 
352         };
353     }
354 
355     /**
356      * Constructs a new <code>NoSuchElementException</code> with specified formatted detail message.
357      * Message formatting is delegated to {@link java.text.MessageFormat}.
358      * @param pattern format specifier
359      * @param arguments format arguments
360      * @return built exception
361      */
362     public static NoSuchElementException createNoSuchElementException(final String pattern,
363                                                                       final Object ... arguments) {
364         return new NoSuchElementException(buildMessage(Locale.US, pattern, arguments)) {
365 
366             /** Serializable version identifier. */
367             private static final long serialVersionUID = 7304273322489425799L;
368 
369             /** {@inheritDoc} */
370             @Override
371             public String getLocalizedMessage() {
372                 return buildMessage(Locale.getDefault(), pattern, arguments);
373             }
374 
375         };
376     }
377 
378     /**
379      * Constructs a new <code>NullPointerException</code> with specified formatted detail message.
380      * Message formatting is delegated to {@link java.text.MessageFormat}.
381      * @param pattern format specifier
382      * @param arguments format arguments
383      * @return built exception
384      */
385     public static NullPointerException createNullPointerException(final String pattern,
386                                                                   final Object ... arguments) {
387         return new NullPointerException(buildMessage(Locale.US, pattern, arguments)) {
388 
389             /** Serializable version identifier. */
390             private static final long serialVersionUID = -3075660477939965216L;
391 
392             /** {@inheritDoc} */
393             @Override
394             public String getLocalizedMessage() {
395                 return buildMessage(Locale.getDefault(), pattern, arguments);
396             }
397 
398         };
399     }
400 
401    /**
402      * Constructs a new <code>ParseException</code> with specified
403      * formatted detail message.
404      * Message formatting is delegated to {@link java.text.MessageFormat}.
405      * @param offset offset at which error occurred
406      * @param pattern format specifier
407      * @param arguments format arguments
408      * @return built exception
409      */
410     public static ParseException createParseException(final int offset,
411                                                       final String pattern,
412                                                       final Object ... arguments) {
413         return new ParseException(buildMessage(Locale.US, pattern, arguments), offset) {
414 
415             /** Serializable version identifier. */
416             private static final long serialVersionUID = -1103502177342465975L;
417 
418             /** {@inheritDoc} */
419             @Override
420             public String getLocalizedMessage() {
421                 return buildMessage(Locale.getDefault(), pattern, arguments);
422             }
423 
424         };
425     }
426 
427     /** Create an {@link java.lang.RuntimeException} for an internal error.
428      * @param cause underlying cause
429      * @return an {@link java.lang.RuntimeException} for an internal error
430      */
431     public static RuntimeException createInternalError(final Throwable cause) {
432 
433         final String pattern  = "internal error, please fill a bug report at {0}";
434         final String argument = "https://issues.apache.org/jira/browse/MATH";
435 
436         return new RuntimeException(buildMessage(Locale.US, pattern, argument)) {
437 
438             /** Serializable version identifier. */
439             private static final long serialVersionUID = -201865440834027016L;
440 
441             /** {@inheritDoc} */
442             @Override
443             public String getLocalizedMessage() {
444                 return buildMessage(Locale.getDefault(), pattern, argument);
445             }
446 
447         };
448 
449     }
450 
451 }