View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math;
18  
19  import java.io.PrintStream;
20  import java.io.PrintWriter;
21  import java.text.MessageFormat;
22  import java.util.Locale;
23  import java.util.MissingResourceException;
24  import java.util.ResourceBundle;
25  
26  
27  /**
28  * Base class for commons-math checked exceptions.
29  * <p>
30  * Supports nesting, emulating JDK 1.4 behavior if necessary.</p>
31  * <p>
32  * Adapted from {@link org.apache.commons.collections.FunctorException}.</p>
33  * 
34  * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $
35  */
36  public class MathException extends Exception {
37      
38      /** Serializable version identifier */
39      private static final long serialVersionUID = -8602234299177097102L;
40  
41      /**
42       * Does JDK support nested exceptions?
43       */
44      private static final boolean JDK_SUPPORTS_NESTED;
45      
46      static {
47          boolean flag = false;
48          try {
49              Throwable.class.getDeclaredMethod("getCause", new Class[0]);
50              flag = true;
51          } catch (NoSuchMethodException ex) {
52              flag = false;
53          }
54          JDK_SUPPORTS_NESTED = flag;
55      }
56  
57      /** Cache for resources bundle. */
58      private static ResourceBundle cachedResources = null;
59   
60      /**
61       * Pattern used to build the message.
62       */
63      private final String pattern;
64  
65      /**
66       * Arguments used to build the message.
67       */
68      private final Object[] arguments;
69  
70      /**
71       * Root cause of the exception
72       */
73      private final Throwable rootCause;
74      
75      /**
76       * Translate a string to a given locale.
77       * @param s string to translate
78       * @param locale locale into which to translate the string
79       * @return translated string or original string
80       * for unsupported locales or unknown strings
81       */
82      private static String translate(String s, Locale locale) {
83          try {
84              if ((cachedResources == null) || (! cachedResources.getLocale().equals(locale))) {
85                  // caching the resource bundle
86                  cachedResources =
87                      ResourceBundle.getBundle("org.apache.commons.math.MessagesResources", locale);
88              }
89  
90              if (cachedResources.getLocale().getLanguage().equals(locale.getLanguage())) {
91                  // the value of the resource is the translated string
92                  return cachedResources.getString(s);
93              }
94              
95          } catch (MissingResourceException mre) {
96              // do nothing here
97          }
98  
99          // the locale is not supported or the resource is unknown
100         // don't translate and fall back to using the string as is
101         return s;
102 
103     }
104 
105     /**
106      * Builds a message string by from a pattern and its arguments.
107      * @param pattern format specifier
108      * @param arguments format arguments
109      * @param locale Locale in which the message should be translated
110      * @return a message string
111      */
112     private static String buildMessage(String pattern, Object[] arguments, Locale locale) {
113         // do it the hard way, for Java 1.3. compatibility
114         MessageFormat mf = new MessageFormat(translate(pattern, locale));
115         mf.setLocale(locale);
116         return mf.format(arguments);        
117     }
118 
119     /**
120      * Constructs a new <code>MathException</code> with no
121      * detail message.
122      */
123     public MathException() {
124         super();
125         this.pattern   = null;
126         this.arguments = new Object[0];
127         this.rootCause = null;
128     }
129     
130     /**
131      * Constructs a new <code>MathException</code> with specified
132      * detail message.
133      *
134      * @param msg  the error message.
135      * @deprecated as of 1.2, replaced by {@link #MathException(String, Object[])}
136      */
137     public MathException(String msg) {
138         super(msg);
139         this.pattern   = msg;
140         this.arguments = new Object[0];
141         this.rootCause = null;
142     }
143 
144     /**
145      * Constructs a new <code>MathException</code> with specified
146      * formatted detail message.
147      * Message formatting is delegated to {@link java.text.MessageFormat}.
148      * @param pattern format specifier
149      * @param arguments format arguments
150      */
151     public MathException(String pattern, Object[] arguments) {
152       super(buildMessage(pattern, arguments, Locale.US));
153       this.pattern   = pattern;
154       this.arguments = (Object[]) arguments.clone();
155       this.rootCause = null;
156     }
157 
158     /**
159      * Constructs a new <code>MathException</code> with specified
160      * nested <code>Throwable</code> root cause.
161      *
162      * @param rootCause  the exception or error that caused this exception
163      *                   to be thrown.
164      */
165     public MathException(Throwable rootCause) {
166         super((rootCause == null ? null : rootCause.getMessage()));
167         this.pattern   = getMessage();
168         this.arguments = new Object[0];
169         this.rootCause = rootCause;
170     }
171     
172     /**
173      * Constructs a new <code>MathException</code> with specified
174      * detail message and nested <code>Throwable</code> root cause.
175      *
176      * @param msg  the error message.
177      * @param rootCause  the exception or error that caused this exception
178      *                   to be thrown.
179      * @deprecated as of 1.2, replaced by {@link #MathException(String, Object[], Throwable)}
180      */
181     public MathException(String msg, Throwable rootCause) {
182         super(msg);
183         this.pattern   = msg;
184         this.arguments = new Object[0];
185         this.rootCause = rootCause;
186     }
187 
188     /**
189      * Constructs a new <code>MathException</code> with specified
190      * formatted detail message and nested <code>Throwable</code> root cause.
191      * Message formatting is delegated to {@link java.text.MessageFormat}.
192      * @param pattern format specifier
193      * @param arguments format arguments
194      * @param rootCause the exception or error that caused this exception
195      * to be thrown.
196      * @since 1.2
197      */
198     public MathException(String pattern, Object[] arguments, Throwable rootCause) {
199       super(buildMessage(pattern, arguments, Locale.US));
200       this.pattern   = pattern;
201       this.arguments = (Object[]) arguments.clone();
202       this.rootCause = rootCause;
203     }
204 
205     /** Gets the pattern used to build the message of this throwable.
206      *
207      * @return the pattern used to build the message of this throwable
208      * @since 1.2
209      */
210     public String getPattern() {
211         return pattern;
212     }
213 
214     /** Gets the arguments used to build the message of this throwable.
215      *
216      * @return the arguments used to build the message of this throwable
217      * @since 1.2
218      */
219     public Object[] getArguments() {
220         return (Object[]) arguments.clone();
221     }
222 
223     /** Gets the message in a specified locale.
224      *
225      * @param locale Locale in which the message should be translated
226      * 
227      * @return localized message
228      * @since 1.2
229      */
230     public String getMessage(Locale locale) {
231         return (pattern == null) ? null : buildMessage(pattern, arguments, locale);
232     }
233 
234     /**
235      * Gets the cause of this throwable.
236      * 
237      * @return  the cause of this throwable, or <code>null</code>
238      */
239     public Throwable getCause() {
240         return rootCause;
241     }
242     
243     /**
244      * Prints the stack trace of this exception to the standard error stream.
245      */
246     public void printStackTrace() {
247         printStackTrace(System.err);
248     }
249     
250     /**
251      * Prints the stack trace of this exception to the specified stream.
252      *
253      * @param out  the <code>PrintStream</code> to use for output
254      */
255     public void printStackTrace(PrintStream out) {
256         synchronized (out) {
257             PrintWriter pw = new PrintWriter(out, false);
258             printStackTrace(pw);
259             // Flush the PrintWriter before it's GC'ed.
260             pw.flush();
261         }
262     }
263     
264     /**
265      * Prints the stack trace of this exception to the specified writer.
266      *
267      * @param out  the <code>PrintWriter</code> to use for output
268      */
269     public void printStackTrace(PrintWriter out) {
270         synchronized (out) {
271             super.printStackTrace(out);
272             if (rootCause != null && JDK_SUPPORTS_NESTED == false) {
273                 out.print("Caused by: ");
274                 rootCause.printStackTrace(out);
275             }
276         }
277     }
278 
279 }