KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > services > impl > ComponentMessagesSourceImpl


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

15 package org.apache.tapestry.services.impl;
16
17 import java.io.BufferedInputStream JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.net.URL JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Properties JavaDoc;
29
30 import org.apache.hivemind.ApplicationRuntimeException;
31 import org.apache.hivemind.Messages;
32 import org.apache.hivemind.Resource;
33 import org.apache.hivemind.util.Defense;
34 import org.apache.hivemind.util.LocalizedNameGenerator;
35 import org.apache.tapestry.IComponent;
36 import org.apache.tapestry.INamespace;
37 import org.apache.tapestry.event.ResetEventListener;
38 import org.apache.tapestry.services.ComponentMessagesSource;
39 import org.apache.tapestry.services.ComponentPropertySource;
40 import org.apache.tapestry.util.text.LocalizedProperties;
41
42 /**
43  * Service used to access localized properties for a component.
44  *
45  * @author Howard Lewis Ship
46  * @since 2.0.4
47  */

48
49 public class ComponentMessagesSourceImpl implements ComponentMessagesSource, ResetEventListener
50 {
51     private Properties JavaDoc _emptyProperties = new Properties JavaDoc();
52
53     private static final String JavaDoc SUFFIX = ".properties";
54
55     /**
56      * The name of the component/application/etc property that will be used to determine the
57      * encoding to use when loading the messages
58      */

59
60     public static final String JavaDoc MESSAGES_ENCODING_PROPERTY_NAME = "org.apache.tapestry.messages-encoding";
61
62     /**
63      * Map of Maps. The outer map is keyed on component specification location (a{@link Resource}.
64      * This inner map is keyed on locale and the value is a {@link Properties}.
65      */

66
67     private Map JavaDoc _componentCache = new HashMap JavaDoc();
68
69     private ComponentPropertySource _componentPropertySource;
70
71     /**
72      * Returns an instance of {@link Properties}containing the properly localized messages for the
73      * component, in the {@link Locale}identified by the component's containing page.
74      */

75
76     protected synchronized Properties JavaDoc getLocalizedProperties(IComponent component)
77     {
78         Defense.notNull(component, "component");
79
80         Resource specificationLocation = component.getSpecification().getSpecificationLocation();
81         Locale JavaDoc locale = component.getPage().getLocale();
82
83         Map JavaDoc propertiesMap = findPropertiesMapForResource(specificationLocation);
84
85         Properties JavaDoc result = (Properties JavaDoc) propertiesMap.get(locale);
86
87         if (result == null)
88         {
89
90             // Not found, create it now.
91

92             result = assembleComponentProperties(
93                     component,
94                     specificationLocation,
95                     propertiesMap,
96                     locale);
97
98             propertiesMap.put(locale, result);
99         }
100
101         return result;
102     }
103
104     private Map JavaDoc findPropertiesMapForResource(Resource resource)
105     {
106         Map JavaDoc result = (Map JavaDoc) _componentCache.get(resource);
107
108         if (result == null)
109         {
110             result = new HashMap JavaDoc();
111             _componentCache.put(resource, result);
112         }
113
114         return result;
115     }
116
117     private Properties JavaDoc getNamespaceProperties(IComponent component, Locale JavaDoc locale)
118     {
119         INamespace namespace = component.getNamespace();
120
121         Resource namespaceLocation = namespace.getSpecificationLocation();
122
123         Map JavaDoc propertiesMap = findPropertiesMapForResource(namespaceLocation);
124
125         Properties JavaDoc result = (Properties JavaDoc) propertiesMap.get(locale);
126
127         if (result == null)
128         {
129             result = assembleNamespaceProperties(namespace, propertiesMap, locale);
130
131             propertiesMap.put(locale, result);
132         }
133
134         return result;
135     }
136
137     private Properties JavaDoc assembleComponentProperties(IComponent component,
138             Resource baseResourceLocation, Map JavaDoc propertiesMap, Locale JavaDoc locale)
139     {
140         List JavaDoc localizations = findLocalizationsForResource(baseResourceLocation, locale);
141
142         Properties JavaDoc parent = getNamespaceProperties(component, locale);
143
144         Iterator JavaDoc i = localizations.iterator();
145
146         while (i.hasNext())
147         {
148             ResourceLocalization rl = (ResourceLocalization) i.next();
149
150             Locale JavaDoc l = rl.getLocale();
151
152             Properties JavaDoc properties = (Properties JavaDoc) propertiesMap.get(l);
153
154             if (properties == null)
155             {
156                 properties = readComponentProperties(component, l, rl.getResource(), parent);
157
158                 propertiesMap.put(l, properties);
159             }
160
161             parent = properties;
162         }
163
164         return parent;
165     }
166
167     private Properties JavaDoc assembleNamespaceProperties(INamespace namespace, Map JavaDoc propertiesMap,
168             Locale JavaDoc locale)
169     {
170         List JavaDoc localizations = findLocalizationsForResource(
171                 namespace.getSpecificationLocation(),
172                 locale);
173
174         // Build them back up in reverse order.
175

176         Properties JavaDoc parent = _emptyProperties;
177
178         Iterator JavaDoc i = localizations.iterator();
179
180         while (i.hasNext())
181         {
182             ResourceLocalization rl = (ResourceLocalization) i.next();
183
184             Locale JavaDoc l = rl.getLocale();
185
186             Properties JavaDoc properties = (Properties JavaDoc) propertiesMap.get(l);
187
188             if (properties == null)
189             {
190                 properties = readNamespaceProperties(namespace, l, rl.getResource(), parent);
191
192                 propertiesMap.put(l, properties);
193             }
194
195             parent = properties;
196         }
197
198         return parent;
199
200     }
201
202     /**
203      * Finds the localizations of the provided resource. Returns a List of
204      * {@link ResourceLocalization}(each pairing a locale with a localized resource). The list is
205      * ordered from most general (i.e., "foo.properties") to most specific (i.e.,
206      * "foo_en_US_yokel.properties").
207      */

208
209     private List JavaDoc findLocalizationsForResource(Resource resource, Locale JavaDoc locale)
210     {
211         List JavaDoc result = new ArrayList JavaDoc();
212
213         String JavaDoc baseName = extractBaseName(resource);
214
215         LocalizedNameGenerator g = new LocalizedNameGenerator(baseName, locale, SUFFIX);
216
217         while (g.more())
218         {
219             String JavaDoc localizedName = g.next();
220             Locale JavaDoc l = g.getCurrentLocale();
221             Resource localizedResource = resource.getRelativeResource(localizedName);
222
223             result.add(new ResourceLocalization(l, localizedResource));
224         }
225
226         Collections.reverse(result);
227
228         return result;
229     }
230
231     private String JavaDoc extractBaseName(Resource baseResourceLocation)
232     {
233         String JavaDoc fileName = baseResourceLocation.getName();
234         int dotx = fileName.lastIndexOf('.');
235
236         return fileName.substring(0, dotx);
237     }
238
239     private Properties JavaDoc readComponentProperties(IComponent component, Locale JavaDoc locale,
240             Resource propertiesResource, Properties JavaDoc parent)
241     {
242         String JavaDoc encoding = getComponentMessagesEncoding(component, locale);
243
244         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
245     }
246
247     private Properties JavaDoc readNamespaceProperties(INamespace namespace, Locale JavaDoc locale,
248             Resource propertiesResource, Properties JavaDoc parent)
249     {
250         String JavaDoc encoding = getNamespaceMessagesEncoding(namespace, locale);
251
252         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
253     }
254
255     private Properties JavaDoc readPropertiesResource(URL JavaDoc resourceURL, String JavaDoc encoding, Properties JavaDoc parent)
256     {
257         if (resourceURL == null)
258             return parent;
259
260         Properties JavaDoc result = new Properties JavaDoc(parent);
261
262         LocalizedProperties wrapper = new LocalizedProperties(result);
263
264         InputStream JavaDoc input = null;
265
266         try
267         {
268             input = new BufferedInputStream JavaDoc(resourceURL.openStream());
269
270             if (encoding == null)
271                 wrapper.load(input);
272             else
273                 wrapper.load(input, encoding);
274
275             input.close();
276         }
277         catch (IOException JavaDoc ex)
278         {
279             throw new ApplicationRuntimeException(ImplMessages.unableToLoadProperties(
280                     resourceURL,
281                     ex), ex);
282         }
283         finally
284         {
285             close(input);
286         }
287
288         return result;
289     }
290
291     private void close(InputStream JavaDoc is)
292     {
293         if (is != null)
294             try
295             {
296                 is.close();
297             }
298             catch (IOException JavaDoc ex)
299             {
300                 // Ignore.
301
}
302     }
303
304     /**
305      * Clears the cache of read properties files.
306      */

307
308     public synchronized void resetEventDidOccur()
309     {
310         _componentCache.clear();
311     }
312
313     public Messages getMessages(IComponent component)
314     {
315         return new ComponentMessages(component.getPage().getLocale(),
316                 getLocalizedProperties(component));
317     }
318
319     private String JavaDoc getComponentMessagesEncoding(IComponent component, Locale JavaDoc locale)
320     {
321         String JavaDoc encoding = _componentPropertySource.getLocalizedComponentProperty(
322                 component,
323                 locale,
324                 MESSAGES_ENCODING_PROPERTY_NAME);
325
326         if (encoding == null)
327             encoding = _componentPropertySource.getLocalizedComponentProperty(
328                     component,
329                     locale,
330                     TemplateSourceImpl.TEMPLATE_ENCODING_PROPERTY_NAME);
331
332         return encoding;
333     }
334
335     private String JavaDoc getNamespaceMessagesEncoding(INamespace namespace, Locale JavaDoc locale)
336     {
337         return _componentPropertySource.getLocalizedNamespaceProperty(
338                 namespace,
339                 locale,
340                 MESSAGES_ENCODING_PROPERTY_NAME);
341     }
342
343     public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
344     {
345         _componentPropertySource = componentPropertySource;
346     }
347 }
Popular Tags