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 */
17package org.apache.commons.math;
18
19import java.io.EOFException;
20import java.io.IOException;
21import java.io.PrintStream;
22import java.io.PrintWriter;
23import java.text.MessageFormat;
24import java.text.ParseException;
25import java.util.ConcurrentModificationException;
26import java.util.Locale;
27import java.util.NoSuchElementException;
28
29import org.apache.commons.math.exception.MathThrowable;
30import org.apache.commons.math.exception.util.DummyLocalizable;
31import org.apache.commons.math.exception.util.Localizable;
32import org.apache.commons.math.exception.util.LocalizedFormats;
33
34/**
35* Base class for commons-math unchecked exceptions.
36*
37* @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
38* @since 2.0
39*/
40public class MathRuntimeException extends RuntimeException implements MathThrowable {
41
42    /** Serializable version identifier. */
43    private static final long serialVersionUID = 9058794795027570002L;
44
45    /**
46     * Pattern used to build the message.
47     */
48    private final Localizable pattern;
49
50    /**
51     * Arguments used to build the message.
52     */
53    private final Object[] arguments;
54
55    /**
56     * Constructs a new <code>MathRuntimeException</code> with specified
57     * formatted detail message.
58     * Message formatting is delegated to {@link java.text.MessageFormat}.
59     * @param pattern format specifier
60     * @param arguments format arguments
61     * @deprecated as of 2.2 replaced by {@link #MathRuntimeException(Localizable, Object...)}
62     */
63    @Deprecated
64    public MathRuntimeException(final String pattern, final Object ... arguments) {
65        this(new DummyLocalizable(pattern), arguments);
66    }
67
68    /**
69     * Constructs a new <code>MathRuntimeException</code> with specified
70     * formatted detail message.
71     * Message formatting is delegated to {@link java.text.MessageFormat}.
72     * @param pattern format specifier
73     * @param arguments format arguments
74     * @since 2.2
75     */
76    public MathRuntimeException(final Localizable pattern, final Object ... arguments) {
77        this.pattern   = pattern;
78        this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
79    }
80
81    /**
82     * Constructs a new <code>MathRuntimeException</code> with specified
83     * nested <code>Throwable</code> root cause.
84     *
85     * @param rootCause  the exception or error that caused this exception
86     *                   to be thrown.
87     */
88    public MathRuntimeException(final Throwable rootCause) {
89        super(rootCause);
90        this.pattern   = LocalizedFormats.SIMPLE_MESSAGE;
91        this.arguments = new Object[] { (rootCause == null) ? "" : rootCause.getMessage() };
92    }
93
94    /**
95     * Constructs a new <code>MathRuntimeException</code> with specified
96     * formatted detail message and nested <code>Throwable</code> root cause.
97     * Message formatting is delegated to {@link java.text.MessageFormat}.
98     * @param rootCause the exception or error that caused this exception
99     * to be thrown.
100     * @param pattern format specifier
101     * @param arguments format arguments
102     * @deprecated as of 2.2 replaced by {@link #MathRuntimeException(Throwable, Localizable, Object...)}
103     */
104    @Deprecated
105    public MathRuntimeException(final Throwable rootCause,
106                                final String pattern, final Object ... arguments) {
107        this(rootCause, new DummyLocalizable(pattern), arguments);
108    }
109
110    /**
111     * Constructs a new <code>MathRuntimeException</code> with specified
112     * formatted detail message and nested <code>Throwable</code> root cause.
113     * Message formatting is delegated to {@link java.text.MessageFormat}.
114     * @param rootCause the exception or error that caused this exception
115     * to be thrown.
116     * @param pattern format specifier
117     * @param arguments format arguments
118     * @since 2.2
119     */
120    public MathRuntimeException(final Throwable rootCause,
121                                final Localizable pattern, final Object ... arguments) {
122        super(rootCause);
123        this.pattern   = pattern;
124        this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
125    }
126
127    /**
128     * Builds a message string by from a pattern and its arguments.
129     * @param locale Locale in which the message should be translated
130     * @param pattern format specifier
131     * @param arguments format arguments
132     * @return a message string
133     * @since 2.2
134     */
135    private static String buildMessage(final Locale locale, final Localizable pattern,
136                                       final Object ... arguments) {
137        return new MessageFormat(pattern.getLocalizedString(locale), locale).format(arguments);
138    }
139
140    /** Gets the pattern used to build the message of this throwable.
141    *
142    * @return the pattern used to build the message of this throwable
143    * @deprecated as of 2.2 replaced by {@link #getSpecificPattern()} and {@link #getGeneralPattern()}
144    */
145    @Deprecated
146    public String getPattern() {
147        return pattern.getSourceString();
148    }
149
150    /**
151     * {@inheritDoc}
152     *
153     * @since 2.2
154     */
155    public Localizable getSpecificPattern() {
156        return null;
157    }
158
159    /**
160     * {@inheritDoc}
161     *
162     * @since 2.2
163     */
164    public Localizable getGeneralPattern() {
165        return pattern;
166    }
167
168    /** {@inheritDoc} */
169    public Object[] getArguments() {
170        return arguments.clone();
171    }
172
173    /** Gets the message in a specified locale.
174     *
175     * @param locale Locale in which the message should be translated
176     *
177     * @return localized message
178     */
179    public String getMessage(final Locale locale) {
180        if (pattern != null) {
181            return buildMessage(locale, pattern, arguments);
182        }
183        return "";
184    }
185
186    /** {@inheritDoc} */
187    @Override
188    public String getMessage() {
189        return getMessage(Locale.US);
190    }
191
192    /** {@inheritDoc} */
193    @Override
194    public String getLocalizedMessage() {
195        return getMessage(Locale.getDefault());
196    }
197
198    /**
199     * Prints the stack trace of this exception to the standard error stream.
200     */
201    @Override
202    public void printStackTrace() {
203        printStackTrace(System.err);
204    }
205
206    /**
207     * Prints the stack trace of this exception to the specified stream.
208     *
209     * @param out  the <code>PrintStream</code> to use for output
210     */
211    @Override
212    public void printStackTrace(final PrintStream out) {
213        synchronized (out) {
214            PrintWriter pw = new PrintWriter(out, false);
215            printStackTrace(pw);
216            // Flush the PrintWriter before it's GC'ed.
217            pw.flush();
218        }
219    }
220
221    /**
222     * Constructs a new <code>ArithmeticException</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     * @deprecated as of 2.2 replaced by {@link #createArithmeticException(Localizable, Object...)}
228     */
229    @Deprecated
230    public static ArithmeticException createArithmeticException(final String pattern,
231                                                                final Object ... arguments) {
232        return createArithmeticException(new DummyLocalizable(pattern), arguments);
233    }
234
235    /**
236     * Constructs a new <code>ArithmeticException</code> with specified formatted detail message.
237     * Message formatting is delegated to {@link java.text.MessageFormat}.
238     * @param pattern format specifier
239     * @param arguments format arguments
240     * @return built exception
241     * @since 2.2
242     */
243    public static ArithmeticException createArithmeticException(final Localizable pattern,
244                                                                final Object ... arguments) {
245        return new ArithmeticException() {
246
247            /** Serializable version identifier. */
248            private static final long serialVersionUID = 5305498554076846637L;
249
250            /** {@inheritDoc} */
251            @Override
252            public String getMessage() {
253                return buildMessage(Locale.US, pattern, arguments);
254            }
255
256            /** {@inheritDoc} */
257            @Override
258            public String getLocalizedMessage() {
259                return buildMessage(Locale.getDefault(), pattern, arguments);
260            }
261
262        };
263    }
264
265    /**
266     * Constructs a new <code>ArrayIndexOutOfBoundsException</code> with specified formatted detail message.
267     * Message formatting is delegated to {@link java.text.MessageFormat}.
268     * @param pattern format specifier
269     * @param arguments format arguments
270     * @return built exception
271     * @deprecated as of 2.2 replaced by {@link #createArrayIndexOutOfBoundsException(Localizable, Object...)}
272     */
273    @Deprecated
274    public static ArrayIndexOutOfBoundsException createArrayIndexOutOfBoundsException(final String pattern,
275                                                                                      final Object ... arguments) {
276        return createArrayIndexOutOfBoundsException(new DummyLocalizable(pattern), arguments);
277    }
278
279    /**
280     * Constructs a new <code>ArrayIndexOutOfBoundsException</code> with specified formatted detail message.
281     * Message formatting is delegated to {@link java.text.MessageFormat}.
282     * @param pattern format specifier
283     * @param arguments format arguments
284     * @return built exception
285     * @since 2.2
286     */
287    public static ArrayIndexOutOfBoundsException createArrayIndexOutOfBoundsException(final Localizable pattern,
288                                                                                      final Object ... arguments) {
289        return new ArrayIndexOutOfBoundsException() {
290
291            /** Serializable version identifier. */
292            private static final long serialVersionUID = 6718518191249632175L;
293
294            /** {@inheritDoc} */
295            @Override
296            public String getMessage() {
297                return buildMessage(Locale.US, pattern, arguments);
298            }
299
300            /** {@inheritDoc} */
301            @Override
302            public String getLocalizedMessage() {
303                return buildMessage(Locale.getDefault(), pattern, arguments);
304            }
305
306        };
307    }
308
309    /**
310     * Constructs a new <code>EOFException</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     * @deprecated as of 2.2 replaced by {@link #createEOFException(Localizable, Object...)}
316     */
317    @Deprecated
318    public static EOFException createEOFException(final String pattern,
319                                                  final Object ... arguments) {
320        return createEOFException(new DummyLocalizable(pattern), arguments);
321    }
322
323    /**
324     * Constructs a new <code>EOFException</code> with specified formatted detail message.
325     * Message formatting is delegated to {@link java.text.MessageFormat}.
326     * @param pattern format specifier
327     * @param arguments format arguments
328     * @return built exception
329     * @since 2.2
330     */
331    public static EOFException createEOFException(final Localizable pattern,
332                                                  final Object ... arguments) {
333        return new EOFException() {
334
335            /** Serializable version identifier. */
336            private static final long serialVersionUID = 6067985859347601503L;
337
338            /** {@inheritDoc} */
339            @Override
340            public String getMessage() {
341                return buildMessage(Locale.US, pattern, arguments);
342            }
343
344            /** {@inheritDoc} */
345            @Override
346            public String getLocalizedMessage() {
347                return buildMessage(Locale.getDefault(), pattern, arguments);
348            }
349
350        };
351    }
352
353    /**
354     * Constructs a new <code>IOException</code> with specified nested
355     * <code>Throwable</code> root cause.
356     * <p>This factory method allows chaining of other exceptions within an
357     * <code>IOException</code> even for Java 5. The constructor for
358     * <code>IOException</code> with a cause parameter was introduced only
359     * with Java 6.</p>
360     * @param rootCause the exception or error that caused this exception
361     * to be thrown.
362     * @return built exception
363     */
364    public static IOException createIOException(final Throwable rootCause) {
365        IOException ioe = new IOException(rootCause.getLocalizedMessage());
366        ioe.initCause(rootCause);
367        return ioe;
368    }
369
370    /**
371     * Constructs a new <code>IllegalArgumentException</code> with specified formatted detail message.
372     * Message formatting is delegated to {@link java.text.MessageFormat}.
373     * @param pattern format specifier
374     * @param arguments format arguments
375     * @return built exception
376     * @deprecated as of 2.2 replaced by {@link #createIllegalArgumentException(Localizable, Object...)}
377     */
378    @Deprecated
379    public static IllegalArgumentException createIllegalArgumentException(final String pattern,
380                                                                          final Object ... arguments) {
381        return createIllegalArgumentException(new DummyLocalizable(pattern), arguments);
382    }
383
384    /**
385     * Constructs a new <code>IllegalArgumentException</code> with specified formatted detail message.
386     * Message formatting is delegated to {@link java.text.MessageFormat}.
387     * @param pattern format specifier
388     * @param arguments format arguments
389     * @return built exception
390     * @since 2.2
391     */
392    public static IllegalArgumentException createIllegalArgumentException(final Localizable pattern,
393                                                                          final Object ... arguments) {
394        return new IllegalArgumentException() {
395
396            /** Serializable version identifier. */
397            private static final long serialVersionUID = -4284649691002411505L;
398
399            /** {@inheritDoc} */
400            @Override
401            public String getMessage() {
402                return buildMessage(Locale.US, pattern, arguments);
403            }
404
405            /** {@inheritDoc} */
406            @Override
407            public String getLocalizedMessage() {
408                return buildMessage(Locale.getDefault(), pattern, arguments);
409            }
410
411        };
412    }
413
414    /**
415     * Constructs a new <code>IllegalArgumentException</code> with specified nested
416     * <code>Throwable</code> root cause.
417     * @param rootCause the exception or error that caused this exception
418     * to be thrown.
419     * @return built exception
420     */
421    public static IllegalArgumentException createIllegalArgumentException(final Throwable rootCause) {
422        IllegalArgumentException iae = new IllegalArgumentException(rootCause.getLocalizedMessage());
423        iae.initCause(rootCause);
424        return iae;
425    }
426
427    /**
428     * Constructs a new <code>IllegalStateException</code> with specified formatted detail message.
429     * Message formatting is delegated to {@link java.text.MessageFormat}.
430     * @param pattern format specifier
431     * @param arguments format arguments
432     * @return built exception
433     * @deprecated as of 2.2 replaced by {@link #createIllegalStateException(Localizable, Object...)}
434     */
435    @Deprecated
436    public static IllegalStateException createIllegalStateException(final String pattern,
437                                                                    final Object ... arguments) {
438        return createIllegalStateException(new DummyLocalizable(pattern), arguments);
439    }
440
441    /**
442     * Constructs a new <code>IllegalStateException</code> with specified formatted detail message.
443     * Message formatting is delegated to {@link java.text.MessageFormat}.
444     * @param pattern format specifier
445     * @param arguments format arguments
446     * @return built exception
447     * @since 2.2
448     */
449    public static IllegalStateException createIllegalStateException(final Localizable pattern,
450                                                                    final Object ... arguments) {
451        return new IllegalStateException() {
452
453            /** Serializable version identifier. */
454            private static final long serialVersionUID = 6880901520234515725L;
455
456            /** {@inheritDoc} */
457            @Override
458            public String getMessage() {
459                return buildMessage(Locale.US, pattern, arguments);
460            }
461
462            /** {@inheritDoc} */
463            @Override
464            public String getLocalizedMessage() {
465                return buildMessage(Locale.getDefault(), pattern, arguments);
466            }
467
468        };
469    }
470
471    /**
472     * Constructs a new <code>ConcurrentModificationException</code> with specified formatted detail message.
473     * Message formatting is delegated to {@link java.text.MessageFormat}.
474     * @param pattern format specifier
475     * @param arguments format arguments
476     * @return built exception
477     * @deprecated as of 2.2 replaced by {@link #createConcurrentModificationException(Localizable, Object...)}
478     */
479    @Deprecated
480    public static ConcurrentModificationException createConcurrentModificationException(final String pattern,
481                                                                                        final Object ... arguments) {
482        return createConcurrentModificationException(new DummyLocalizable(pattern), arguments);
483    }
484
485    /**
486     * Constructs a new <code>ConcurrentModificationException</code> with specified formatted detail message.
487     * Message formatting is delegated to {@link java.text.MessageFormat}.
488     * @param pattern format specifier
489     * @param arguments format arguments
490     * @return built exception
491     * @since 2.2
492     */
493    public static ConcurrentModificationException createConcurrentModificationException(final Localizable pattern,
494                                                                                        final Object ... arguments) {
495        return new ConcurrentModificationException() {
496
497            /** Serializable version identifier. */
498            private static final long serialVersionUID = -1878427236170442052L;
499
500            /** {@inheritDoc} */
501            @Override
502            public String getMessage() {
503                return buildMessage(Locale.US, pattern, arguments);
504            }
505
506            /** {@inheritDoc} */
507            @Override
508            public String getLocalizedMessage() {
509                return buildMessage(Locale.getDefault(), pattern, arguments);
510            }
511
512        };
513    }
514
515    /**
516     * Constructs a new <code>NoSuchElementException</code> with specified formatted detail message.
517     * Message formatting is delegated to {@link java.text.MessageFormat}.
518     * @param pattern format specifier
519     * @param arguments format arguments
520     * @return built exception
521     * @deprecated as of 2.2 replaced by {@link #createNoSuchElementException(Localizable, Object...)}
522     */
523    @Deprecated
524    public static NoSuchElementException createNoSuchElementException(final String pattern,
525                                                                      final Object ... arguments) {
526        return createNoSuchElementException(new DummyLocalizable(pattern), arguments);
527    }
528
529    /**
530     * Constructs a new <code>NoSuchElementException</code> with specified formatted detail message.
531     * Message formatting is delegated to {@link java.text.MessageFormat}.
532     * @param pattern format specifier
533     * @param arguments format arguments
534     * @return built exception
535     * @since 2.2
536     */
537    public static NoSuchElementException createNoSuchElementException(final Localizable pattern,
538                                                                      final Object ... arguments) {
539        return new NoSuchElementException() {
540
541            /** Serializable version identifier. */
542            private static final long serialVersionUID = 1632410088350355086L;
543
544            /** {@inheritDoc} */
545            @Override
546            public String getMessage() {
547                return buildMessage(Locale.US, pattern, arguments);
548            }
549
550            /** {@inheritDoc} */
551            @Override
552            public String getLocalizedMessage() {
553                return buildMessage(Locale.getDefault(), pattern, arguments);
554            }
555
556        };
557    }
558
559    /**
560     * Constructs a new <code>UnsupportedOperationException</code> with specified formatted detail message.
561     * Message formatting is delegated to {@link java.text.MessageFormat}.
562     * @param pattern format specifier
563     * @param arguments format arguments
564     * @return built exception
565     * @since 2.2
566     * @deprecated in 2.2. Please use {@link org.apache.commons.math.exception.MathUnsupportedOperationException}
567     * instead.
568     */
569    @Deprecated
570    public static UnsupportedOperationException createUnsupportedOperationException(final Localizable pattern,
571                                                                                    final Object ... arguments) {
572        return new UnsupportedOperationException() {
573
574            /** Serializable version identifier. */
575            private static final long serialVersionUID = -4284649691002411505L;
576
577            /** {@inheritDoc} */
578            @Override
579            public String getMessage() {
580                return buildMessage(Locale.US, pattern, arguments);
581            }
582
583            /** {@inheritDoc} */
584            @Override
585            public String getLocalizedMessage() {
586                return buildMessage(Locale.getDefault(), pattern, arguments);
587            }
588
589        };
590    }
591
592    /**
593     * Constructs a new <code>NullPointerException</code> with specified formatted detail message.
594     * Message formatting is delegated to {@link java.text.MessageFormat}.
595     * @param pattern format specifier
596     * @param arguments format arguments
597     * @return built exception
598     * @deprecated as of 2.2 replaced by {@link #createNullPointerException(Localizable, Object...)}
599     */
600    @Deprecated
601    public static NullPointerException createNullPointerException(final String pattern,
602                                                                  final Object ... arguments) {
603        return createNullPointerException(new DummyLocalizable(pattern), arguments);
604    }
605
606    /**
607     * Constructs a new <code>NullPointerException</code> with specified formatted detail message.
608     * Message formatting is delegated to {@link java.text.MessageFormat}.
609     * @param pattern format specifier
610     * @param arguments format arguments
611     * @return built exception
612     * @since 2.2
613     * @deprecated in 2.2. Checks for "null" must not be performed in Commons-Math.
614     */
615    @Deprecated
616    public static NullPointerException createNullPointerException(final Localizable pattern,
617                                                                  final Object ... arguments) {
618        return new NullPointerException() {
619
620            /** Serializable version identifier. */
621            private static final long serialVersionUID = 451965530686593945L;
622
623            /** {@inheritDoc} */
624            @Override
625            public String getMessage() {
626                return buildMessage(Locale.US, pattern, arguments);
627            }
628
629            /** {@inheritDoc} */
630            @Override
631            public String getLocalizedMessage() {
632                return buildMessage(Locale.getDefault(), pattern, arguments);
633            }
634
635        };
636    }
637
638   /**
639     * Constructs a new <code>ParseException</code> with specified
640     * formatted detail message.
641     * Message formatting is delegated to {@link java.text.MessageFormat}.
642     * @param offset offset at which error occurred
643     * @param pattern format specifier
644     * @param arguments format arguments
645     * @return built exception
646     * @deprecated as of 2.2 replaced by {@link #createParseException(int, Localizable, Object...)}
647     */
648    @Deprecated
649    public static ParseException createParseException(final int offset,
650                                                      final String pattern,
651                                                      final Object ... arguments) {
652        return createParseException(offset, new DummyLocalizable(pattern), arguments);
653    }
654
655    /**
656     * Constructs a new <code>ParseException</code> with specified
657     * formatted detail message.
658     * Message formatting is delegated to {@link java.text.MessageFormat}.
659     * @param offset offset at which error occurred
660     * @param pattern format specifier
661     * @param arguments format arguments
662     * @return built exception
663     * @since 2.2
664     */
665    public static ParseException createParseException(final int offset,
666                                                      final Localizable pattern,
667                                                      final Object ... arguments) {
668        return new ParseException(null, offset) {
669
670            /** Serializable version identifier. */
671            private static final long serialVersionUID = 8153587599409010120L;
672
673            /** {@inheritDoc} */
674            @Override
675            public String getMessage() {
676                return buildMessage(Locale.US, pattern, arguments);
677            }
678
679            /** {@inheritDoc} */
680            @Override
681            public String getLocalizedMessage() {
682                return buildMessage(Locale.getDefault(), pattern, arguments);
683            }
684
685        };
686    }
687
688    /** Create an {@link java.lang.RuntimeException} for an internal error.
689     * @param cause underlying cause
690     * @return an {@link java.lang.RuntimeException} for an internal error
691     */
692    public static RuntimeException createInternalError(final Throwable cause) {
693
694        final String argument = "https://issues.apache.org/jira/browse/MATH";
695
696        return new RuntimeException(cause) {
697
698            /** Serializable version identifier. */
699            private static final long serialVersionUID = -201865440834027016L;
700
701            /** {@inheritDoc} */
702            @Override
703            public String getMessage() {
704                return buildMessage(Locale.US, LocalizedFormats.INTERNAL_ERROR, argument);
705            }
706
707            /** {@inheritDoc} */
708            @Override
709            public String getLocalizedMessage() {
710                return buildMessage(Locale.getDefault(), LocalizedFormats.INTERNAL_ERROR, argument);
711            }
712
713        };
714
715    }
716
717}
718