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 }