--- old/src/share/classes/sun/tools/jconsole/Resources.java 2012-05-21 01:32:54.179829988 +0200 +++ new/src/share/classes/sun/tools/jconsole/Resources.java 2012-05-21 01:32:53.336798033 +0200 @@ -25,89 +25,191 @@ package sun.tools.jconsole; +import java.awt.event.KeyEvent; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; -import sun.tools.jconsole.resources.JConsoleResources; - /** - * Provides resource support for jconsole. + * Toolkit that provides resource support for JConsole. */ public final class Resources { + private static Map MNEMONIC_LOOKUP = Collections + .synchronizedMap(new HashMap()); + + private Resources() { + throw new AssertionError(); + } + + /** + * Convenience method for {@link MessageFormat#format(String, Object...)}. + * + * @param pattern + * the pattern + * @param objects + * the arguments for the pattern + * + * @return a formatted string + */ + public static String format(String pattern, Object... arguments) { + return MessageFormat.format(pattern, arguments); + } + + /** + * Returns the mnemonic for a message. + * + * @param message + * + * @return the mnemonic int + */ + public static int getMnemonicInt(String message) { + Integer integer = MNEMONIC_LOOKUP.get(message); + if (integer != null) { + return integer.intValue(); + } + return 0; + } - private static final Object lock = new Object(); - private static JConsoleResources resources = null; - static { + /** + * Initializes all non-final public static fields in the given class with + * messages from a {@link ResourceBundle}. + * + * @param clazz + * the class containing the fields + */ + public static void initializeMessages(Class clazz, String rbName) { + ResourceBundle rb = null; try { - resources = - (JConsoleResources)ResourceBundle.getBundle("sun.tools.jconsole.resources.JConsoleResources"); - } catch (MissingResourceException e) { - // gracefully handle this later + rb = ResourceBundle.getBundle(rbName); + } catch (MissingResourceException mre) { + // fall through, handled later + } + for (Field field : clazz.getFields()) { + if (isWritableField(field)) { + String key = field.getName(); + String message = getMessage(rb, key); + int mnemonicInt = findMnemonicInt(message); + message = removeMnemonicAmpersand(message); + message = replaceWithPlatformLineFeed(message); + setFieldValue(field, message); + MNEMONIC_LOOKUP.put(message, mnemonicInt); + } } } - private Resources() { throw new AssertionError(); } + private static boolean isWritableField(Field field) { + int modifiers = field.getModifiers(); + return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) + && !Modifier.isFinal(modifiers); + } /** - * Returns the text of the jconsole resource for the specified key - * formatted with the specified arguments. + * Returns the message corresponding to the key in the bundle or a text + * describing it's missing. * + * @param rb + * the resource bundle + * @param key + * the key + * @return the message */ - public static String getText(String key, Object... args) { - String format = getString(key); - if (format == null) { - format = "missing resource key: key = \"" + key + "\", " + - "arguments = \"{0}\", \"{1}\", \"{2}\""; + private static String getMessage(ResourceBundle rb, String key) { + if (rb == null) { + return "missing resource bundle"; + } + try { + return rb.getString(key); + } catch (MissingResourceException mre) { + return "missing message for key = \"" + key + + "\" in resource bundle "; } - return formatMessage(format, args); } - static String formatMessage(String format, Object... args) { - String ss = null; - synchronized (lock) { - /* - * External synchronization required for safe use of - * java.text.MessageFormat: - */ - ss = MessageFormat.format(format, args); + private static void setFieldValue(Field field, String value) { + try { + field.set(null, value); + } catch (IllegalArgumentException | IllegalAccessException e) { + // ignore } - return ss; } /** - * Returns the mnemonic keycode int of the jconsole resource for the specified key. + * Returns a {@link String} where all \n in the have + * been replaced with the line separator for the platform. * + * @param text + * + * @return the replaced text */ - public static int getMnemonicInt(String key) { - int mnemonic = 0; - if (resources != null) { - Object obj = resources.getObject(key+".mnemonic"); - if (obj instanceof Character) { - mnemonic = (int)(Character)obj; - if (mnemonic >= 'a' && mnemonic <='z') { - mnemonic -= ('a' - 'A'); - } - } else if (obj instanceof Integer) { - mnemonic = (Integer)obj; + private static String replaceWithPlatformLineFeed(String text) { + return text.replace("\n", System.getProperty("line.separator")); + } + + /** + * Removes the mnemonic identifier (&) from a string unless + * it's escaped by && or placed at the end. + * + * @param message + * the message + * + * @return a message with the mnemonic identifier removed + */ + private static String removeMnemonicAmpersand(String message) { + StringBuilder s = new StringBuilder(); + for (int i = 0; i < message.length(); i++) { + char current = message.charAt(i); + if (current != '&' || i == message.length() - 1 + || message.charAt(i + 1) == '&') { + s.append(current); } } - return mnemonic; + return s.toString(); } /** - * Returns the jconsole resource string for the specified key. + * Finds the mnemonic character in a message. * + * The mnemonic character is the first character followed by the first + * & that is not followed by another &. + * + * @return the mnemonic as an int, or 0 if it + * can't be found. */ - private static String getString(String key) { - if (resources != null) { - try { - return resources.getString(key); - } catch (MissingResourceException e) { - return null; + private static int findMnemonicInt(String s) { + for (int i = 0; i < s.length() - 1; i++) { + if (s.charAt(i) == '&') { + if (s.charAt(i + 1) != '&') { + return lookupMnemonicInt(s.substring(i + 1, i + 2)); + } else { + i++; + } } } - return "missing resource bundle: key = \"" + key + "\", " + - "arguments = \"{0}\", \"{1}\", \"{2}\""; + return 0; + } + + /** + * Lookups the mnemonic for a key in the {@link KeyEvent} class. + * + * @param c + * the character to lookup + * + * @return the mnemonic as an int, or 0 if it + * can't be found. + */ + private static int lookupMnemonicInt(String c) { + try { + return KeyEvent.class.getDeclaredField("VK_" + c.toUpperCase()) + .getInt(null); + } catch (IllegalArgumentException | IllegalAccessException + | NoSuchFieldException | SecurityException e) { + // Missing VK is okay + return 0; + } } }