KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > internal > core > MessageResourceBundle


1 /*******************************************************************************
2  * Copyright (c) 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.osgi.framework.internal.core;
12
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.lang.reflect.Field JavaDoc;
16 import java.lang.reflect.Modifier JavaDoc;
17 import java.security.AccessController JavaDoc;
18 import java.security.PrivilegedAction JavaDoc;
19 import java.util.*;
20 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
21 import org.eclipse.osgi.framework.debug.Debug;
22 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
23
24 /**
25  * Class responsible for loading message values from a property file
26  * and assigning them directly to the fields of a messages class.
27  * @since 3.1
28  */

29 public class MessageResourceBundle {
30     /**
31      * Class which sub-classes java.util.Properties and uses the #put method
32      * to set field values rather than storing the values in the table.
33      *
34      * @since 3.1
35      */

36     private static class MessagesProperties extends Properties {
37
38         private static final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
39         private static final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
40         private static final long serialVersionUID = 1L;
41
42         private final String JavaDoc bundleName;
43         private final Map fields;
44         private final boolean isAccessible;
45
46         public MessagesProperties(Map fieldMap, String JavaDoc bundleName, boolean isAccessible) {
47             super();
48             this.fields = fieldMap;
49             this.bundleName = bundleName;
50             this.isAccessible = isAccessible;
51         }
52
53         /* (non-Javadoc)
54          * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
55          */

56         public synchronized Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
57             Object JavaDoc fieldObject = fields.put(key, ASSIGNED);
58             // if already assigned, there is nothing to do
59
if (fieldObject == ASSIGNED)
60                 return null;
61             if (fieldObject == null) {
62                 final String JavaDoc msg = "NLS unused message: " + key + " in: " + bundleName;//$NON-NLS-1$ //$NON-NLS-2$
63
if (Debug.DEBUG_MESSAGE_BUNDLES)
64                     System.out.println(msg);
65                 log(SEVERITY_WARNING, msg, null);
66                 return null;
67             }
68             final Field JavaDoc field = (Field JavaDoc) fieldObject;
69             //can only set value of public static non-final fields
70
if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED)
71                 return null;
72             try {
73                 // Check to see if we are allowed to modify the field. If we aren't (for instance
74
// if the class is not public) then change the accessible attribute of the field
75
// before trying to set the value.
76
if (!isAccessible)
77                     makeAccessible(field);
78                 // Set the value into the field. We should never get an exception here because
79
// we know we have a public static non-final field. If we do get an exception, silently
80
// log it and continue. This means that the field will (most likely) be un-initialized and
81
// will fail later in the code and if so then we will see both the NPE and this error.
82
field.set(null, value);
83             } catch (Exception JavaDoc e) {
84                 log(SEVERITY_ERROR, "Exception setting field value.", e); //$NON-NLS-1$
85
}
86             return null;
87         }
88     }
89
90     private static FrameworkAdaptor adaptor;
91     /**
92      * This object is assigned to the value of a field map to indicate
93      * that a translated message has already been assigned to that field.
94      */

95     static final Object JavaDoc ASSIGNED = new Object JavaDoc();
96
97     private static final String JavaDoc EXTENSION = ".properties"; //$NON-NLS-1$
98

99     private static String JavaDoc[] nlSuffixes;
100
101     static int SEVERITY_ERROR = 0x04;
102
103     static int SEVERITY_WARNING = 0x02;
104
105     /*
106      * Build an array of property files to search. The returned array contains
107      * the property fields in order from most specific to most generic.
108      * So, in the FR_fr locale, it will return file_fr_FR.properties, then
109      * file_fr.properties, and finally file.properties.
110      */

111     private static String JavaDoc[] buildVariants(String JavaDoc root) {
112         if (nlSuffixes == null) {
113             //build list of suffixes for loading resource bundles
114
String JavaDoc nl = Locale.getDefault().toString();
115             ArrayList result = new ArrayList(4);
116             int lastSeparator;
117             while (true) {
118                 result.add('_' + nl + EXTENSION);
119                 lastSeparator = nl.lastIndexOf('_');
120                 if (lastSeparator == -1)
121                     break;
122                 nl = nl.substring(0, lastSeparator);
123             }
124             //add the empty suffix last (most general)
125
result.add(EXTENSION);
126             nlSuffixes = (String JavaDoc[]) result.toArray(new String JavaDoc[result.size()]);
127         }
128         root = root.replace('.', '/');
129         String JavaDoc[] variants = new String JavaDoc[nlSuffixes.length];
130         for (int i = 0; i < variants.length; i++)
131             variants[i] = root + nlSuffixes[i];
132         return variants;
133     }
134
135     /*
136      * Change the accessibility of the specified field so we can set its value
137      * to be the appropriate message string.
138      */

