| /* |
| * 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. |
| */ |
| /* |
| * $Id: Messages.java 468654 2006-10-28 07:09:23Z minchau $ |
| */ |
| package org.apache.xml.serializer.utils; |
| |
| import java.util.ListResourceBundle; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| |
| /** |
| * A utility class for issuing error messages. |
| * |
| * A user of this class normally would create a singleton |
| * instance of this class, passing the name |
| * of the message class on the constructor. For example: |
| * <CODE> |
| * static Messages x = new Messages("org.package.MyMessages"); |
| * </CODE> |
| * Later the message is typically generated this way if there are no |
| * substitution arguments: |
| * <CODE> |
| * String msg = x.createMessage(org.package.MyMessages.KEY_ONE, null); |
| * </CODE> |
| * If there are arguments substitutions then something like this: |
| * <CODE> |
| * String filename = ...; |
| * String directory = ...; |
| * String msg = x.createMessage(org.package.MyMessages.KEY_TWO, |
| * new Object[] {filename, directory) ); |
| * </CODE> |
| * |
| * The constructor of an instance of this class must be given |
| * the class name of a class that extends java.util.ListResourceBundle |
| * ("org.package.MyMessages" in the example above). |
| * The name should not have any language suffix |
| * which will be added automatically by this utility class. |
| * |
| * The message class ("org.package.MyMessages") |
| * must define the abstract method getContents() that is |
| * declared in its base class, for example: |
| * <CODE> |
| * public Object[][] getContents() {return contents;} |
| * </CODE> |
| * |
| * It is suggested that the message class expose its |
| * message keys like this: |
| * <CODE> |
| * public static final String KEY_ONE = "KEY1"; |
| * public static final String KEY_TWO = "KEY2"; |
| * . . . |
| * </CODE> |
| * and used through their names (KEY_ONE ...) rather than |
| * their values ("KEY1" ...). |
| * |
| * The field contents (returned by getContents() |
| * should be initialized something like this: |
| * <CODE> |
| * public static final Object[][] contents = { |
| * { KEY_ONE, "Something has gone wrong!" }, |
| * { KEY_TWO, "The file ''{0}'' does not exist in directory ''{1}''." }, |
| * . . . |
| * { KEY_N, "Message N" } } |
| * </CODE> |
| * |
| * Where that section of code with the KEY to Message mappings |
| * (where the message classes 'contents' field is initialized) |
| * can have the Message strings translated in an alternate language |
| * in a errorResourceClass with a language suffix. |
| * |
| * More sophisticated use of this class would be to pass null |
| * when contructing it, but then call loadResourceBundle() |
| * before creating any messages. |
| * |
| * This class is not a public API, it is only public because it is |
| * used in org.apache.xml.serializer. |
| * |
| * @xsl.usage internal |
| */ |
| public final class Messages |
| { |
| /** The local object to use. */ |
| private final Locale m_locale = Locale.getDefault(); |
| |
| /** The language specific resource object for messages. */ |
| private ListResourceBundle m_resourceBundle; |
| |
| /** The class name of the error message string table with no language suffix. */ |
| private String m_resourceBundleName; |
| |
| |
| |
| /** |
| * Constructor. |
| * @param resourceBundle the class name of the ListResourceBundle |
| * that the instance of this class is associated with and will use when |
| * creating messages. |
| * The class name is without a language suffix. If the value passed |
| * is null then loadResourceBundle(errorResourceClass) needs to be called |
| * explicitly before any messages are created. |
| * |
| * @xsl.usage internal |
| */ |
| Messages(String resourceBundle) |
| { |
| |
| m_resourceBundleName = resourceBundle; |
| } |
| |
| /* |
| * Set the Locale object to use. If this method is not called the |
| * default locale is used. This method needs to be called before |
| * loadResourceBundle(). |
| * |
| * @param locale non-null reference to Locale object. |
| * @xsl.usage internal |
| */ |
| // public void setLocale(Locale locale) |
| // { |
| // m_locale = locale; |
| // } |
| |
| /** |
| * Get the Locale object that is being used. |
| * |
| * @return non-null reference to Locale object. |
| * @xsl.usage internal |
| */ |
| private Locale getLocale() |
| { |
| return m_locale; |
| } |
| |
| /** |
| * Get the ListResourceBundle being used by this Messages instance which was |
| * previously set by a call to loadResourceBundle(className) |
| * @xsl.usage internal |
| */ |
| private ListResourceBundle getResourceBundle() |
| { |
| return m_resourceBundle; |
| } |
| |
| /** |
| * Creates a message from the specified key and replacement |
| * arguments, localized to the given locale. |
| * |
| * @param msgKey The key for the message text. |
| * @param args The arguments to be used as replacement text |
| * in the message created. |
| * |
| * @return The formatted message string. |
| * @xsl.usage internal |
| */ |
| public final String createMessage(String msgKey, Object args[]) |
| { |
| if (m_resourceBundle == null) |
| m_resourceBundle = loadResourceBundle(m_resourceBundleName); |
| |
| if (m_resourceBundle != null) |
| { |
| return createMsg(m_resourceBundle, msgKey, args); |
| } |
| else |
| return "Could not load the resource bundles: "+ m_resourceBundleName; |
| } |
| |
| /** |
| * Creates a message from the specified key and replacement |
| * arguments, localized to the given locale. |
| * |
| * @param errorCode The key for the message text. |
| * |
| * @param fResourceBundle The resource bundle to use. |
| * @param msgKey The message key to use. |
| * @param args The arguments to be used as replacement text |
| * in the message created. |
| * |
| * @return The formatted message string. |
| * @xsl.usage internal |
| */ |
| private final String createMsg( |
| ListResourceBundle fResourceBundle, |
| String msgKey, |
| Object args[]) //throws Exception |
| { |
| |
| String fmsg = null; |
| boolean throwex = false; |
| String msg = null; |
| |
| if (msgKey != null) |
| msg = fResourceBundle.getString(msgKey); |
| else |
| msgKey = ""; |
| |
| if (msg == null) |
| { |
| throwex = true; |
| /* The message is not in the bundle . . . this is bad, |
| * so try to get the message that the message is not in the bundle |
| */ |
| try |
| { |
| |
| msg = |
| java.text.MessageFormat.format( |
| MsgKey.BAD_MSGKEY, |
| new Object[] { msgKey, m_resourceBundleName }); |
| } |
| catch (Exception e) |
| { |
| /* even the message that the message is not in the bundle is |
| * not there ... this is really bad |
| */ |
| msg = |
| "The message key '" |
| + msgKey |
| + "' is not in the message class '" |
| + m_resourceBundleName+"'"; |
| } |
| } |
| else if (args != null) |
| { |
| try |
| { |
| // Do this to keep format from crying. |
| // This is better than making a bunch of conditional |
| // code all over the place. |
| int n = args.length; |
| |
| for (int i = 0; i < n; i++) |
| { |
| if (null == args[i]) |
| args[i] = ""; |
| } |
| |
| fmsg = java.text.MessageFormat.format(msg, args); |
| // if we get past the line above we have create the message ... hurray! |
| } |
| catch (Exception e) |
| { |
| throwex = true; |
| try |
| { |
| // Get the message that the format failed. |
| fmsg = |
| java.text.MessageFormat.format( |
| MsgKey.BAD_MSGFORMAT, |
| new Object[] { msgKey, m_resourceBundleName }); |
| fmsg += " " + msg; |
| } |
| catch (Exception formatfailed) |
| { |
| // We couldn't even get the message that the format of |
| // the message failed ... so fall back to English. |
| fmsg = |
| "The format of message '" |
| + msgKey |
| + "' in message class '" |
| + m_resourceBundleName |
| + "' failed."; |
| } |
| } |
| } |
| else |
| fmsg = msg; |
| |
| if (throwex) |
| { |
| throw new RuntimeException(fmsg); |
| } |
| |
| return fmsg; |
| } |
| |
| /** |
| * Return a named ResourceBundle for a particular locale. This method mimics the behavior |
| * of ResourceBundle.getBundle(). |
| * |
| * @param className the name of the class that implements ListResourceBundle, |
| * without language suffix. |
| * @return the ResourceBundle |
| * @throws MissingResourceException |
| * @xsl.usage internal |
| */ |
| private ListResourceBundle loadResourceBundle(String resourceBundle) |
| throws MissingResourceException |
| { |
| m_resourceBundleName = resourceBundle; |
| Locale locale = getLocale(); |
| |
| ListResourceBundle lrb; |
| |
| try |
| { |
| |
| ResourceBundle rb = |
| ResourceBundle.getBundle(m_resourceBundleName, locale); |
| lrb = (ListResourceBundle) rb; |
| } |
| catch (MissingResourceException e) |
| { |
| try // try to fall back to en_US if we can't load |
| { |
| |
| // Since we can't find the localized property file, |
| // fall back to en_US. |
| lrb = |
| (ListResourceBundle) ResourceBundle.getBundle( |
| m_resourceBundleName, |
| new Locale("en", "US")); |
| } |
| catch (MissingResourceException e2) |
| { |
| |
| // Now we are really in trouble. |
| // very bad, definitely very bad...not going to get very far |
| throw new MissingResourceException( |
| "Could not load any resource bundles." + m_resourceBundleName, |
| m_resourceBundleName, |
| ""); |
| } |
| } |
| m_resourceBundle = lrb; |
| return lrb; |
| } |
| |
| /** |
| * Return the resource file suffic for the indicated locale |
| * For most locales, this will be based the language code. However |
| * for Chinese, we do distinguish between Taiwan and PRC |
| * |
| * @param locale the locale |
| * @return an String suffix which can be appended to a resource name |
| * @xsl.usage internal |
| */ |
| private static String getResourceSuffix(Locale locale) |
| { |
| |
| String suffix = "_" + locale.getLanguage(); |
| String country = locale.getCountry(); |
| |
| if (country.equals("TW")) |
| suffix += "_" + country; |
| |
| return suffix; |
| } |
| } |