--- /dev/null
+/*\r
+ Derby - Class org.apache.derby.common.i18n.MessageUtil\r
+ \r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+ \r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+ \r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+ \r
+ */\r
+package org.apache.derby.shared.common.i18n;\r
+\r
+import org.apache.derby.shared.common.error.ExceptionSeverity;\r
+import org.apache.derby.shared.common.sanity.SanityManager;\r
+import java.util.Locale;\r
+import java.util.ResourceBundle;\r
+import java.util.MissingResourceException;\r
+import java.text.MessageFormat;\r
+\r
+/**\r
+ * Class comments here\r
+ */\r
+public class MessageUtil\r
+{ \r
+ public static final Locale US = new Locale("en", "US");\r
+ \r
+ /** \r
+ * The name of the resource bundle we are using to load\r
+ * messages\r
+ */\r
+ private String resourceBundleName;\r
+ \r
+ /**\r
+ * Create an instance of MessageUtil with a specific resource\r
+ * bundle. This assumes the default locale, which is just fine for\r
+ * users of this class other than the engine (which potentially has\r
+ * a different locale and a different resource bundle for each\r
+ * invocation of getCompleteMessage().\r
+ *\r
+ * @param resourceBundleName\r
+ * The base name of the resource bundle to use.\r
+ */\r
+ public MessageUtil(String resourceBundleName)\r
+ {\r
+ this.resourceBundleName = resourceBundleName;\r
+ }\r
+ \r
+ /** Get a message with default locale - no arguments */\r
+ public String getTextMessage(String messageID) \r
+ {\r
+ return getCompleteMessage(messageID, (Object[]) null);\r
+ }\r
+ \r
+ /** Get a message with default locale - one argument */\r
+ public String getTextMessage(String messageID, Object a1) \r
+ {\r
+ return getCompleteMessage(messageID, new Object[]{a1});\r
+ }\r
+ \r
+ /** Get a message with default locale - two arguments */\r
+ public String getTextMessage(String messageID, Object a1, Object a2) \r
+ {\r
+ return getCompleteMessage(messageID, new Object[]{a1, a2});\r
+ }\r
+ \r
+ /** Get a message with default locale - three arguments */\r
+ public String getTextMessage(String messageID, Object a1, Object a2, \r
+ Object a3) \r
+ {\r
+ return getCompleteMessage(messageID, new Object[]{a1, a2, a3});\r
+ }\r
+ \r
+ /** Get a message with default locale - four arguments */\r
+ public String getTextMessage(String messageID, Object a1, Object a2, \r
+ Object a3, Object a4) \r
+ {\r
+ return getCompleteMessage(messageID, new Object[]{a1, a2, a3, a4});\r
+ }\r
+ \r
+ /** \r
+ * Instance method to get the complete message, using the\r
+ * provided resource bundle name as specified when this\r
+ * instance was constructed\r
+ *\r
+ * If for some reason the message could not be found, we return a\r
+ * default message using the message arguments\r
+ */\r
+ public String getCompleteMessage(String messageID, Object[] args)\r
+ {\r
+ return getCompleteMessage(messageID, resourceBundleName, args);\r
+ }\r
+ \r
+ /**\r
+ * Generic routine to get a message with any number of arguments.\r
+ * \r
+ * Looks in the provided resource bundle for the message, using the\r
+ * specified locale and then the US locale. \r
+ * \r
+ * @param locale\r
+ * The locale to use when looking for the message. If the message\r
+ * is not found using this locale, we attempt to find it using the\r
+ * US locale (our default).\r
+ * \r
+ * @param resourceBundleName\r
+ * The base name for the resource bundle to use. \r
+ * \r
+ * @param messageId \r
+ * The message identifier for this message\r
+ * \r
+ * @param arguments\r
+ * The arguments for the message\r
+ * \r
+ * @param composeDefault\r
+ * If this is true, this method will compose a default message if\r
+ * the message could not be found in the\r
+ * provided resource bundles. If it is false, this method will\r
+ * throw a MissingResourceException if the message could not be\r
+ * found.\r
+ * \r
+ * @return\r
+ * The message for the given message id, with arguments\r
+ * substituted.\r
+ * \r
+ * @throws MissingResourceException\r
+ * If the message could not be found and the \r
+ * <code>composeDefault</code> parameter was set to false. \r
+ */\r
+ public static String getCompleteMessage(Locale locale, \r
+ String resourceBundleName, String messageId, Object[] arguments, \r
+ boolean composeDefault) throws MissingResourceException\r
+ {\r
+ try\r
+ {\r
+ return formatMessage(\r
+ ResourceBundle.getBundle(resourceBundleName, locale), messageId,\r
+ arguments, false);\r
+ }\r
+ catch ( MissingResourceException mre )\r
+ {\r
+ // Try the US locale. Use composeDefault to indicate whether\r
+ // we should compose a default message or throw an exception if\r
+ // the message still is not found.\r
+ return formatMessage(\r
+ ResourceBundle.getBundle(resourceBundleName, US), \r
+ messageId, arguments, composeDefault);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * This is a wrapper for the getCompleteMessage workhorse routine\r
+ * using some obvious defaults, particularly for non-engine subsystems\r
+ * that only ever use the default locale.\r
+ * \r
+ * Get a message using the default locale. If the message is not found \r
+ * with the default locale, use the US locale. Do this both for the\r
+ * common bundle and the parent bundle.\r
+ * \r
+ * If the message is not found in common or in the parent resource\r
+ * bundle, return a default message composed of the message arguments.\r
+ * \r
+ * @param messageId\r
+ * The id to use to look up the message\r
+ * \r
+ * @param resourceBundleName\r
+ * The base name of the resource bundle to use.\r
+ * \r
+ * @param arguments\r
+ * The arguments to the message\r
+ */\r
+ public static String getCompleteMessage(String messageId,\r
+ String resourceBundleName, Object[] arguments) \r
+ throws MissingResourceException\r
+ {\r
+ return getCompleteMessage(Locale.getDefault(), resourceBundleName,\r
+ messageId, arguments, true);\r
+ }\r
+ \r
+ /**\r
+ * Format a message given a resource bundle and a message id.\r
+ * <p>\r
+ * The arguments to the messages are passed via an object array. The objects\r
+ * in the array WILL be changed by this class. The caller should NOT get the\r
+ * object back from this array.\r
+ *\r
+ * @param bundle\r
+ * The resource bundle to use to look for the message\r
+ *\r
+ * @param messageId\r
+ * The message id to use for the message\r
+ *\r
+ * @param arguments\r
+ * The arguments for the message\r
+ *\r
+ * @param composeDefault\r
+ * Indicates whether a default message should be composed if\r
+ * the message can't be found in the resource bundle.\r
+ * <p>\r
+ * If composeDefault is false, this method will\r
+ * throw a MissingResourceException if the message could not be\r
+ * found.\r
+ * <p>\r
+ * If composeDefault is true, then if the message id is not found in\r
+ * the given bundle, this method composes and returns as helpful a \r
+ * message as possible in the format "UNKNOWN : [arg1], [arg2], ..."\r
+ */\r
+ public static String formatMessage(ResourceBundle bundle, String messageId, \r
+ Object[] arguments, boolean composeDefault) {\r
+\r
+ String message = null;\r
+ String badArgsMessage = null;\r
+ \r
+ if (arguments == null)\r
+ arguments = new Object[0];\r
+\r
+ if (bundle != null) {\r
+\r
+ try {\r
+ message = bundle.getString(messageId);\r
+ \r
+ \r
+ // Ensure that the right number of arguments are passed in.\r
+ if ( SanityManager.DEBUG )\r
+ {\r
+ int numExpected = countParams(message);\r
+ SanityManager.ASSERT(numExpected == arguments.length,\r
+ "Number of parameters expected for message id " +\r
+ messageId + " (" + numExpected +\r
+ ") does not match number of arguments received (" +\r
+ arguments.length + ")");\r
+ }\r
+\r
+ try {\r
+ return MessageFormat.format(message, arguments);\r
+ }\r
+ catch (IllegalArgumentException iae) {\r
+ if ( !composeDefault || SanityManager.DEBUG )\r
+ throw iae;\r
+ }\r
+ catch (NullPointerException npe) {\r
+ //\r
+ //null arguments cause a NullPointerException. \r
+ //This improves reporting.\r
+ if ( !composeDefault || SanityManager.DEBUG )\r
+ throw npe;\r
+ }\r
+\r
+ } catch (MissingResourceException mre) {\r
+ // caller will try and handle the last chance\r
+ if (!composeDefault )\r
+ throw mre;\r
+ } \r
+ }\r
+\r
+ return composeDefaultMessage("UNKNOWN MESSAGE, id " + messageId, arguments);\r
+ }\r
+ \r
+ /**\r
+ * Count the number of substituation parameters in the message\r
+ */\r
+ private static int countParams(String message)\r
+ {\r
+ boolean openFound = false;\r
+ int numparams = 0;\r
+ \r
+ for ( int i = 0 ; i < message.length() ; i++ )\r
+ {\r
+ char ch = message.charAt(i);\r
+ if ( ch == '{' ) {\r
+ openFound = true;\r
+ }\r
+ \r
+ if ( ch == '}' && openFound )\r
+ {\r
+ numparams++;\r
+ openFound = false;\r
+ }\r
+ }\r
+ \r
+ return numparams;\r
+ }\r
+\r
+ /**\r
+ * Compose a default message so that the user at least gets\r
+ * *something* useful rather than just a MissingResourceException,\r
+ * which is particularly unhelpful\r
+ *\r
+ * @param message\r
+ * The message to start with, which often is null\r
+ *\r
+ * @param arguments\r
+ * The arguments to the message. \r
+ */\r
+ public static String composeDefaultMessage(String message, Object[] arguments)\r
+ {\r
+ if (message == null)\r
+ {\r
+ message = "UNKNOWN";\r
+ }\r
+ \r
+ StringBuffer sb = new StringBuffer(message);\r
+ \r
+ if ( arguments == null )\r
+ {\r
+ return sb.toString();\r
+ }\r
+\r
+ sb.append(" : ");\r
+ int len = arguments.length;\r
+\r
+ for (int i=0; i < len; i++) {\r
+ // prepend a comma to all but the first\r
+ if (i > 0)\r
+ sb.append(", ");\r
+\r
+ sb.append('[');\r
+ sb.append(i);\r
+ sb.append("] ");\r
+ if (arguments[i] == null)\r
+ sb.append("null");\r
+ else\r
+ sb.append(arguments[i].toString());\r
+ }\r
+\r
+ return sb.toString(); \r
+ }\r
+}\r