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.text.MessageFormat;
29 import java.util.MissingResourceException;
30 import java.util.ResourceBundle;
31
32 import sun.tools.jconsole.resources.JConsoleResources;
33
34 /**
35 * Provides resource support for jconsole.
36 */
37 public final class Resources {
38
39 private static final Object lock = new Object();
40 private static JConsoleResources resources = null;
41 static {
42 try {
43 resources =
44 (JConsoleResources)ResourceBundle.getBundle("sun.tools.jconsole.resources.JConsoleResources");
45 } catch (MissingResourceException e) {
46 // gracefully handle this later
47 }
48 }
49
50 private Resources() { throw new AssertionError(); }
51
52 /**
53 * Returns the text of the jconsole resource for the specified key
54 * formatted with the specified arguments.
55 *
56 */
57 public static String getText(String key, Object... args) {
58 String format = getString(key);
59 if (format == null) {
60 format = "missing resource key: key = \"" + key + "\", " +
61 "arguments = \"{0}\", \"{1}\", \"{2}\"";
62 }
63 return formatMessage(format, args);
64 }
65
66 static String formatMessage(String format, Object... args) {
67 String ss = null;
68 synchronized (lock) {
69 /*
70 * External synchronization required for safe use of
71 * java.text.MessageFormat:
72 */
73 ss = MessageFormat.format(format, args);
74 }
75 return ss;
76 }
77
78 /**
79 * Returns the mnemonic keycode int of the jconsole resource for the specified key.
80 *
81 */
82 public static int getMnemonicInt(String key) {
83 int mnemonic = 0;
84 if (resources != null) {
85 Object obj = resources.getObject(key+".mnemonic");
86 if (obj instanceof Character) {
87 mnemonic = (int)(Character)obj;
88 if (mnemonic >= 'a' && mnemonic <='z') {
89 mnemonic -= ('a' - 'A');
90 }
91 } else if (obj instanceof Integer) {
92 mnemonic = (Integer)obj;
93 }
94 }
95 return mnemonic;
96 }
97
98 /**
99 * Returns the jconsole resource string for the specified key.
100 *
101 */
102 private static String getString(String key) {
103 if (resources != null) {
104 try {
105 return resources.getString(key);
106 } catch (MissingResourceException e) {
107 return null;
108 }
109 }
110 return "missing resource bundle: key = \"" + key + "\", " +
111 "arguments = \"{0}\", \"{1}\", \"{2}\"";
112 }
113 }
|
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.HashMap;
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 HashMap<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
53 * the pattern
54 * @param objects
55 * the arguments for the pattern
56 *
57 * @return a formatted string
58 */
59 public static String format(String pattern, Object... arguments) {
60 return MessageFormat.format(pattern, arguments);
61 }
62
63 /**
64 * Returns the mnemonic for a message.
65 *
66 * @param message
67 *
68 * @return the mnemonic <code>int</code>
69 */
70 public static int getMnemonicInt(String message) {
71 Integer integer = MNEMONIC_LOOKUP.get(message);
72 if (integer != null) {
73 return integer.intValue();
74 }
75 return 0;
76 }
77
78 /**
79 * Initializes all non-final public static fields in the given class with
80 * messages from a {@link ResourceBundle}.
81 *
82 * @param clazz
83 * the class containing the fields
84 */
85 public static void initializeMessages(Class<?> clazz, String rbName) {
86 ResourceBundle rb = null;
87 try {
88 rb = ResourceBundle.getBundle(rbName);
89 } catch (MissingResourceException mre) {
90 // fall through, handled later
91 }
92 for (Field field : clazz.getFields()) {
93 if (isWritableField(field)) {
94 String key = field.getName();
95 String message = getMessage(rb, key);
96 int mnemonicInt = findMnemonicInt(message);
97 message = removeMnemonicAmpersand(message);
98 message = replaceWithPlatformLineFeed(message);
99 setFieldValue(field, message);
100 MNEMONIC_LOOKUP.put(message, mnemonicInt);
101 }
102 }
103 }
104
105 private static boolean isWritableField(Field field) {
106 int modifiers = field.getModifiers();
107 return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
108 && !Modifier.isFinal(modifiers);
109 }
110
111 /**
112 * Returns the message corresponding to the key in the bundle or a text
113 * describing it's missing.
114 *
115 * @param rb
116 * the resource bundle
117 * @param key
118 * the key
119 * @return the message
120 */
121 private static String getMessage(ResourceBundle rb, String key) {
122 if (rb == null) {
123 return "missing resource bundle";
124 }
125 try {
126 return rb.getString(key);
127 } catch (MissingResourceException mre) {
128 return "missing message for key = \"" + key
129 + "\" in resource bundle ";
130 }
131 }
132
133 private static void setFieldValue(Field field, String value) {
134 try {
135 field.set(null, value);
136 } catch (IllegalArgumentException | IllegalAccessException e) {
137 // ignore
138 }
139 }
140
141 /**
142 * Returns a {@link String} where all <code>\n</code> in the <text> have
143 * been replaced with the line separator for the platform.
144 *
145 * @param text
146 *
147 * @return the replaced text
148 */
149 private static String replaceWithPlatformLineFeed(String text) {
150 return text.replace("\n", System.getProperty("line.separator"));
151 }
152
153 /**
154 * Removes the mnemonic identifier (<code>&</code>) from a string unless
155 * it's escaped by <code>&&</code> or placed at the end.
156 *
157 * @param message
158 * the message
159 *
160 * @return a message with the mnemonic identifier removed
161 */
162 private static String removeMnemonicAmpersand(String message) {
163 StringBuilder s = new StringBuilder();
164 for (int i = 0; i < message.length(); i++) {
165 char current = message.charAt(i);
166 if (current != '&' || i == message.length() - 1
167 || message.charAt(i + 1) == '&') {
168 s.append(current);
169 }
170 }
171 return s.toString();
172 }
173
174 /**
175 * Finds the mnemonic character in a message.
176 *
177 * The mnemonic character is the first character followed by the first
178 * <code>&</code> that is not followed by another <code>&</code>.
179 *
180 * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
181 * can't be found.
182 */
183 private static int findMnemonicInt(String s) {
184 for (int i = 0; i < s.length() - 1; i++) {
185 if (s.charAt(i) == '&') {
186 if (s.charAt(i + 1) != '&') {
187 return lookupMnemonicInt(s.substring(i + 1, i + 2));
188 } else {
189 i++;
190 }
191 }
192 }
193 return 0;
194 }
195
196 /**
197 * Lookups the mnemonic for a key in the {@link KeyEvent} class.
198 *
199 * @param c
200 * the character to lookup
201 *
202 * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
203 * can't be found.
204 */
205 private static int lookupMnemonicInt(String c) {
206 try {
207 return KeyEvent.class.getDeclaredField("VK_" + c.toUpperCase())
208 .getInt(null);
209 } catch (IllegalArgumentException | IllegalAccessException
210 | NoSuchFieldException | SecurityException e) {
211 // Missing VK is okay
212 return 0;
213 }
214 }
215 }
|