src/jdk.jconsole/share/classes/sun/tools/jconsole/Resources.java
changeset 47216 71c04702a3d5
parent 25859 3317bb8137f4
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.tools.jconsole;
       
    27 
       
    28 import java.awt.event.KeyEvent;
       
    29 import java.lang.reflect.Field;
       
    30 import java.lang.reflect.Modifier;
       
    31 import java.text.MessageFormat;
       
    32 import java.util.Collections;
       
    33 import java.util.IdentityHashMap;
       
    34 import java.util.Map;
       
    35 import java.util.MissingResourceException;
       
    36 import java.util.ResourceBundle;
       
    37 
       
    38 /**
       
    39  * Toolkit that provides resource support for JConsole.
       
    40  */
       
    41 public final class Resources {
       
    42     private static Map<String, Integer> MNEMONIC_LOOKUP = Collections
       
    43             .synchronizedMap(new IdentityHashMap<String, Integer>());
       
    44 
       
    45     private Resources() {
       
    46         throw new AssertionError();
       
    47     }
       
    48 
       
    49     /**
       
    50      * Convenience method for {@link MessageFormat#format(String, Object...)}.
       
    51      *
       
    52      * @param pattern the pattern
       
    53      * @param objects the arguments for the pattern
       
    54      *
       
    55      * @return a formatted string
       
    56      */
       
    57     public static String format(String pattern, Object... arguments) {
       
    58             return MessageFormat.format(pattern, arguments);
       
    59     }
       
    60 
       
    61     /**
       
    62      * Returns the mnemonic for a message.
       
    63      *
       
    64      * @param message the message
       
    65      *
       
    66      * @return the mnemonic <code>int</code>
       
    67      */
       
    68     public static int getMnemonicInt(String message) {
       
    69         Integer integer = MNEMONIC_LOOKUP.get(message);
       
    70         if (integer != null) {
       
    71             return integer.intValue();
       
    72         }
       
    73         return 0;
       
    74     }
       
    75 
       
    76     /**
       
    77      * Initializes all non-final public static fields in the given class with
       
    78      * messages from a {@link ResourceBundle}.
       
    79      *
       
    80      * @param clazz the class containing the fields
       
    81      */
       
    82     public static void initializeMessages(Class<?> clazz, String rbName) {
       
    83         ResourceBundle rb = null;
       
    84         try {
       
    85             rb = ResourceBundle.getBundle(rbName);
       
    86         } catch (MissingResourceException mre) {
       
    87             // fall through, handled later
       
    88         }
       
    89         for (Field field : clazz.getFields()) {
       
    90             if (isWritableField(field)) {
       
    91                 String key = field.getName();
       
    92                 String message = getMessage(rb, key);
       
    93                 int mnemonicInt = findMnemonicInt(message);
       
    94                 message = removeMnemonicAmpersand(message);
       
    95                 message = replaceWithPlatformLineFeed(message);
       
    96                 setFieldValue(field, message);
       
    97                 MNEMONIC_LOOKUP.put(message, mnemonicInt);
       
    98             }
       
    99         }
       
   100     }
       
   101 
       
   102     private static boolean isWritableField(Field field) {
       
   103         int modifiers = field.getModifiers();
       
   104         return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
       
   105                 && !Modifier.isFinal(modifiers);
       
   106     }
       
   107 
       
   108     /**
       
   109      * Returns the message corresponding to the key in the bundle or a text
       
   110      * describing it's missing.
       
   111      *
       
   112      * @param rb the resource bundle
       
   113      * @param key the key
       
   114      *
       
   115      * @return the message
       
   116      */
       
   117     private static String getMessage(ResourceBundle rb, String key) {
       
   118         if (rb == null) {
       
   119             return "missing resource bundle";
       
   120         }
       
   121         try {
       
   122             return rb.getString(key);
       
   123         } catch (MissingResourceException mre) {
       
   124             return "missing message for key = \"" + key
       
   125                     + "\" in resource bundle ";
       
   126         }
       
   127     }
       
   128 
       
   129     private static void setFieldValue(Field field, String value) {
       
   130         try {
       
   131             field.set(null, value);
       
   132         } catch (IllegalArgumentException | IllegalAccessException e) {
       
   133             throw new Error("Unable to access or set message for field " + field.getName());
       
   134         }
       
   135     }
       
   136 
       
   137     /**
       
   138      * Returns a {@link String} where all <code>\n</code> in the <text> have
       
   139      * been replaced with the line separator for the platform.
       
   140      *
       
   141      * @param text the to be replaced
       
   142      *
       
   143      * @return the replaced text
       
   144      */
       
   145     private static String replaceWithPlatformLineFeed(String text) {
       
   146         return text.replace("\n", System.getProperty("line.separator"));
       
   147     }
       
   148 
       
   149     /**
       
   150      * Removes the mnemonic identifier (<code>&</code>) from a string unless
       
   151      * it's escaped by <code>&&</code> or placed at the end.
       
   152      *
       
   153      * @param message the message
       
   154      *
       
   155      * @return a message with the mnemonic identifier removed
       
   156      */
       
   157     private static String removeMnemonicAmpersand(String message) {
       
   158         StringBuilder s = new StringBuilder();
       
   159         for (int i = 0; i < message.length(); i++) {
       
   160             char current = message.charAt(i);
       
   161             if (current != '&' || i == message.length() - 1
       
   162                     || message.charAt(i + 1) == '&') {
       
   163                 s.append(current);
       
   164             }
       
   165         }
       
   166         return s.toString();
       
   167     }
       
   168 
       
   169     /**
       
   170      * Finds the mnemonic character in a message.
       
   171      *
       
   172      * The mnemonic character is the first character followed by the first
       
   173      * <code>&</code> that is not followed by another <code>&</code>.
       
   174      *
       
   175      * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
       
   176      *         can't be found.
       
   177      */
       
   178     private static int findMnemonicInt(String s) {
       
   179         for (int i = 0; i < s.length() - 1; i++) {
       
   180             if (s.charAt(i) == '&') {
       
   181                 if (s.charAt(i + 1) != '&') {
       
   182                     return lookupMnemonicInt(s.substring(i + 1, i + 2));
       
   183                 } else {
       
   184                     i++;
       
   185                 }
       
   186             }
       
   187         }
       
   188         return 0;
       
   189     }
       
   190 
       
   191     /**
       
   192      * Lookups the mnemonic for a key in the {@link KeyEvent} class.
       
   193      *
       
   194      * @param c the character to lookup
       
   195      *
       
   196      * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
       
   197      *         can't be found.
       
   198      */
       
   199     private static int lookupMnemonicInt(String c) {
       
   200         try {
       
   201             return KeyEvent.class.getDeclaredField("VK_" + c.toUpperCase())
       
   202                     .getInt(null);
       
   203         } catch (IllegalArgumentException | IllegalAccessException
       
   204                 | NoSuchFieldException | SecurityException e) {
       
   205             // Missing VK is okay
       
   206             return 0;
       
   207         }
       
   208     }
       
   209 }