KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > core > resourceloader > GlobalResourceLoader


1 //The contents of this file are subject to the Mozilla Public License Version 1.1
2
//(the "License"); you may not use this file except in compliance with the
3
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
4
//
5
//Software distributed under the License is distributed on an "AS IS" basis,
6
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
7
//for the specific language governing rights and
8
//limitations under the License.
9
//
10
//The Original Code is "The Columba Project"
11
//
12
//The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
13
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
14
//
15
//All Rights Reserved.
16

17 package org.columba.core.resourceloader;
18
19 import java.io.File JavaDoc;
20 import java.io.FileFilter JavaDoc;
21 import java.net.MalformedURLException JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.net.URLClassLoader JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Locale JavaDoc;
28 import java.util.MissingResourceException JavaDoc;
29 import java.util.ResourceBundle JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32 import java.util.logging.Logger JavaDoc;
33
34 import org.columba.core.config.Config;
35 import org.columba.core.config.DefaultConfigDirectory;
36 import org.columba.core.xml.XmlElement;
37
38 /**
39  * This is the core class to handle i18n in columba, loading, handling and
40  * returning localized strings. It should not be used directly, use
41  * MailResourceLoader or AddressbookResourceLoader (or *ResourceLoader) instead.
42  *
43  * Behaviour: When a resource is needed, getString() or getMnemonics() are
44  * called. They look for a resource with that name (in the current locale
45  * bundles). If it is not found, they look for the resource in the global
46  * resource bundle (for the current locale). If this is not found, "FIXME" is
47  * returned.
48  *
49  * Example of usage: We need to get the text for "my_cool_button" located into
50  * "org/columba/modules/mail/i18n/action/something_else_than_action" sPath:
51  * org/columba/modules/mail/i18n/action/ => The complete package path. sName:
52  * something_else_than_action => the name of the _it_IT.properties file. sID:
53  * my_cool_button => the name to be looked for inside sName file. We can call:
54  * a) MailResourceLoader.getString("action", "something_else_than_action",
55  * "my_cool_button"); b)
56  * ResourceLoader.getString("org/columba/modules/mail/i18n/action",
57  * "something_else_than_action", "my_cool_button"); They'll both work.
58  *
59  * We need to gets its mnemonic: a) MailResourceLoader.getMnemonic("action",
60  * "something_else_than_action", "my_cool_button"); b)
61  * ResourceLoader.getMnemonic("org/columba/modules/mail/i18n/action",
62  * "something_else_than_action", "my_cool_button");
63  */

