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 }