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 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 e) {
133 throw new Error("Unable to access or set message for field " + field.getName());
134 } catch (IllegalAccessException e) {
135 throw new Error("Unable to access or set message for field " + field.getName());
136 }
137 }
138
139 /**
140 * Returns a {@link String} where all <code>\n</code> in the <text> have
141 * been replaced with the line separator for the platform.
142 *
143 * @param text the to be replaced
144 *
145 * @return the replaced text
146 */
147 private static String replaceWithPlatformLineFeed(String text) {
148 return text.replace("\n", System.getProperty("line.separator"));
149 }
150
151 /**
152 * Removes the mnemonic identifier (<code>&</code>) from a string unless
153 * it's escaped by <code>&&</code> or placed at the end.
154 *
155 * @param message the message
156 *
157 * @return a message with the mnemonic identifier removed
158 */
159 private static String removeMnemonicAmpersand(String message) {
160 StringBuilder s = new StringBuilder();
161 for (int i = 0; i < message.length(); i++) {
162 char current = message.charAt(i);
163 if (current != '&' || i == message.length() - 1
164 || message.charAt(i + 1) == '&') {
165 s.append(current);
166 }
167 }
168 return s.toString();
169 }
170
171 /**
172 * Finds the mnemonic character in a message.
173 *
174 * The mnemonic character is the first character followed by the first
175 * <code>&</code> that is not followed by another <code>&</code>.
176 *
177 * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
178 * can't be found.
179 */
180 private static int findMnemonicInt(String s) {
181 for (int i = 0; i < s.length() - 1; i++) {
182 if (s.charAt(i) == '&') {
183 if (s.charAt(i + 1) != '&') {
184 return lookupMnemonicInt(s.substring(i + 1, i + 2));
185 } else {
186 i++;
187 }
188 }
189 }
190 return 0;
191 }
192
193 /**
194 * Lookups the mnemonic for a key in the {@link KeyEvent} class.
195 *
196 * @param c the character to lookup
197 *
198 * @return the mnemonic as an <code>int</code>, or <code>0</code> if it
199 * can't be found.
200 */
201 private static int lookupMnemonicInt(String c) {
202 try {
203 return KeyEvent.class.getDeclaredField("VK_" + c.toUpperCase())
204 .getInt(null);
205 } catch (IllegalArgumentException e) {
206 // Missing VK is okay
207 return 0;
208 } catch (IllegalAccessException e) {
209 // Missing VK is okay
210 return 0;
211 } catch (NoSuchFieldException e) {
212 // Missing VK is okay
213 return 0;
214 } catch (SecurityException e) {
215 // Missing VK is okay
216 return 0;
217 }
218 }
219 }
|