| /****************************************************************************** |
| * Copyright (c) 2002, 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.examples.runtime.ui.pde.internal.l10n; |
| |
| import java.text.MessageFormat; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.gmf.examples.runtime.ui.pde.internal.GmfExamplesDebugOptions; |
| import org.eclipse.gmf.examples.runtime.ui.pde.internal.GmfExamplesPlugin; |
| import org.eclipse.gmf.examples.runtime.ui.pde.internal.GmfExamplesStatusCodes; |
| import org.eclipse.gmf.examples.runtime.ui.pde.util.Log; |
| import org.eclipse.gmf.examples.runtime.ui.pde.util.StringStatics; |
| import org.eclipse.gmf.examples.runtime.ui.pde.util.Trace; |
| |
| /** |
| * <p> |
| * AbstractResourceManager is an abstract class which is designed to encapsulate a behaviour |
| * of an object that provides a single point of access to the I18N and resource management |
| * per logical cluster of Java packages. |
| * </p> |
| * <p> |
| * The logical cluster, though can be equivalent, but not limited to one per plug-in. |
| * For instance, a logical cluster in the plug-in devoted to UML diagrams can be |
| * split into as many logical clusters, as there are types of diagrams in the plug-in. |
| * That is - a plugin that is dedicated to collaboration and sequence diagrams, can be |
| * split into two logical clusters, each requiring separate resource management - |
| * one for collaboration diagram, and another for sequence diagram. |
| * </p> |
| * <p> |
| * Each cluster should allocate a dedicated package for I18N and resource management. The |
| * preferred convention is use i18n package suffix to designate such package. For example, |
| * com.ibm.diagrams.collaboration.l10n and com.ibm.diagrams.sequence.l10n are |
| * designated packages for resource and I18N management. |
| * </p> |
| * <p> |
| * Each cluster-oriented resource management package will have a single |
| * <code>org.eclipse.gmf.examples.ui.pde.internal.l10n.AbstractResourceManager</code> subclass. The subclass should |
| * have a singleton instance and override, if necessary, the resource initialization method |
| * <code> |
| * initializeMessageResources() |
| * </code> |
| * to add the assignments of values to any value holding static variables declared in the |
| * subclass. The subclass can be designated to hold |
| * any resource and I18N related static variables if necessary, e.g. message resource bundle |
| * keys. |
| * |
| * The <code>initilaizeResources()</code> method should be overridden by subclasses in order to |
| * add/remove initialization of any additional/redundant resource types |
| * </p> |
| * <p> |
| * The subclass should override if necessary the default names of the message resource bundle |
| * file (default MessageBundle) using the method: |
| * <code> |
| * getMessageBundleName() |
| * </code> |
| * </p> |
| * <p> |
| * On the file system side the convention is to store all resources associated with the given |
| * cluster in the designated i18n package. That includes messages.properties. |
| * For example, com.ibm.diagram.collaboration cluster will store |
| * its resources here: |
| * com/ |
| * rational/ |
| * diagram/ |
| * collaboration/ |
| * l10n/ |
| * messages.properties |
| * </p> |
| * <p> |
| * Synchronization aspects |
| * |
| * The instances of this class are immutable, once created and initialized. |
| * |
| * @see java.util.ResourceBundle |
| * @author Natalia Balaba |
| * @canBeSeenBy %partners |
| */ |
| |
| public abstract class AbstractResourceManager { |
| // --------------------------------------------------------------------// |
| // ------------ STATIC VARIABLES BEGIN -------------------------------// |
| // --------------------------------------------------------------------// |
| |
| // strings that used to compose default resource names |
| |
| private static final String MESSAGES = ".messages"; //$NON-NLS-1$ |
| |
| private static final String MISSING_RESOURCE_MESSAGE = "Attempt to access missing resource ({0})."; //$NON-NLS-1$ |
| |
| // |
| // Resource bundle keys for localizable components of a list of items. |
| // Note that these strings are localized in the Common Core plug-in's |
| // message resource bundle, not in my subclass's plug-in's bundle! |
| // |
| /** Key for list separator. */ |
| static final String KEY_LIST_SEPARATOR = "list.separator"; //$NON-NLS-1$ |
| |
| /** Ksy for list separator only. */ |
| static final String KEY_LIST_SEPARATOR_ONLY = "list.separator.only"; //$NON-NLS-1$ |
| |
| /** Key for first list separator. */ |
| static final String KEY_LIST_SEPARATOR_FIRST = "list.separator.first"; //$NON-NLS-1$ |
| |
| /** Key for last list separator. */ |
| static final String KEY_LIST_SEPARATOR_LAST = "list.separator.last"; //$NON-NLS-1$ |
| |
| /** Key for list prefix. */ |
| static final String KEY_LIST_PREFIX = "list.prefix"; //$NON-NLS-1$ |
| |
| /** Key for list suffix. */ |
| static final String KEY_LIST_SUFFIX = "list.suffix"; //$NON-NLS-1$ |
| |
| /** Key for default list separator. */ |
| static final String DEFAULT_LIST_SEPARATOR = ", "; //$NON-NLS-1$ |
| |
| /** Key for default list prefix. */ |
| static final String DEFAULT_LIST_PREFIX = ""; //$NON-NLS-1$ |
| |
| /** Key for default list suffix. */ |
| static final String DEFAULT_LIST_SUFFIX = ""; //$NON-NLS-1$ |
| |
| // --------------------------------------------------------------------// |
| // ------------ STATIC VARIABLES END ---------------------------------// |
| // --------------------------------------------------------------------// |
| |
| // --------------------------------------------------------------------// |
| // ------------ INSTANCE VARIABLES BEGIN -----------------------------// |
| // --------------------------------------------------------------------// |
| |
| /** |
| * a resource bundle that stores I18N message resources |
| */ |
| private ResourceBundle messagesBundle = null; |
| |
| /* |
| * the strings that point to the names and locations of the resources. |
| * subclasses must override if name of the messages bundle is different |
| * from the default |
| */ |
| |
| /** |
| * The name of the messages bundle. The default is "messages" |
| */ |
| private String messagesBundleName = null; |
| |
| // --------------------------------------------------------------------// |
| // ------------ INSTANCE VARIABLES END ------------------------------// |
| // --------------------------------------------------------------------// |
| |
| // --------------------------------------------------------------------// |
| // ------------ CONSTRUCTORS BEGIN ---------------------------------// |
| // --------------------------------------------------------------------// |
| |
| /** |
| * Create a resource manager instance and initialize resources it will manage. |
| * Subclasses should be declared final and have a singleton instance. If the |
| * name of the messages bundle is different from the default the subclasses |
| * should override getMessagesBundleDefaultName() |
| */ |
| protected AbstractResourceManager() { |
| super(); |
| messagesBundleName = getMessagesBundleDefaultName(); |
| |
| initializeResources(); |
| } |
| |
| // --------------------------------------------------------------------// |
| // ------------ CONSTRUCTORS BEGIN ---------------------------------// |
| // --------------------------------------------------------------------// |
| |
| // --------------------------------------------------------------------// |
| // ------------ INSTANCE METHODS BEGIN ------------------------------// |
| // --------------------------------------------------------------------// |
| |
| /** |
| * Returns the messageBundle. |
| * Resource bundles contain locale-specific objects - text, numbers, etc. |
| * @return the message bundle |
| */ |
| protected ResourceBundle getMessagesBundle() { |
| return messagesBundle; |
| } |
| |
| /** |
| * Returns a package name of the class of this object |
| * @return - the full name if the client resource package |
| */ |
| protected String getPackageName() { |
| return getClass().getPackage().getName(); |
| } |
| |
| /** |
| * Returns the name of the messages bundle, including the package path. |
| * E.g. for MessageBundle.properties file located at |
| * com.ibm.diagrams.collaboration.l10n |
| * the name returned will be com.ibm.diagrams.collaboration.l10n.MessageBundle |
| * @return - messages bundle name |
| */ |
| protected String getMessagesBundleName() { |
| return messagesBundleName; |
| } |
| |
| /** |
| * Returns the plugin that hosts the resource manager |
| * @return Plugin the plugin that hosts the resource manager |
| */ |
| protected abstract Plugin getPlugin(); |
| |
| /** |
| * Load various resources. Do nothing by default. |
| * Subclasses should override this method to include initialization of the |
| * particular resource types. |
| */ |
| protected abstract void initializeResources(); |
| |
| /** |
| * Populate messageBundle with text related resources from the MessageBundle |
| * properties file. |
| * This method provides single assignment point to the private variable messagesBundle. |
| * To override default initialization subclasses should override createMessagesBundle() |
| * @see #createMessagesBundle() |
| */ |
| protected void initializeMessageResources() { |
| messagesBundle = createMessagesBundle(); |
| } |
| |
| /** |
| * Load messages resource bundle. |
| * |
| * If resource bundle is missing creates an instance of EmptyResourceBundle and |
| * returns that as a default value |
| * @return - messages resource bundle |
| */ |
| |
| protected ResourceBundle createMessagesBundle() { |
| try { |
| return ResourceBundle.getBundle( |
| getMessagesBundleName(), |
| Locale.getDefault(), |
| getClass().getClassLoader()); |
| } catch (MissingResourceException mre) { |
| Trace.catching(GmfExamplesPlugin.getDefault(), GmfExamplesDebugOptions.EXCEPTIONS_CATCHING, getClass(), "createMessagesBundle", mre); //$NON-NLS-1$ |
| Log.error(GmfExamplesPlugin.getDefault(), GmfExamplesStatusCodes.L10N_FAILURE, "createMessagesBundle", mre); //$NON-NLS-1$ |
| return new EmptyResourceBundle(getMessagesBundleName()); |
| } |
| |
| } |
| |
| /** |
| * Returns the string from the plugin's resource bundle, |
| * or 'key' if not found. |
| * @return - value for the given key or the key if value |
| * @param key java.lang.String the key to retrieve the value |
| */ |
| public String getString(String key) { |
| return getString(key, key); |
| } |
| |
| /** |
| * Returns the string from the plugin's resource bundle, |
| * or defaultValue if not found. |
| * @return - value for the given key or the suuplied |
| * default if value was not found |
| * @param key java.lang.String the key to retrieve the value |
| * @param defaultValue java.lang.String the default value to return |
| * if no value by the given key was |
| * found |
| */ |
| public String getString(String key, String defaultValue) { |
| try { |
| return getMessagesBundle().getString(key); |
| } catch (MissingResourceException mre) { |
| Trace.catching(GmfExamplesPlugin.getDefault(), GmfExamplesDebugOptions.EXCEPTIONS_CATCHING, getClass(), "getString", mre); //$NON-NLS-1$ |
| Log.warning( |
| GmfExamplesPlugin.getDefault(), |
| GmfExamplesStatusCodes.L10N_FAILURE, |
| MessageFormat.format( |
| MISSING_RESOURCE_MESSAGE, |
| new Object[] { key }), |
| mre); |
| |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Creates a localized, parameterized message from the specified pattern |
| * in the resource bundle. |
| * |
| * @param patternKey resource bundle key of the message pattern |
| * @param args objects to substitute into the <tt>{0}</tt>, <tt>{1}</tt>, |
| * etc. parameters in the message pattern |
| * @return the formatted message |
| * |
| * @see MessageFormat |
| */ |
| public String formatMessage(String patternKey, Object[] args) { |
| final String pattern = getString(patternKey); |
| |
| try { |
| return MessageFormat.format(pattern, args); |
| } catch (Exception e) { |
| // formats may throw IllegalArgumentExceptions and others |
| Trace.catching( |
| getPlugin(), |
| GmfExamplesDebugOptions.EXCEPTIONS_CATCHING, |
| ResourceManager.class, |
| "messageFormat", //$NON-NLS-1$ |
| e); |
| |
| return pattern; // better than nothing? |
| } |
| } |
| |
| /** |
| * Formats an array of strings according to the conventions of the locale. |
| * For example, in English locales, the result is a comma-separated list |
| * with "and" preceding the last item (no commas if there are only two |
| * items). The entry in a singleton array is returned as is. |
| * |
| * @param strings an array of strings to format into a list |
| * @return the list, <code>strings[0]</code> if there is only one element, |
| * or <code>""</code> if the array has no elements |
| */ |
| public String formatList(String[] strings) { |
| return formatList(java.util.Arrays.asList(strings)); |
| } |
| |
| /** |
| * <p> |
| * Formats a collection of objects according to the conventions of the |
| * locale. |
| * For example, in English locales, the result is a comma-separated list |
| * with "and" preceding the last item (no commas if there are only two |
| * items). |
| * </p> |
| * <p> |
| * The individual elements of the collection are converted to strings using |
| * the {@link String#valueOf(java.lang.Object)} method. |
| * </p> |
| * |
| * @param items an array of objects to format into a list |
| * @return the list, <code>strings[0]</code> if there is only one element, |
| * or <code>""</code> if the array has no elements |
| */ |
| public String formatList(Collection items) { |
| switch (items.size()) { |
| case 0 : |
| return StringStatics.BLANK; |
| case 1 : |
| return String.valueOf(items.iterator().next()); |
| case 2 : |
| return formatPair(ResourceManager.getInstance(), items); |
| default : |
| return formatList(ResourceManager.getInstance(), items); |
| } |
| } |
| |
| /** |
| * Helper method to format a two-item list (which in some locales looks |
| * different from a list of more than two items). |
| * |
| * @param mgr the common core plug-in's resource manager, which is used to |
| * retrieve the localized components of a list |
| * @param items the pair of items (must be exactly two) |
| * @return the pair as a string |
| * |
| * @see #formatList(Collection) |
| */ |
| private String formatPair(AbstractResourceManager mgr, Collection items) { |
| Iterator iter = items.iterator(); |
| |
| StringBuffer result = new StringBuffer(32); |
| |
| result.append(iter.next()); |
| |
| result.append(mgr.getString( |
| KEY_LIST_SEPARATOR_ONLY, |
| mgr.getString( |
| KEY_LIST_SEPARATOR, |
| DEFAULT_LIST_SEPARATOR))); |
| |
| result.append(iter.next()); |
| |
| return result.toString(); |
| } |
| |
| /** |
| * Helper method to format a list of more than two items. |
| * |
| * @param mgr the common core plug-in's resource manager, which is used to |
| * retrieve the localized components of a list |
| * @param items the list of items (must be more than two) |
| * @return the list as a string |
| * |
| * @see #formatList(Collection) |
| */ |
| private String formatList(AbstractResourceManager mgr, Collection items) { |
| Iterator iter = items.iterator(); |
| int max = items.size() - 1; |
| |
| final String sep = mgr.getString( |
| KEY_LIST_SEPARATOR, |
| DEFAULT_LIST_SEPARATOR); |
| |
| StringBuffer result = new StringBuffer(32); |
| |
| result.append(mgr.getString(KEY_LIST_PREFIX, DEFAULT_LIST_PREFIX)); |
| |
| for (int i = 0; i <= max; i++) { |
| if (i == 1) { |
| result.append(mgr.getString(KEY_LIST_SEPARATOR_FIRST, sep)); |
| } else if (i == max) { |
| result.append(mgr.getString(KEY_LIST_SEPARATOR_LAST, sep)); |
| } else if (i > 1) { |
| result.append(sep); |
| } |
| |
| result.append(iter.next()); |
| } |
| |
| result.append(mgr.getString(KEY_LIST_SUFFIX, DEFAULT_LIST_SUFFIX)); |
| |
| return result.toString(); |
| } |
| |
| /** |
| * Returns default name for the messages bundle. Subclasses should override |
| * if the messages bundle name differs from the default |
| * @return - default name for the messages bundle |
| */ |
| protected String getMessagesBundleDefaultName() { |
| return getPackageName() + MESSAGES; |
| } |
| |
| |
| |
| // --------------------------------------------------------------------// |
| // ------------ INSTANCE METHODS END --------------------------------// |
| // --------------------------------------------------------------------// |
| |
| } |