KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > i18n > XMLResourceBundleFactory


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.i18n;
17
18 import org.apache.avalon.framework.activity.Disposable;
19 import org.apache.avalon.framework.component.ComponentException;
20 import org.apache.avalon.framework.configuration.Configurable;
21 import org.apache.avalon.framework.configuration.Configuration;
22 import org.apache.avalon.framework.configuration.ConfigurationException;
23 import org.apache.avalon.framework.logger.AbstractLogEnabled;
24 import org.apache.avalon.framework.logger.LogEnabled;
25 import org.apache.avalon.framework.service.ServiceException;
26 import org.apache.avalon.framework.service.ServiceManager;
27 import org.apache.avalon.framework.service.Serviceable;
28 import org.apache.avalon.framework.thread.ThreadSafe;
29 import org.apache.excalibur.source.Source;
30 import org.apache.excalibur.source.SourceResolver;
31 import org.apache.excalibur.store.Store;
32
33 import org.apache.cocoon.util.NetUtils;
34
35 import java.io.IOException JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.Locale JavaDoc;
39 import java.util.Map JavaDoc;
40
41 /**
42  * This is the XMLResourceBundleFactory, the method for getting and creating
43  * XMLResourceBundles.
44  *
45  * @author <a HREF="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
46  * @author <a HREF="mailto:neeme@one.lv">Neeme Praks</a>
47  * @author <a HREF="mailto:oleg@one.lv">Oleg Podolsky</a>
48  * @author <a HREF="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
49  * @author <a HREF="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
50  * @version $Id: XMLResourceBundleFactory.java 315011 2005-10-12 19:35:03Z vgritsenko $
51  */

