blob: afbf186aa77390b02c311dc152ddf81b4494bde1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* The <code>InternationalizedException</code> class adds internationalization
* support to the standard functionality provided by
* <code>java.lang.Exception</code>.
* <p>
* To support internationalization, the thrower of an exception must not specify
* a hardcoded message string. Instead, the thrower specifies a key that
* identifies the message. That key is then looked up in a locale-specific
* {@link java.util.ResourceBundle ResourceBundle} to find the actual message
* associated with this exception.
* <p>
* This class also supports arguments to messages. The full message will be
* constructed using the {@link java.text.MessageFormat MessageFormat} class.
* For more information on internationalization, see the <a
* href="http://java.sun.com/j2se/1.4/docs/guide/intl/index.html"> Java
* Internationalization Guide</a>.
* <p>
* This version of this class works with JDK versions prior to 1.4, since it
* does not assume support for exception chaining. The file
* <code>InternationalizedException.java_1_4</code> is a version that uses the
* exception chaining support built-in to JDK1.4.
*
*
*/
public class InternationalizedException extends Exception {
private static final long serialVersionUID = 2306587442280738385L;
/**
* The base name of the resource bundle in which the message for this
* exception is located.
*/
private String mResourceBundleName;
/**
* An identifier that maps to the message for this exception.
*/
private String mMessageKey;
/**
* The arguments to this exception's message, if any. This allows an
* <code>InternationalizedException</code> to have a compound message, made
* up of multiple parts that are concatenated in a language-neutral way.
*/
private Object[] mArguments;
/**
* The exception that caused this exception to occur.
*/
private Throwable mCause;
/**
* Creates a new <code>InternationalizedException</code> with a null
* message.
*/
public InternationalizedException() {
this(null, null, null, null);
}
/**
* Creates a new <code>InternationalizedException</code> with the specified
* cause and a null message.
*
* @param aCause
* the original exception that caused this exception to be thrown,
* if any
*/
public InternationalizedException(Throwable aCause) {
this(null, null, null, aCause);
}
/**
* Creates a new <code>InternationalizedException</code> with the specified
* message.
*
* @param aResourceBundleName
* the base name of the resource bundle in which the message for
* this exception is located.
* @param aMessageKey
* an identifier that maps to the message for this exception. The
* message may contain placeholders for arguments as defined by the
* {@link java.text.MessageFormat MessageFormat} class.
* @param aArguments
* The arguments to the message. <code>null</code> may be used if
* the message has no arguments.
*/
public InternationalizedException(String aResourceBundleName,
String aMessageKey, Object[] aArguments) {
this(aResourceBundleName, aMessageKey, aArguments, null);
}
/**
* Creates a new <code>InternationalizedException</code> with the specified
* message and cause.
*
* @param aResourceBundleName
* the base name of the resource bundle in which the message for
* this exception is located.
* @param aMessageKey
* an identifier that maps to the message for this exception. The
* message may contain placeholders for arguments as defined by the
* {@link java.text.MessageFormat MessageFormat} class.
* @param aArguments
* The arguments to the message. <code>null</code> may be used if
* the message has no arguments.
* @param aCause
* the original exception that caused this exception to be thrown,
* if any
*/
public InternationalizedException(String aResourceBundleName,
String aMessageKey, Object[] aArguments, Throwable aCause) {
super();
mCause = aCause;
mResourceBundleName = aResourceBundleName;
mMessageKey = aMessageKey;
mArguments = aArguments;
// if null message and mCause is Internationalized exception, "promote"
// message
if (mResourceBundleName == null && mMessageKey == null) {
if (mCause instanceof InternationalizedException) {
mResourceBundleName = ((InternationalizedException) mCause)
.getResourceBundleName();
mMessageKey = ((InternationalizedException) mCause).getMessageKey();
mArguments = ((InternationalizedException) mCause).getArguments();
} else if (mCause instanceof InternationalizedRuntimeException) {
mResourceBundleName = ((InternationalizedRuntimeException) mCause)
.getResourceBundleName();
mMessageKey = ((InternationalizedRuntimeException) mCause)
.getMessageKey();
mArguments = ((InternationalizedRuntimeException) mCause)
.getArguments();
}
}
}
/**
* Gets the base name of the resource bundle in which the message for this
* exception is located.
*
* @return the resource bundle base name. May return <code>null</code> if
* this exception has no message.
*/
public String getResourceBundleName() {
return mResourceBundleName;
}
/**
* Gets the identifier for this exception's message. This identifier can be
* looked up in this exception's
* {@link java.util.ResourceBundle ResourceBundle} to get the locale-specific
* message for this exception.
*
* @return the resource identifier for this exception's message. May return
* <code>null</code> if this exception has no message.
*/
public String getMessageKey() {
return mMessageKey;
}
/**
* Gets the arguments to this exception's message. Arguments allow a
* <code>InternationalizedException</code> to have a compound message, made
* up of multiple parts that are concatenated in a language-neutral way.
*
* @return the arguments to this exception's message.
*/
public Object[] getArguments() {
if (mArguments == null)
return new Object[0];
Object[] result = new Object[mArguments.length];
System.arraycopy(mArguments, 0, result, 0, mArguments.length);
return result;
}
/**
* Gets the <i>English</i> detail message for this exception. For the
* localized message use {@link #getLocalizedMessage()}.
*
* @return the English detail message for this exception.
*/
public String getMessage() {
return getLocalizedMessage(Locale.ENGLISH);
}
/**
* Gets the localized detail message for this exception. This uses the
* default Locale for this JVM. A Locale may be specified using
* {@link #getLocalizedMessage(Locale)}.
*
* @return this exception's detail message, localized for the default Locale.
*/
public String getLocalizedMessage() {
return getLocalizedMessage(Locale.getDefault());
}
/**
* Gets the localized detail message for this exception using the specified
* <code>Locale</code>.
*
* @param aLocale
* the locale to use for localizing the message
*
* @return this exception's detail message, localized for the specified
* <code>Locale</code>.
*/
public String getLocalizedMessage(Locale aLocale) {
// check for null message
if (getMessageKey() == null)
return null;
try {
// locate the resource bundle for this exception's messages
// turn over the classloader of the current object explicitly, so that the
// message resolving also works for derived exception classes
ResourceBundle bundle = ResourceBundle.getBundle(
getResourceBundleName(), aLocale, this.getClass()
.getClassLoader());
// retrieve the message from the resource bundle
String message = bundle.getString(getMessageKey());
// if arguments exist, use MessageFormat to include them
if (getArguments().length > 0) {
MessageFormat fmt = new MessageFormat(message);
fmt.setLocale(aLocale);
return fmt.format(getArguments());
} else
return message;
} catch (Exception e) {
return "EXCEPTION MESSAGE LOCALIZATION FAILED: " + e.toString();
}
}
/**
* Gets the cause of this Exception.
*
* @return the Throwable that caused this Exception to occur, if any. Returns
* <code>null</code> if there is no such cause.
*/
public Throwable getCause() {
return mCause;
}
/**
* Checks if this exception, or any of its root causes, has a particular UIMA
* message key. This allows checking for particular error condition
*
* @param messageKey
* to search for in the exception chain
* @return
*/
public boolean hasMessageKey(String messageKey) {
if (messageKey.equals(this.getMessageKey())) {
return true;
}
Throwable cause = getCause();
if (cause != null && cause instanceof InternationalizedException) {
return ((InternationalizedException) cause).hasMessageKey(messageKey);
}
return false;
}
public synchronized Throwable initCause(Throwable cause) {
mCause = cause;
return this;
}
}