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: 786478 $ $Date: 2009-06-19 08:33:36 -0400 (Fri, 19 Jun 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 * Translate a string to a given locale.
054 * @param s string to translate
055 * @param locale locale into which to translate the string
056 * @return translated string or original string
057 * for unsupported locales or unknown strings
058 */
059 private static String translate(final String s, final Locale locale) {
060 try {
061 ResourceBundle bundle =
062 ResourceBundle.getBundle("org.apache.commons.math.MessagesResources", locale);
063 if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
064 // the value of the resource is the translated string
065 return bundle.getString(s);
066 }
067
068 } catch (MissingResourceException mre) {
069 // do nothing here
070 }
071
072 // the locale is not supported or the resource is unknown
073 // don't translate and fall back to using the string as is
074 return s;
075
076 }
077
078 /**
079 * Builds a message string by from a pattern and its arguments.
080 * @param locale Locale in which the message should be translated
081 * @param pattern format specifier
082 * @param arguments format arguments
083 * @return a message string
084 */
085 private static String buildMessage(final Locale locale, final String pattern,
086 final Object ... arguments) {
087 return (pattern == null) ? "" : new MessageFormat(translate(pattern, locale), locale).format(arguments);
088 }
089
090 /**
091 * Constructs a new <code>MathRuntimeException</code> with specified
092 * formatted detail message.
093 * Message formatting is delegated to {@link java.text.MessageFormat}.
094 * @param pattern format specifier
095 * @param arguments format arguments
096 */
097 public MathRuntimeException(final String pattern, final Object ... arguments) {
098 super(buildMessage(Locale.US, pattern, arguments));
099 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 }