52 public class XMLResourceBundleFactory extends AbstractLogEnabled
53                                       implements BundleFactory, Serviceable, Configurable,
54                                                  Disposable, ThreadSafe, LogEnabled {
55
56     /**
57      * Root directory to all bundle names
58      */

59     private String JavaDoc directory;
60
61     /**
62      * Reload check interval in milliseconds.
63      * Defaults to 60000 (1 minute), use <code>-1</code> to
64      * disable reloads and <code>0</code> to check for modifications
65      * on each catalogue request.
66      */

67     private long interval;
68
69     /**
70      * Service Manager
71      */

72     protected ServiceManager manager;
73
74     /**
75      * Source resolver
76      */

77     protected SourceResolver resolver;
78
79     /**
80      * Store of the loaded bundles
81      */

82     protected Store cache;
83
84
85     //
86
// Lifecycle
87
//
88

89     public void service(ServiceManager manager) throws ServiceException {
90         this.manager = manager;
91         this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
92     }
93
94     /**
95      * Configure the component.
96      *
97      * @param configuration the configuration
98      */

99     public void configure(Configuration configuration) throws ConfigurationException {
100         this.directory = configuration.getChild(ConfigurationKeys.ROOT_DIRECTORY).getValue("");
101
102         String JavaDoc cacheRole = configuration.getChild(ConfigurationKeys.STORE_ROLE).getValue(Store.TRANSIENT_STORE);
103         try {
104             this.cache = (Store) this.manager.lookup(cacheRole);
105         } catch (ServiceException e) {
106             throw new ConfigurationException("Unable to lookup store '" + cacheRole + "'");
107         }
108
109         this.interval = configuration.getChild(ConfigurationKeys.RELOAD_INTERVAL).getValueAsLong(60000L);
110
111         if (getLogger().isDebugEnabled()) {
112             getLogger().debug("Bundle directory '" + this.directory + "'");
113             getLogger().debug("Store role '" + cacheRole + "'");
114         }
115     }
116
117     /**
118      * Disposes this component.
119      */

120     public void dispose() {
121         this.manager.release(this.resolver);
122         this.manager.release(this.cache);
123         this.resolver = null;
124         this.cache = null;
125         this.manager = null;
126     }
127
128     //
129
// BundleFactory Interface
130
//
131

132     /**
133      * Returns the root directory to all bundles.
134      *
135      * @return the directory path
136      */

137     protected String JavaDoc getDirectory() {
138         return this.directory;
139     }
140
141     /**
142      * Select a bundle based on the bundle name and the locale name.
143      *
144      * @param name bundle name
145      * @param locale locale name
146      * @return the bundle
147      * @exception ComponentException if a bundle is not found
148      */

149     public Bundle select(String JavaDoc name, String JavaDoc locale) throws ComponentException {
150         return select(getDirectory(), name, locale);
151     }
152
153     /**
154      * Select a bundle based on the bundle name and the locale.
155      *
156      * @param name bundle name
157      * @param locale locale
158      * @return the bundle
159      * @exception ComponentException if a bundle is not found
160      */

161     public Bundle select(String JavaDoc name, Locale JavaDoc locale) throws ComponentException {
162         return select(getDirectory(), name, locale);
163     }
164
165     /**
166      * Select a bundle based on the catalogue base location, bundle name,
167      * and the locale name.
168      *
169      * @param directory catalogue base location (URI)
170      * @param name bundle name
171      * @param localeName locale name
172      * @return the bundle
173      * @exception ComponentException if a bundle is not found
174      */

175     public Bundle select(String JavaDoc directory, String JavaDoc name, String JavaDoc localeName)
176     throws ComponentException {
177         return select(directory, name, new Locale JavaDoc(localeName, localeName));
178     }
179
180     /**
181      * Select a bundle based on the catalogue base location, bundle name,
182      * and the locale.
183      *
184      * @param directory catalogue base location (URI)
185      * @param name bundle name
186      * @param locale locale
187      * @return the bundle
188      * @exception ComponentException if a bundle is not found
189      */

190     public Bundle select(String JavaDoc directory, String JavaDoc name, Locale JavaDoc locale)
191     throws ComponentException {
192         return select(new String JavaDoc[] { directory }, name, locale);
193     }
194
195     /**
196      * Select a bundle based on the catalogue base location, bundle name,
197      * and the locale.
198      *
199      * @param directories catalogue base location (URI)
200      * @param name bundle name
201      * @param locale locale
202      * @return the bundle
203      * @exception ComponentException if a bundle is not found
204      */

205     public Bundle select(String JavaDoc[] directories, String JavaDoc name, Locale JavaDoc locale)
206     throws ComponentException {
207         Bundle bundle = _select(directories, 0, name, locale);
208         if (bundle == null) {
209             throw new ComponentException(name, "Unable to locate resource: " + name);
210         }
211         return bundle;
212     }
213
214     public void release(Bundle bundle) {
215         // Do nothing
216
}
217
218     //
219
// Implementation
220
//
221

222     /**
223      * Select a bundle based on bundle name and locale.
224      *
225      * @param directories catalogue location(s)
226      * @param name bundle name
227      * @param locale locale
228      * @return the bundle
229      */

230     private XMLResourceBundle _select(String JavaDoc[] directories, int index, String JavaDoc name,
231                                       Locale JavaDoc locale)
232     throws ComponentException {
233         if (getLogger().isDebugEnabled()) {
234             getLogger().debug("Selecting from: " + name + ", locale: " + locale +
235                               ", directory: " + directories[index]);
236         }
237
238         final String JavaDoc cacheKey = getCacheKey(directories, index, name, locale);
239
240         XMLResourceBundle bundle = selectCached(cacheKey);
241         if (bundle == null) {
242             synchronized (this) {
243                 bundle = selectCached(cacheKey);
244                 if (bundle == null) {
245                     boolean localeAvailable = (locale != null && !locale.getLanguage().equals(""));
246                     index++;
247
248                     // Find parent bundle first
249
XMLResourceBundle parent = null;
250                     if (localeAvailable && index == directories.length) {
251                         // all directories have been searched with this locale,
252
// now start again with the first directory and the parent locale
253
parent = _select(directories, 0, name, getParentLocale(locale));
254                     } else if (index < directories.length) {
255                         // there are directories left to search for with this locale
256
parent = _select(directories, index, name, locale);
257                     }
258
259                     // Create this bundle (if source exists) and pass parent to it.
260
final String JavaDoc sourceURI = getSourceURI(directories[index - 1], name, locale);
261                     bundle = _create(sourceURI, locale, parent);
262                     updateCache(cacheKey, bundle);
263                 }
264             }
265         }
266         return bundle;
267     }
268
269     /**
270      * Constructs new bundle.
271      *
272      * <p>
273      * If there is a problem loading the bundle, created bundle will be empty.
274      *
275      * @param sourceURI source URI of the XML resource bundle
276      * @param locale locale of the bundle
277      * @param parent parent bundle, if any
278      * @return the bundle
279      */

280     private XMLResourceBundle _create(String JavaDoc sourceURI,
281                                       Locale JavaDoc locale,
282                                       XMLResourceBundle parent) {
283         if (getLogger().isDebugEnabled()) {
284             getLogger().debug("Creating bundle <" + sourceURI + ">");
285         }
286
287         XMLResourceBundle bundle = new XMLResourceBundle(sourceURI, locale, parent);
288         bundle.enableLogging(getLogger());
289         bundle.reload(this.resolver, this.interval);
290         return bundle;
291     }
292
293     /**
294      * Returns the next locale up the parent hierarchy.
295      * E.g. the parent of new Locale("en","us","mac") would be
296      * new Locale("en", "us", "").
297      *
298      * @param locale the locale
299      * @return the parent locale
300      */

301     protected Locale JavaDoc getParentLocale(Locale JavaDoc locale) {
302         Locale JavaDoc newloc;
303         if (locale.getVariant().equals("")) {
304             if (locale.getCountry().equals("")) {
305                 newloc = new Locale JavaDoc("", "", "");
306             } else {
307                 newloc = new Locale JavaDoc(locale.getLanguage(), "", "");
308             }
309         } else {
310             newloc = new Locale JavaDoc(locale.getLanguage(), locale.getCountry(), "");
311         }
312         return newloc;
313     }
314
315     /**
316      * Creates a cache key for the bundle.
317      * @return the cache key
318      */

319     protected String JavaDoc getCacheKey(String JavaDoc[] directories, int index, String JavaDoc name, Locale JavaDoc locale)
320     throws ComponentException {
321         StringBuffer JavaDoc cacheKey = new StringBuffer JavaDoc("XRB");
322         for (; index < directories.length; index++) {
323             cacheKey.append(":");
324             cacheKey.append(getSourceURI(directories[index], name, locale));
325         }
326         return cacheKey.toString();
327     }
328
329     /**
330      * Maps a bundle name and locale to a bundle source URI.
331      * If you need a different mapping, then just override this method.
332      *
333      * @param base the base URI for the catalogues
334      * @param name the name of the catalogue
335      * @param locale the locale of the bundle
336      * @return the source URI for the bundle
337      */

338     protected String JavaDoc getSourceURI(String JavaDoc base, String JavaDoc name, Locale JavaDoc locale)
339     throws ComponentException {
340         // If base is null default to the current location
341
if (base == null) {
342             base = "";
343         }
344
345         // Resolve base URI
346
Source src = null;
347         Map JavaDoc parameters = Collections.EMPTY_MAP;
348         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
349         try {
350             src = this.resolver.resolveURI(base);
351
352             // Deparameterize base URL before adding catalogue name
353
String JavaDoc uri = NetUtils.deparameterize(src.getURI(),
354                                                  parameters = new HashMap JavaDoc(7));
355
356             // Append trailing slash
357
sb.append(uri);
358             if (!uri.endsWith("/")) {
359                 sb.append('/');
360             }
361
362         } catch (IOException JavaDoc e) {
363             throw new ComponentException("Cannot resolve catalogue base URI <" + base + ">", name, e);
364         } finally {
365             this.resolver.release(src);
366         }
367
368         // Append catalogue name
369
sb.append(name);
370
371         // Append catalogue locale
372
if (locale != null) {
373             if (!locale.getLanguage().equals("")) {
374                 sb.append("_");
375                 sb.append(locale.getLanguage());
376             }
377             if (!locale.getCountry().equals("")) {
378                 sb.append("_");
379                 sb.append(locale.getCountry());
380             }
381             if (!locale.getVariant().equals("")) {
382                 sb.append("_");
383                 sb.append(locale.getVariant());
384             }
385         }
386         sb.append(".xml");
387
388         // Reconstruct complete bundle URI with parameters
389
String JavaDoc uri = NetUtils.parameterize(sb.toString(), parameters);
390
391         if (getLogger().isDebugEnabled()) {
392             getLogger().debug("Resolved name: " + name +
393                               ", locale: " + locale + " --> " + uri);
394         }
395         return uri;
396     }
397
398     /**
399      * Selects a bundle from the cache, and reloads it if needed.
400      *
401      * @param cacheKey caching key of the bundle
402      * @return the cached bundle; null, if not found
403      */

404     protected XMLResourceBundle selectCached(String JavaDoc cacheKey) {
405         XMLResourceBundle bundle = (XMLResourceBundle) this.cache.get(cacheKey);
406
407         if (bundle != null && this.interval != -1) {
408             // Reload this bundle and all parent bundles, as necessary
409
for (XMLResourceBundle b = bundle; b != null; b = (XMLResourceBundle) b.parent) {
410                 b.reload(this.resolver, this.interval);
411             }
412         }
413
414         return bundle;
415     }
416
417     /**
418      * Stores bundle in the cache.
419      *
420      * @param cacheKey caching key of the bundle
421      * @param bundle bundle to be placed in the cache
422      */

423     protected void updateCache(String JavaDoc cacheKey, XMLResourceBundle bundle) {
424         try {
425             this.cache.store(cacheKey, bundle);
426         } catch (IOException JavaDoc e) {
427             getLogger().error("Bundle <" + bundle.getSourceURI() + ">: unable to store.", e);
428         }
429     }
430 }
431
Popular Tags