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.NoSuchElementException;
028    
029    import org.apache.commons.math.exception.MathThrowable;
030    import org.apache.commons.math.exception.util.DummyLocalizable;
031    import org.apache.commons.math.exception.util.Localizable;
032    import org.apache.commons.math.exception.util.LocalizedFormats;
033    
034    /**
035    * Base class for commons-math unchecked exceptions.
036    *
037    * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 f??vr. 2011) $
038    * @since 2.0
039    */
040    public class MathRuntimeException extends RuntimeException implements MathThrowable {
041    
042        /** Serializable version identifier. */
043        private static final long serialVersionUID = 9058794795027570002L;
044    
045        /**
046         * Pattern used to build the message.
047         */
048        private final Localizable pattern;
049    
050        /**
051         * Arguments used to build the message.
052         */
053        private final Object[] arguments;
054    
055        /**
056         * Constructs a new <code>MathRuntimeException</code> with specified
057         * formatted detail message.
058         * Message formatting is delegated to {@link java.text.MessageFormat}.
059         * @param pattern format specifier
060         * @param arguments format arguments
061         * @deprecated as of 2.2 replaced by {@link #MathRuntimeException(Localizable, Object...)}
062         */
063        @Deprecated
064        public MathRuntimeException(final String pattern, final Object ... arguments) {
065            this(new DummyLocalizable(pattern), arguments);
066        }
067    
068        /**
069         * Constructs a new <code>MathRuntimeException</code> with specified
070         * formatted detail message.
071         * Message formatting is delegated to {@link java.text.MessageFormat}.
072         * @param pattern format specifier
073         * @param arguments format arguments
074         * @since 2.2
075         */
076        public MathRuntimeException(final Localizable pattern, final Object ... arguments) {
077            this.pattern   = pattern;
078            this.arguments = (arguments == null) ? new Object[0] : arguments.clone();
079        }
080    
081        /**
082         * Constructs a new <code>MathRuntimeException</code> with specified
083         * nested <code>Throwable</code> root cause.
084         *
085         * @param rootCause  the exception or error that caused this exception
086         *                   to be thrown.
087         */
088        public MathRuntimeException(final Throwable rootCause) {
089            super(rootCause);
090            this.pattern   = LocalizedFormats.SIMPLE_MESSAGE;
091            this.arguments = new Object[] { (rootCause == null) ? "" : rootCause.getMessage() };
092        }
093    
094        /**
095         * Constructs a new <code>MathRuntimeException</code> with specified
096         * formatted detail message and nested <code>Throwable</code> root cause.
097         * Message formatting is delegated to {@link java.text.MessageFormat}.
098         * @param rootCause the exception or error that caused this exception
099         * 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    }