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.MissingResourceException; 028 import java.util.NoSuchElementException; 029 import java.util.ResourceBundle; 030 031 /** 032 * Base class for commons-math unchecked exceptions. 033 * 034 * @version $Revision: 786478 $ $Date: 2009-06-19 08:33:36 -0400 (Fri, 19 Jun 2009) $ 035 * @since 2.0 036 */ 037 public class MathRuntimeException extends RuntimeException { 038 039 /** Serializable version identifier. */ 040 private static final long serialVersionUID = -5128983364075381060L; 041 042 /** 043 * Pattern used to build the message. 044 */ 045 private final String pattern; 046 047 /** 048 * Arguments used to build the message. 049 */ 050 private final Object[] arguments; 051 052 /** 053 * Translate a string to a given locale. 054 * @param s string to translate 055 * @param locale locale into which to translate the string 056 * @return translated string or original string 057 * for unsupported locales or unknown strings 058 */ 059 private static String translate(final String s, final Locale locale) { 060 try { 061 ResourceBundle bundle = 062 ResourceBundle.getBundle("org.apache.commons.math.MessagesResources", locale); 063 if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) { 064 // the value of the resource is the translated string 065 return bundle.getString(s); 066 } 067 068 } catch (MissingResourceException mre) { 069 // do nothing here 070 } 071 072 // the locale is not supported or the resource is unknown 073 // don't translate and fall back to using the string as is 074 return s; 075 076 } 077 078 /** 079 * Builds a message string by from a pattern and its arguments. 080 * @param locale Locale in which the message should be translated 081 * @param pattern format specifier 082 * @param arguments format arguments 083 * @return a message string 084 */ 085 private static String buildMessage(final Locale locale, final String pattern, 086 final Object ... arguments) { 087 return (pattern == null) ? "" : new MessageFormat(translate(pattern, locale), locale).format(arguments); 088 } 089 090 /** 091 * Constructs a new <code>MathRuntimeException</code> with specified 092 * formatted detail message. 093 * Message formatting is delegated to {@link java.text.MessageFormat}. 094 * @param pattern format specifier 095 * @param arguments format arguments 096 */ 097 public MathRuntimeException(final String pattern, final Object ... arguments) { 098 super(buildMessage(Locale.US, pattern, arguments)); 099 this.pattern = pattern; 100 this.arguments = (arguments == null) ? new Object[0] : arguments.clone(); 101 } 102 103 /** 104 * Constructs a new <code>MathRuntimeException</code> with specified 105 * nested <code>Throwable</code> root cause. 106 * 107 * @param rootCause the exception or error that caused this exception 108 * to be thrown. 109 */ 110 public MathRuntimeException(final Throwable rootCause) { 111 super(rootCause); 112 this.pattern = getMessage(); 113 this.arguments = new Object[0]; 114 } 115 116 /** 117 * Constructs a new <code>MathRuntimeException</code> with specified 118 * formatted detail message and nested <code>Throwable</code> root cause. 119 * Message formatting is delegated to {@link java.text.MessageFormat}. 120 * @param rootCause the exception or error that caused this exception 121 * to be thrown. 122 * @param pattern format specifier 123 * @param arguments format arguments 124 */ 125 public MathRuntimeException(final Throwable rootCause, 126 final String pattern, final Object ... arguments) { 127 super(buildMessage(Locale.US, pattern, arguments), rootCause); 128 this.pattern = pattern; 129 this.arguments = (arguments == null) ? new Object[0] : arguments.clone(); 130 } 131 132 /** Gets the pattern used to build the message of this throwable. 133 * 134 * @return the pattern used to build the message of this throwable 135 */ 136 public String getPattern() { 137 return pattern; 138 } 139 140 /** Gets the arguments used to build the message of this throwable. 141 * 142 * @return the arguments used to build the message of this throwable 143 */ 144 public Object[] getArguments() { 145 return arguments.clone(); 146 } 147 148 /** Gets the message in a specified locale. 149 * 150 * @param locale Locale in which the message should be translated 151 * 152 * @return localized message 153 */ 154 public String getMessage(final Locale locale) { 155 return buildMessage(locale, pattern, arguments); 156 } 157 158 /** {@inheritDoc} */ 159 @Override 160 public String getLocalizedMessage() { 161 return getMessage(Locale.getDefault()); 162 } 163 164 /** 165 * Prints the stack trace of this exception to the standard error stream. 166 */ 167 @Override 168 public void printStackTrace() { 169 printStackTrace(System.err); 170 } 171 172 /** 173 * Prints the stack trace of this exception to the specified stream. 174 * 175 * @param out the <code>PrintStream</code> to use for output 176 */ 177 @Override 178 public void printStackTrace(final PrintStream out) { 179 synchronized (out) { 180 PrintWriter pw = new PrintWriter(out, false); 181 printStackTrace(pw); 182 // Flush the PrintWriter before it's GC'ed. 183 pw.flush(); 184 } 185 } 186 187 /** 188 * Constructs a new <code>ArithmeticException</code> with specified formatted detail message. 189 * Message formatting is delegated to {@link java.text.MessageFormat}. 190 * @param pattern format specifier 191 * @param arguments format arguments 192 * @return built exception 193 */ 194 public static ArithmeticException createArithmeticException(final String pattern, 195 final Object ... arguments) { 196 return new ArithmeticException(buildMessage(Locale.US, pattern, arguments)) { 197 198 /** Serializable version identifier. */ 199 private static final long serialVersionUID = 7705628723242533939L; 200 201 /** {@inheritDoc} */ 202 @Override 203 public String getLocalizedMessage() { 204 return buildMessage(Locale.getDefault(), pattern, arguments); 205 } 206 207 }; 208 } 209 210 /** 211 * Constructs a new <code>ArrayIndexOutOfBoundsException</code> with specified formatted detail message. 212 * Message formatting is delegated to {@link java.text.MessageFormat}. 213 * @param pattern format specifier 214 * @param arguments format arguments 215 * @return built exception 216 */ 217 public static ArrayIndexOutOfBoundsException createArrayIndexOutOfBoundsException(final String pattern, 218 final Object ... arguments) { 219 return new ArrayIndexOutOfBoundsException(buildMessage(Locale.US, pattern, arguments)) { 220 221 /** Serializable version identifier. */ 222 private static final long serialVersionUID = -3394748305449283486L; 223 224 /** {@inheritDoc} */ 225 @Override 226 public String getLocalizedMessage() { 227 return buildMessage(Locale.getDefault(), pattern, arguments); 228 } 229 230 }; 231 } 232 233 /** 234 * Constructs a new <code>EOFException</code> with specified formatted detail message. 235 * Message formatting is delegated to {@link java.text.MessageFormat}. 236 * @param pattern format specifier 237 * @param arguments format arguments 238 * @return built exception 239 */ 240 public static EOFException createEOFException(final String pattern, 241 final Object ... arguments) { 242 return new EOFException(buildMessage(Locale.US, pattern, arguments)) { 243 244 /** Serializable version identifier. */ 245 private static final long serialVersionUID = 279461544586092584L; 246 247 /** {@inheritDoc} */ 248 @Override 249 public String getLocalizedMessage() { 250 return buildMessage(Locale.getDefault(), pattern, arguments); 251 } 252 253 }; 254 } 255 256 /** 257 * Constructs a new <code>IOException</code> with specified nested 258 * <code>Throwable</code> root cause. 259 * <p>This factory method allows chaining of other exceptions within an 260 * <code>IOException</code> even for Java 5. The constructor for 261 * <code>IOException</code> with a cause parameter was introduced only 262 * with Java 6.</p> 263 * @param rootCause the exception or error that caused this exception 264 * to be thrown. 265 * @return built exception 266 */ 267 public static IOException createIOException(final Throwable rootCause) { 268 IOException ioe = new IOException(rootCause.getLocalizedMessage()); 269 ioe.initCause(rootCause); 270 return ioe; 271 } 272 273 /** 274 * Constructs a new <code>IllegalArgumentException</code> with specified formatted detail message. 275 * Message formatting is delegated to {@link java.text.MessageFormat}. 276 * @param pattern format specifier 277 * @param arguments format arguments 278 * @return built exception 279 */ 280 public static IllegalArgumentException createIllegalArgumentException(final String pattern, 281 final Object ... arguments) { 282 return new IllegalArgumentException(buildMessage(Locale.US, pattern, arguments)) { 283 284 /** Serializable version identifier. */ 285 private static final long serialVersionUID = -6555453980658317913L; 286 287 /** {@inheritDoc} */ 288 @Override 289 public String getLocalizedMessage() { 290 return buildMessage(Locale.getDefault(), pattern, arguments); 291 } 292 293 }; 294 } 295 296 /** 297 * Constructs a new <code>IllegalArgumentException</code> with specified nested 298 * <code>Throwable</code> root cause. 299 * @param rootCause the exception or error that caused this exception 300 * to be thrown. 301 * @return built exception 302 */ 303 public static IllegalArgumentException createIllegalArgumentException(final Throwable rootCause) { 304 IllegalArgumentException iae = new IllegalArgumentException(rootCause.getLocalizedMessage()); 305 iae.initCause(rootCause); 306 return iae; 307 } 308 309 /** 310 * Constructs a new <code>IllegalStateException</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 */ 316 public static IllegalStateException createIllegalStateException(final String pattern, 317 final Object ... arguments) { 318 return new IllegalStateException(buildMessage(Locale.US, pattern, arguments)) { 319 320 /** Serializable version identifier. */ 321 private static final long serialVersionUID = -95247648156277208L; 322 323 /** {@inheritDoc} */ 324 @Override 325 public String getLocalizedMessage() { 326 return buildMessage(Locale.getDefault(), pattern, arguments); 327 } 328 329 }; 330 } 331 332 /** 333 * Constructs a new <code>ConcurrentModificationException</code> with specified formatted detail message. 334 * Message formatting is delegated to {@link java.text.MessageFormat}. 335 * @param pattern format specifier 336 * @param arguments format arguments 337 * @return built exception 338 */ 339 public static ConcurrentModificationException createConcurrentModificationException(final String pattern, 340 final Object ... arguments) { 341 return new ConcurrentModificationException(buildMessage(Locale.US, pattern, arguments)) { 342 343 /** Serializable version identifier. */ 344 private static final long serialVersionUID = 6134247282754009421L; 345 346 /** {@inheritDoc} */ 347 @Override 348 public String getLocalizedMessage() { 349 return buildMessage(Locale.getDefault(), pattern, arguments); 350 } 351 352 }; 353 } 354 355 /** 356 * Constructs a new <code>NoSuchElementException</code> with specified formatted detail message. 357 * Message formatting is delegated to {@link java.text.MessageFormat}. 358 * @param pattern format specifier 359 * @param arguments format arguments 360 * @return built exception 361 */ 362 public static NoSuchElementException createNoSuchElementException(final String pattern, 363 final Object ... arguments) { 364 return new NoSuchElementException(buildMessage(Locale.US, pattern, arguments)) { 365 366 /** Serializable version identifier. */ 367 private static final long serialVersionUID = 7304273322489425799L; 368 369 /** {@inheritDoc} */ 370 @Override 371 public String getLocalizedMessage() { 372 return buildMessage(Locale.getDefault(), pattern, arguments); 373 } 374 375 }; 376 } 377 378 /** 379 * Constructs a new <code>NullPointerException</code> with specified formatted detail message. 380 * Message formatting is delegated to {@link java.text.MessageFormat}. 381 * @param pattern format specifier 382 * @param arguments format arguments 383 * @return built exception 384 */ 385 public static NullPointerException createNullPointerException(final String pattern, 386 final Object ... arguments) { 387 return new NullPointerException(buildMessage(Locale.US, pattern, arguments)) { 388 389 /** Serializable version identifier. */ 390 private static final long serialVersionUID = -3075660477939965216L; 391 392 /** {@inheritDoc} */ 393 @Override 394 public String getLocalizedMessage() { 395 return buildMessage(Locale.getDefault(), pattern, arguments); 396 } 397 398 }; 399 } 400 401 /** 402 * Constructs a new <code>ParseException</code> with specified 403 * formatted detail message. 404 * Message formatting is delegated to {@link java.text.MessageFormat}. 405 * @param offset offset at which error occurred 406 * @param pattern format specifier 407 * @param arguments format arguments 408 * @return built exception 409 */ 410 public static ParseException createParseException(final int offset, 411 final String pattern, 412 final Object ... arguments) { 413 return new ParseException(buildMessage(Locale.US, pattern, arguments), offset) { 414 415 /** Serializable version identifier. */ 416 private static final long serialVersionUID = -1103502177342465975L; 417 418 /** {@inheritDoc} */ 419 @Override 420 public String getLocalizedMessage() { 421 return buildMessage(Locale.getDefault(), pattern, arguments); 422 } 423 424 }; 425 } 426 427 /** Create an {@link java.lang.RuntimeException} for an internal error. 428 * @param cause underlying cause 429 * @return an {@link java.lang.RuntimeException} for an internal error 430 */ 431 public static RuntimeException createInternalError(final Throwable cause) { 432 433 final String pattern = "internal error, please fill a bug report at {0}"; 434 final String argument = "https://issues.apache.org/jira/browse/MATH"; 435 436 return new RuntimeException(buildMessage(Locale.US, pattern, argument)) { 437 438 /** Serializable version identifier. */ 439 private static final long serialVersionUID = -201865440834027016L; 440 441 /** {@inheritDoc} */ 442 @Override 443 public String getLocalizedMessage() { 444 return buildMessage(Locale.getDefault(), pattern, argument); 445 } 446 447 }; 448 449 } 450 451 }