64 public class GlobalResourceLoader {
65
66     private static final Logger JavaDoc LOG = Logger.getLogger("org.columba.core.util");
67
68     protected static ClassLoader JavaDoc classLoader;
69
70     protected static Hashtable JavaDoc htBundles = new Hashtable JavaDoc(80);
71
72     protected static ResourceBundle JavaDoc globalBundle;
73
74     private static final String JavaDoc GLOBAL_BUNDLE_PATH = "org.columba.core.i18n.global.global";
75
76     static {
77         initClassLoader();
78     }
79
80     /**
81      * Initialize in org.columba.core.main.Main to use user-definable language
82      * pack.
83      */

84     public static void loadLanguage() {
85         XmlElement locale = Config.getInstance().get("options").getElement(
86                 "/options/locale");
87
88         // no configuration available, create default config
89
if (locale == null) {
90             // create new locale xml treenode
91
locale = new XmlElement("locale");
92             locale.addAttribute("language", "en");
93             Config.getInstance().get("options").getElement("/options")
94                     .addElement(locale);
95         }
96
97         String JavaDoc language = locale.getAttribute("language");
98         String JavaDoc country = locale.getAttribute("country", "");
99         String JavaDoc variant = locale.getAttribute("variant", "");
100         Locale.setDefault(new Locale JavaDoc(language, country, variant));
101         initClassLoader();
102     }
103
104     public static Locale JavaDoc[] getAvailableLocales() {
105         Set JavaDoc locales = new HashSet JavaDoc();
106         locales.add(new Locale JavaDoc("en", ""));
107
108         FileFilter JavaDoc langpackFileFilter = new LangPackFileFilter();
109         File JavaDoc[] langpacks = DefaultConfigDirectory.getInstance().getCurrentPath().listFiles(
110                 langpackFileFilter);
111
112         for (int i = 0; i < langpacks.length; i++) {
113             locales.add(extractLocaleFromFilename(langpacks[i].getName()));
114         }
115
116         langpacks = new File JavaDoc(".").listFiles(langpackFileFilter);
117
118         for (int i = 0; i < langpacks.length; i++) {
119             locales.add(extractLocaleFromFilename(langpacks[i].getName()));
120         }
121
122         return (Locale JavaDoc[]) locales.toArray(new Locale JavaDoc[0]);
123     }
124
125     private static Locale JavaDoc extractLocaleFromFilename(String JavaDoc name) {
126         String JavaDoc language = "";
127         String JavaDoc country = "";
128         String JavaDoc variant = "";
129         name = name.substring(9, name.length() - 4);
130
131         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(name, "_");
132
133         if (tokenizer.hasMoreElements()) {
134             language = tokenizer.nextToken();
135
136             if (tokenizer.hasMoreElements()) {
137                 country = tokenizer.nextToken();
138
139                 if (tokenizer.hasMoreElements()) {
140                     variant = tokenizer.nextToken();
141                 }
142             }
143         }
144
145         return new Locale JavaDoc(language, country, variant);
146     }
147
148     protected static void initClassLoader() {
149         File JavaDoc langpack = null;
150         try {
151             langpack = lookupLanguagePackFile(Locale.getDefault(), DefaultConfigDirectory.getInstance().getCurrentPath());
152         } catch (RuntimeException JavaDoc ex) {
153             // this is ok
154
}
155
156         if (langpack == null) {
157             langpack = lookupLanguagePackFile(Locale.getDefault(),
158                     new File JavaDoc("."));
159         }
160
161         if (langpack != null) {
162             LOG
163                     .fine("Creating new i18n class loader for "
164                             + langpack.getPath());
165
166             try {
167                 classLoader = new URLClassLoader JavaDoc(new URL JavaDoc[] { langpack.toURL() });
168             } catch (MalformedURLException JavaDoc mue) {
169             }
170             //does not occur
171
} else {
172             // using default english language, shipped with Columba
173

174             // we can't use SystemClassLoader here, because that
175
// wouldn't work with java webstart,
176
// ResourceBundle uses its own internal classloader
177
// if no classloader is given
178
// -> set classloader = null
179
/*
180              * classLoader = ClassLoader.getSystemClassLoader();
181              */

182             classLoader = null;
183         }
184
185         try {
186             // use ResourceBundle's internal classloader
187
if (classLoader == null) {
188                 globalBundle = ResourceBundle.getBundle(GLOBAL_BUNDLE_PATH,
189                         Locale.getDefault());
190             } else {
191                 globalBundle = ResourceBundle.getBundle(GLOBAL_BUNDLE_PATH,
192                         Locale.getDefault(), classLoader);
193             }
194         } catch (MissingResourceException JavaDoc mre) {
195             throw new RuntimeException JavaDoc(
196                     "Global resource bundle not found, Columba cannot start.");
197         }
198     }
199
200     /**
201      * Checks whether there is a language pack file corresponding to the given
202      * locale in the specified directory.
203      */

204     private static File JavaDoc lookupLanguagePackFile(Locale JavaDoc locale, File JavaDoc directory) {
205         File JavaDoc langpack = new File JavaDoc(directory, "langpack_" + locale.toString()
206                 + ".jar");
207         if (!langpack.exists() || !langpack.isFile()) {
208             langpack = new File JavaDoc(directory, "langpack_" + locale.getLanguage()
209                     + ".jar");
210         }
211         return langpack.exists() && langpack.isFile() ? langpack : null;
212     }
213
214     protected static String JavaDoc generateBundlePath(String JavaDoc sPath, String JavaDoc sName) {
215         return sPath + "." + sName;
216     }
217
218     /*
219      * This method returns the translation for the given string identifier. If
220      * no translation is found, the default english item is used. Should this
221      * fail too, the sID string will be returned.
222      *
223      * Example usage call: getString("org/columba/modules/mail/i18n/", "dialog",
224      * "close") We'll look for "close" in
225      * "org/columba/modules/mail/i18n/dialog/dialog_locale_LOCALE.properties"
226      * Thus: sPath: "org/columba/modules/mail/i18n/dialog" sName: "dialog" sID:
227      * "close" The bundle name will be:
228      * "org/columba/modules/mail/i18n/dialog/dialog"
229      *
230      * Hypotetically this method should not be available to classes different
231      * from *ResourceLoader (example: MailResourceLoader,
232      * AddressbookResourceLoader); this means that *ResourceLoader classes *do
233      * know* how to call this method.
234      */

235     public static String JavaDoc getString(String JavaDoc sPath, String JavaDoc sName, String JavaDoc sID) {
236         if ((sID == null) || sID.equals("")) {
237             return null;
238         }
239
240         ResourceBundle JavaDoc bundle = null;
241         String JavaDoc sBundlePath = null;
242
243         if ((sPath != null) && !sPath.equals("")) {
244             //Find out if we already loaded the needed ResourceBundle
245
//object in the hashtable.
246
sBundlePath = generateBundlePath(sPath, sName);
247             bundle = (ResourceBundle JavaDoc) htBundles.get(sBundlePath);
248         }
249
250         if ((bundle == null) && (sBundlePath != null)) {
251             try {
252                 // use ResourceBundle's internal classloader
253
if (classLoader == null) {
254                     bundle = ResourceBundle.getBundle(sBundlePath, Locale
255                             .getDefault());
256                 } else {
257                     bundle = ResourceBundle.getBundle(sBundlePath, Locale
258                             .getDefault(), classLoader);
259                 }
260
261                 htBundles.put(sBundlePath, bundle);
262             } catch (MissingResourceException JavaDoc mre) {
263             }
264         }
265
266         if (bundle != null) {
267             try {
268                 return bundle.getString(sID);
269             } catch (MissingResourceException JavaDoc mre) {
270             }
271         }
272
273         try {
274             return globalBundle.getString(sID);
275         } catch (MissingResourceException JavaDoc mre) {
276             LOG.severe("'" + sID + "' in '" + sBundlePath
277                     + "' could not be found.");
278
279             return sID;
280         }
281     }
282
283     public static void reload() {
284         initClassLoader();
285         LOG.fine("Reloading cached resource bundles for locale "
286                 + Locale.getDefault().toString());
287
288         try {
289             // use ResourceBundle's internal classloader
290
if (classLoader == null) {
291                 globalBundle = ResourceBundle.getBundle(GLOBAL_BUNDLE_PATH,
292                         Locale.getDefault());
293             } else {
294                 globalBundle = ResourceBundle.getBundle(GLOBAL_BUNDLE_PATH,
295                         Locale.getDefault(), classLoader);
296             }
297         } catch (MissingResourceException JavaDoc mre) {
298         }
299         //should not occur, otherwise the static initializer should have thrown
300
// a RuntimeException
301

302         String JavaDoc bundlePath;
303         ResourceBundle JavaDoc bundle;
304
305         for (Enumeration JavaDoc entries = htBundles.keys(); entries.hasMoreElements();) {
306             try {
307                 bundlePath = (String JavaDoc) entries.nextElement();
308
309                 //retrieve new bundle
310
// use ResourceBundle's internal classloader
311
if (classLoader == null) {
312                     bundle = ResourceBundle.getBundle(bundlePath, Locale
313                             .getDefault());
314                 } else {
315                     bundle = ResourceBundle.getBundle(bundlePath, Locale
316                             .getDefault(), classLoader);
317                 }
318
319                 //overwrite old bundle
320
htBundles.put(bundlePath, bundle);
321             } catch (MissingResourceException JavaDoc mre) {
322             }
323             //should not occur, otherwise the bundlePath would not be in the
324
// hashtable
325
}
326     }
327
328     public static class LangPackFileFilter implements FileFilter JavaDoc {
329         public boolean accept(File JavaDoc file) {
330             String JavaDoc name = file.getName().toLowerCase();
331
332             return file.isFile() && name.startsWith("langpack_")
333                     && name.endsWith(".jar");
334         }
335     }
336 }
Popular Tags