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