001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math;
018
019 import java.io.EOFException;
020 import java.io.IOException;
021 import java.io.PrintStream;
022 import java.io.PrintWriter;
023 import java.text.MessageFormat;
024 import java.text.ParseException;
025 import java.util.ConcurrentModificationException;
026 import java.util.Locale;
027 import java.util.MissingResourceException;
028 import java.util.NoSuchElementException;
029 import java.util.ResourceBundle;
030
031 /**
032 * Base class for commons-math unchecked exceptions.
033 *
034 * @version $Revision: 822850 $ $Date: 2009-10-07 14:56:42 -0400 (Wed, 07 Oct 2009) $
035 * @since 2.0
036 */
037 public class MathRuntimeException extends RuntimeException {
038
039 /** Serializable version identifier. */
040 private static final long serialVersionUID = -5128983364075381060L;
041
042 /**
043 * Pattern used to build the message.
044 */
045 private final String pattern;
046
047 /**
048 * Arguments used to build the message.
049 */
050 private final Object[] arguments;
051
052 /**
053 * Constructs a new <code>MathRuntimeException</code> with specified
054 * formatted detail message.
055 * Message formatting is delegated to {@link java.text.MessageFormat}.
056 * @param pattern format specifier
057 * @param arguments format arguments
058 */
059 public MathRuntimeException(final String pattern, final Object ... arguments) {
060 this.pattern = pattern;
061 this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
062 }
063
064 /**
065 * Constructs a new <code>MathRuntimeException</code> with specified
066 * nested <code>Throwable</code> root cause.
067 *
068 * @param rootCause the exception or error that caused this exception
069 * to be thrown.
070 */
071 public MathRuntimeException(final Throwable rootCause) {
072 super(rootCause);
073 this.pattern = getMessage();
074 this.arguments = new Object[0];
075 }
076
077 /**
078 * Constructs a new <code>MathRuntimeException</code> with specified
079 * formatted detail message and nested <code>Throwable</code> root cause.
080 * Message formatting is delegated to {@link java.text.MessageFormat}.
081 * @param rootCause the exception or error that caused this exception
082 * to be thrown.
083 * @param pattern format specifier
084 * @param arguments format arguments
085 */
086 public MathRuntimeException(final Throwable rootCause,
087 final String pattern, final Object ... arguments) {
088 super(rootCause);
089 this.pattern = pattern;
090 this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
091 }
092
093 /**
094 * Translate a string to a given locale.
095 * @param s string to translate
096 * @param locale locale into which to translate the string
097 * @return translated string or original string
098 * for unsupported locales or unknown strings
099 */
100 private static String translate(final String s, final Locale locale) {
101 try {
102 ResourceBundle bundle =
103 ResourceBundle.getBundle("org.apache.commons.math.MessagesResources", locale);
104 if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
105 // the value of the resource is the translated string
106 return bundle.getString(s);
107 }
108
109 } catch (MissingResourceException mre) {
110 // do nothing here
111 }
112
113 // the locale is not supported or the resource is unknown
114 // don't translate and fall back to using the string as is
115 return s;
116
117 }
118
119 /**
120 * Builds a message string by from a pattern and its arguments.
121 * @param locale Locale in which the message should be translated
122 * @param pattern format specifier
123 * @param arguments format arguments
124 * @return a message string
125 */
126 private static String buildMessage(final Locale locale, final String pattern,
127 final Object ... arguments) {
128 return (pattern == null) ? "" : new MessageFormat(translate(pattern, locale), locale).format(arguments);
129 }
130
131 /** Gets the pattern used to build the message of this throwable.
132 *
133 * @return the pattern used to build the message of this throwable
134 */
135 public String getPattern() {
136 return pattern;
137 }
138
139 /** Gets the arguments used to build the message of this throwable.
140 *
141 * @return the arguments used to build the message of this throwable
142 */
143 public Object[] getArguments() {
144 return arguments.clone();
145 }
146
147 /** Gets the message in a specified locale.
148 *
149 * @param locale Locale in which the message should be translated
150 *
151 * @return localized message
152 */
153 public String getMessage(final Locale locale) {
154 return buildMessage(locale, pattern, arguments);
155 }
156
157 /** {@inheritDoc} */
158 @Override
159 public String getMessage() {
160 return getMessage(Locale.US);
161 }
162
163 /** {@inheritDoc} */
164 @Override
165 public String getLocalizedMessage() {
166 return getMessage(Locale.getDefault());
167 }
168
169 /**
170 * Prints the stack trace of this exception to the standard error stream.
171 */
172 @Override
173 public void printStackTrace() {
174 printStackTrace(System.err);
175 }
176
177 /**
178 * Prints the stack trace of this exception to the specified stream.
179 *
180 * @param out the <code>PrintStream</code> to use for output
181 */
182 @Override
183 public void printStackTrace(final PrintStream out) {
184 synchronized (out) {
185 PrintWriter pw = new PrintWriter(out, false);
186 printStackTrace(pw);
187 // Flush the PrintWriter before it's GC'ed.
188 pw.flush();
189 }
190 }
191
192 /**
193 * Constructs a new <code>ArithmeticException</code> with specified formatted detail message.
194 * Message formatting is delegated to {@link java.text.MessageFormat}.
195 * @param pattern format specifier
196 * @param arguments format arguments
197 * @return built exception
198 */
199 public static ArithmeticException createArithmeticException(final String pattern,
200 final Object ... arguments) {
201 return new ArithmeticException() {
202
203 /** Serializable version identifier. */
204 private static final long serialVersionUID = 7705628723242533939L;
205
206 /** {@inheritDoc} */
207 @Override
208 public String getMessage() {
209 return buildMessage(Locale.US, pattern, arguments);
210 }
211
212 /** {@inheritDoc} */
213 @Override
214 public String getLocalizedMessage() {
215 return buildMessage(Locale.getDefault(), pattern, arguments);
216 }
217
218 };
219 }
220
221 /**
222 * Constructs a new <code>ArrayIndexOutOfBoundsException</code> with specified formatted detail message.
223 * Message formatting is delegated to {@link java.text.MessageFormat}.
224 * @param pattern format specifier
225 * @param arguments format arguments
226 * @return built exception
227 */
228 public static ArrayIndexOutOfBoundsException createArrayIndexOutOfBoundsException(final String pattern,
229 final Object ... arguments) {
230 return new ArrayIndexOutOfBoundsException() {
231
232 /** Serializable version identifier. */
233 private static final long serialVersionUID = -3394748305449283486L;
234
235 /** {@inheritDoc} */
236 @Override
237 public String getMessage() {
238 return buildMessage(Locale.US, pattern, arguments);
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public String getLocalizedMessage() {
244 return buildMessage(Locale.getDefault(), pattern, arguments);
245 }
246
247 };
248 }
249
250 /**
251 * Constructs a new <code>EOFException</code> with specified formatted detail message.
252 * Message formatting is delegated to {@link java.text.MessageFormat}.
253 * @param pattern format specifier
254 * @param arguments format arguments
255 * @return built exception
256 */
257 public static EOFException createEOFException(final String pattern,
258 final Object ... arguments) {
259 return new EOFException() {
260
261 /** Serializable version identifier. */
262 private static final long serialVersionUID = 279461544586092584L;
263
264 /** {@inheritDoc} */
265 @Override
266 public String getMessage() {
267 return buildMessage(Locale.US, pattern, arguments);
268 }
269
270 /** {@inheritDoc} */
271 @Override
272 public String getLocalizedMessage() {
273 return buildMessage(Locale.getDefault(), pattern, arguments);
274 }
275
276 };
277 }
278
279 /**
280 * Constructs a new <code>IOException</code> with specified nested
281 * <code>Throwable</code> root cause.
282 * <p>This factory method allows chaining of other exceptions within an
283 * <code>IOException</code> even for Java 5. The constructor for
284 * <code>IOException</code> with a cause parameter was introduced only
285 * with Java 6.</p>
286 * @param rootCause the exception or error that caused this exception
287 * to be thrown.
288 * @return built exception
289 */
290 public static IOException createIOException(final Throwable rootCause) {
291 IOException ioe = new IOException(rootCause.getLocalizedMessage());
292 ioe.initCause(rootCause);
293 return ioe;
294 }
295
296 /**
297 * Constructs a new <code>IllegalArgumentException</code> with specified formatted detail message.
298 * Message formatting is delegated to {@link java.text.MessageFormat}.
299 * @param pattern format specifier
300 * @param arguments format arguments
301 * @return built exception
302 */
303 public static IllegalArgumentException createIllegalArgumentException(final String pattern,
304 final Object ... arguments) {
305 return new IllegalArgumentException() {
306
307 /** Serializable version identifier. */
308 private static final long serialVersionUID = -6555453980658317913L;
309
310 /** {@inheritDoc} */
311 @Override
312 public String getMessage() {
313 return buildMessage(Locale.US, pattern, arguments);
314 }
315
316 /** {@inheritDoc} */
317 @Override
318 public String getLocalizedMessage() {
319 return buildMessage(Locale.getDefault(), pattern, arguments);
320 }
321
322 };
323 }
324
325 /**
326 * Constructs a new <code>IllegalArgumentException</code> with specified nested
327 * <code>Throwable</code> root cause.
328 * @param rootCause the exception or error that caused this exception
329 * to be thrown.
330 * @return built exception
331 */
332 public static IllegalArgumentException createIllegalArgumentException(final Throwable rootCause) {
333 IllegalArgumentException iae = new IllegalArgumentException(rootCause.getLocalizedMessage());
334 iae.initCause(rootCause);
335 return iae;
336 }
337
338 /**
339 * Constructs a new <code>IllegalStateException</code> with specified formatted detail message.
340 * Message formatting is delegated to {@link java.text.MessageFormat}.
341 * @param pattern format specifier
342 * @param arguments format arguments
343 * @return built exception
344 */
345 public static IllegalStateException createIllegalStateException(final String pattern,
346 final Object ... arguments) {
347 return new IllegalStateException() {
348
349 /** Serializable version identifier. */
350 private static final long serialVersionUID = -95247648156277208L;
351
352 /** {@inheritDoc} */
353 @Override
354 public String getMessage() {
355 return buildMessage(Locale.US, pattern, arguments);
356 }
357
358 /** {@inheritDoc} */
359 @Override
360 public String getLocalizedMessage() {
361 return buildMessage(Locale.getDefault(), pattern, arguments);
362 }
363
364 };
365 }
366
367 /**
368 * Constructs a new <code>ConcurrentModificationException</code> with specified formatted detail message.
369 * Message formatting is delegated to {@link java.text.MessageFormat}.
370 * @param pattern format specifier
371 * @param arguments format arguments
372 * @return built exception
373 */
374 public static ConcurrentModificationException createConcurrentModificationException(final String pattern,
375 final Object ... arguments) {
376 return new ConcurrentModificationException() {
377
378 /** Serializable version identifier. */
379 private static final long serialVersionUID = 6134247282754009421L;
380
381 /** {@inheritDoc} */
382 @Override
383 public String getMessage() {
384 return buildMessage(Locale.US, pattern, arguments);
385 }
386
387 /** {@inheritDoc} */
388 @Override
389 public String getLocalizedMessage() {
390 return buildMessage(Locale.getDefault(), pattern, arguments);
391 }
392
393 };
394 }
395
396 /**
397 * Constructs a new <code>NoSuchElementException</code> with specified formatted detail message.
398 * Message formatting is delegated to {@link java.text.MessageFormat}.
399 * @param pattern format specifier
400 * @param arguments format arguments
401 * @return built exception
402 */
403 public static NoSuchElementException createNoSuchElementException(final String pattern,
404 final Object ... arguments) {
405 return new NoSuchElementException() {
406
407 /** Serializable version identifier. */
408 private static final long serialVersionUID = 7304273322489425799L;
409
410 /** {@inheritDoc} */
411 @Override
412 public String getMessage() {
413 return buildMessage(Locale.US, pattern, arguments);
414 }
415
416 /** {@inheritDoc} */
417 @Override
418 public String getLocalizedMessage() {
419 return buildMessage(Locale.getDefault(), pattern, arguments);
420 }
421
422 };
423 }
424
425 /**
426 * Constructs a new <code>NullPointerException</code> with specified formatted detail message.
427 * Message formatting is delegated to {@link java.text.MessageFormat}.
428 * @param pattern format specifier
429 * @param arguments format arguments
430 * @return built exception
431 */
432 public static NullPointerException createNullPointerException(final String pattern,
433 final Object ... arguments) {
434 return new NullPointerException() {
435
436 /** Serializable version identifier. */
437 private static final long serialVersionUID = -3075660477939965216L;
438
439 /** {@inheritDoc} */
440 @Override
441 public String getMessage() {
442 return buildMessage(Locale.US, pattern, arguments);
443 }
444
445 /** {@inheritDoc} */
446 @Override
447 public String getLocalizedMessage() {
448 return buildMessage(Locale.getDefault(), pattern, arguments);
449 }
450
451 };
452 }
453
454 /**
455 * Constructs a new <code>ParseException</code> with specified
456 * formatted detail message.
457 * Message formatting is delegated to {@link java.text.MessageFormat}.
458 * @param offset offset at which error occurred
459 * @param pattern format specifier
460 * @param arguments format arguments
461 * @return built exception
462 */
463 public static ParseException createParseException(final int offset,
464 final String pattern,
465 final Object ... arguments) {
466 return new ParseException(null, offset) {
467
468 /** Serializable version identifier. */
469 private static final long serialVersionUID = -1103502177342465975L;
470
471 /** {@inheritDoc} */
472 @Override
473 public String getMessage() {
474 return buildMessage(Locale.US, pattern, arguments);
475 }
476
477 /** {@inheritDoc} */
478 @Override
479 public String getLocalizedMessage() {
480 return buildMessage(Locale.getDefault(), pattern, arguments);
481 }
482
483 };
484 }
485
486 /** Create an {@link java.lang.RuntimeException} for an internal error.
487 * @param cause underlying cause
488 * @return an {@link java.lang.RuntimeException} for an internal error
489 */
490 public static RuntimeException createInternalError(final Throwable cause) {
491
492 final String pattern = "internal error, please fill a bug report at {0}";
493 final String argument = "https://issues.apache.org/jira/browse/MATH";
494
495 return new RuntimeException() {
496
497 /** Serializable version identifier. */
498 private static final long serialVersionUID = -201865440834027016L;
499
500 /** {@inheritDoc} */
501 @Override
502 public String getMessage() {
503 return buildMessage(Locale.US, pattern, argument);
504 }
505
506 /** {@inheritDoc} */
507 @Override
508 public String getLocalizedMessage() {
509 return buildMessage(Locale.getDefault(), pattern, argument);
510 }
511
512 };
513
514 }
515
516 }