139     static void makeAccessible(final Field JavaDoc field) {
140         if (System.getSecurityManager() == null) {
141             field.setAccessible(true);
142         } else {
143             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
144                 public Object JavaDoc run() {
145                     field.setAccessible(true);
146                     return null;
147                 }
148             });
149         }
150     }
151
152     private static void computeMissingMessages(String JavaDoc bundleName, Class JavaDoc clazz, Map fieldMap, Field JavaDoc[] fieldArray, boolean isAccessible) {
153         // iterate over the fields in the class to make sure that there aren't any empty ones
154
final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
155         final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
156         final int numFields = fieldArray.length;
157         for (int i = 0; i < numFields; i++) {
158             Field JavaDoc field = fieldArray[i];
159             if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED)
160                 continue;
161             //if the field has a a value assigned, there is nothing to do
162
if (fieldMap.get(field.getName()) == ASSIGNED)
163                 continue;
164             try {
165                 // Set a value for this empty field. We should never get an exception here because
166
// we know we have a public static non-final field. If we do get an exception, silently
167
// log it and continue. This means that the field will (most likely) be un-initialized and
168
// will fail later in the code and if so then we will see both the NPE and this error.
169
String JavaDoc value = "NLS missing message: " + field.getName() + " in: " + bundleName; //$NON-NLS-1$ //$NON-NLS-2$
170
if (Debug.DEBUG_MESSAGE_BUNDLES)
171                     System.out.println(value);
172                 log(SEVERITY_WARNING, value, null);
173                 if (!isAccessible)
174                     makeAccessible(field);
175                 field.set(null, value);
176             } catch (Exception JavaDoc e) {
177                 log(SEVERITY_ERROR, "Error setting the missing message value for: " + field.getName(), e); //$NON-NLS-1$
178
}
179         }
180     }
181
182     /**
183      * Load the given resource bundle using the specified class loader.
184      */

185     public static void load(final String JavaDoc bundleName, Class JavaDoc clazz) {
186         long start = System.currentTimeMillis();
187         final Field JavaDoc[] fieldArray = clazz.getDeclaredFields();
188         ClassLoader JavaDoc loader = clazz.getClassLoader();
189
190         boolean isAccessible = (clazz.getModifiers() & Modifier.PUBLIC) != 0;
191
192         //build a map of field names to Field objects
193
final int len = fieldArray.length;
194         Map fields = new HashMap(len * 2);
195         for (int i = 0; i < len; i++)
196             fields.put(fieldArray[i].getName(), fieldArray[i]);
197
198         // search the variants from most specific to most general, since
199
// the MessagesProperties.put method will mark assigned fields
200
// to prevent them from being assigned twice
201
final String JavaDoc[] variants = buildVariants(bundleName);
202         for (int i = 0; i < variants.length; i++) {
203             // loader==null if we're launched off the Java boot classpath
204
final InputStream JavaDoc input = loader==null ? ClassLoader.getSystemResourceAsStream(variants[i]) : loader.getResourceAsStream(variants[i]);
205             if (input == null)
206                 continue;
207             try {
208                 final MessagesProperties properties = new MessagesProperties(fields, bundleName, isAccessible);
209                 properties.load(input);
210             } catch (IOException JavaDoc e) {
211                 log(SEVERITY_ERROR, "Error loading " + variants[i], e); //$NON-NLS-1$
212
} finally {
213                 if (input != null)
214                     try {
215                         input.close();
216                     } catch (IOException JavaDoc e) {
217                         // ignore
218
}
219             }
220         }
221         computeMissingMessages(bundleName, clazz, fields, fieldArray, isAccessible);
222         if (Debug.DEBUG_MESSAGE_BUNDLES)
223             System.out.println("Time to load message bundle: " + bundleName + " was " + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
224
}
225
226     static void log(int severity, String JavaDoc msg, Exception JavaDoc e) {
227         if (adaptor != null)
228             adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + ' ' + severity + ' ' + 1, msg, 0, e, null));
229         else {
230             System.out.println(msg);
231             if (e != null)
232                 e.printStackTrace();
233         }
234     }
235
236     static void setAdaptor(FrameworkAdaptor adaptor) {
237         MessageResourceBundle.adaptor = adaptor;
238     }
239 }
Popular Tags