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 }