KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > util > PropertyMessageResources


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

18
19
20 package org.apache.struts.util;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Properties JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 /**
33  * Concrete subclass of <code>MessageResources</code> that reads message keys
34  * and corresponding strings from named property resources in the same manner
35  * that <code>java.util.PropertyResourceBundle</code> does. The
36  * <code>base</code> property defines the base property resource name, and
37  * must be specified.
38  * <p>
39  * <strong>IMPLEMENTATION NOTE</strong> - This class trades memory for
40  * speed by caching all messages located via generalizing the Locale under
41  * the original locale as well.
42  * This results in specific messages being stored in the message cache
43  * more than once, but improves response time on subsequent requests for
44  * the same locale + key combination.
45  *
46  * @version $Rev: 54929 $ $Date: 2004-10-16 17:38:42 +0100 (Sat, 16 Oct 2004) $
47  */

48 public class PropertyMessageResources extends MessageResources {
49
50
51     // ----------------------------------------------------------- Constructors
52

53
54     /**
55      * Construct a new PropertyMessageResources according to the
56      * specified parameters.
57      *
58      * @param factory The MessageResourcesFactory that created us
59      * @param config The configuration parameter for this MessageResources
60      */

61     public PropertyMessageResources(MessageResourcesFactory factory,
62                                     String JavaDoc config) {
63
64         super(factory, config);
65         log.trace("Initializing, config='" + config + "'");
66
67     }
68
69
70     /**
71      * Construct a new PropertyMessageResources according to the
72      * specified parameters.
73      *
74      * @param factory The MessageResourcesFactory that created us
75      * @param config The configuration parameter for this MessageResources
76      * @param returnNull The returnNull property we should initialize with
77      */

78     public PropertyMessageResources(MessageResourcesFactory factory,
79                                     String JavaDoc config, boolean returnNull) {
80
81         super(factory, config, returnNull);
82         log.trace("Initializing, config='" + config +
83                  "', returnNull=" + returnNull);
84
85     }
86
87
88     // ------------------------------------------------------------- Properties
89

90
91     /**
92      * The set of locale keys for which we have already loaded messages, keyed
93      * by the value calculated in <code>localeKey()</code>.
94      */

95     protected HashMap JavaDoc locales = new HashMap JavaDoc();
96
97
98     /**
99      * The <code>Log</code> instance for this class.
100      */

101     protected static final Log log =
102         LogFactory.getLog(PropertyMessageResources.class);
103
104
105     /**
106      * The cache of messages we have accumulated over time, keyed by the
107      * value calculated in <code>messageKey()</code>.
108      */

109     protected HashMap JavaDoc messages = new HashMap JavaDoc();
110
111
112     // --------------------------------------------------------- Public Methods
113

114
115     /**
116      * Returns a text message for the specified key, for the default Locale.
117      * A null string result will be returned by this method if no relevant
118      * message resource is found for this key or Locale, if the
119      * <code>returnNull</code> property is set. Otherwise, an appropriate
120      * error message will be returned.
121      * <p>
122      * This method must be implemented by a concrete subclass.
123      *
124      * @param locale The requested message Locale, or <code>null</code>
125      * for the system default Locale
126      * @param key The message key to look up
127      * @return text message for the specified key and locale
128      */

129     public String JavaDoc getMessage(Locale JavaDoc locale, String JavaDoc key) {
130
131         if (log.isDebugEnabled()) {
132             log.debug("getMessage(" + locale + "," + key + ")");
133         }
134
135         // Initialize variables we will require
136
String JavaDoc localeKey = localeKey(locale);
137         String JavaDoc originalKey = messageKey(localeKey, key);
138         String JavaDoc messageKey = null;
139         String JavaDoc message = null;
140         int underscore = 0;
141         boolean addIt = false; // Add if not found under the original key
142

143         // Loop from specific to general Locales looking for this message
144
while (true) {
145
146             // Load this Locale's messages if we have not done so yet
147
loadLocale(localeKey);
148
149             // Check if we have this key for the current locale key
150
messageKey = messageKey(localeKey, key);
151             synchronized (messages) {
152                 message = (String JavaDoc) messages.get(messageKey);
153                 if (message != null) {
154                     if (addIt) {
155                         messages.put(originalKey, message);
156                     }
157                     return (message);
158                 }
159             }
160
161             // Strip trailing modifiers to try a more general locale key
162
addIt = true;
163             underscore = localeKey.lastIndexOf("_");
164             if (underscore < 0) {
165                 break;
166             }
167             localeKey = localeKey.substring(0, underscore);
168
169         }
170
171         // Try the default locale if the current locale is different
172
if (!defaultLocale.equals(locale)) {
173             localeKey = localeKey(defaultLocale);
174             messageKey = messageKey(localeKey, key);
175             loadLocale(localeKey);
176             synchronized (messages) {
177                 message = (String JavaDoc) messages.get(messageKey);
178                 if (message != null) {
179                     messages.put(originalKey, message);
180                     return (message);
181                 }
182             }
183         }
184
185         // As a last resort, try the default Locale
186
localeKey = "";
187         messageKey = messageKey(localeKey, key);
188         loadLocale(localeKey);
189         synchronized (messages) {
190             message = (String JavaDoc) messages.get(messageKey);
191             if (message != null) {
192                 messages.put(originalKey, message);
193                 return (message);
194             }
195         }
196
197         // Return an appropriate error indication
198
if (returnNull) {
199             return (null);
200         } else {
201             return ("???" + messageKey(locale, key) + "???");
202         }
203
204     }
205
206
207     // ------------------------------------------------------ Protected Methods
208

209
210     /**
211      * Load the messages associated with the specified Locale key. For this
212      * implementation, the <code>config</code> property should contain a fully
213      * qualified package and resource name, separated by periods, of a series
214      * of property resources to be loaded from the class loader that created
215      * this PropertyMessageResources instance. This is exactly the same name
216      * format you would use when utilizing the
217      * <code>java.util.PropertyResourceBundle</code> class.
218      *
219      * @param localeKey Locale key for the messages to be retrieved
220      */

221     protected synchronized void loadLocale(String JavaDoc localeKey) {
222
223         if (log.isTraceEnabled()) {
224             log.trace("loadLocale(" + localeKey + ")");
225         }
226         
227         // Have we already attempted to load messages for this locale?
228
if (locales.get(localeKey) != null) {
229             return;
230         }
231         
232         locales.put(localeKey, localeKey);
233
234         // Set up to load the property resource for this locale key, if we can
235
String JavaDoc name = config.replace('.', '/');
236         if (localeKey.length() > 0) {
237             name += "_" + localeKey;
238         }
239         
240         name += ".properties";
241         InputStream JavaDoc is = null;
242         Properties JavaDoc props = new Properties JavaDoc();
243
244         // Load the specified property resource
245
if (log.isTraceEnabled()) {
246             log.trace(" Loading resource '" + name + "'");
247         }
248         
249         ClassLoader JavaDoc classLoader = Thread.currentThread().getContextClassLoader();
250         if (classLoader == null) {
251             classLoader = this.getClass().getClassLoader();
252         }
253         
254         is = classLoader.getResourceAsStream(name);
255         if (is != null) {
256             try {
257                 props.load(is);
258                 
259             } catch (IOException JavaDoc e) {
260                 log.error("loadLocale()", e);
261             } finally {
262                 try {
263                     is.close();
264                 } catch (IOException JavaDoc e) {
265                     log.error("loadLocale()", e);
266                 }
267             }
268         }
269         
270         if (log.isTraceEnabled()) {
271             log.trace(" Loading resource completed");
272         }
273
274         // Copy the corresponding values into our cache
275
if (props.size() < 1) {
276             return;
277         }
278         
279         synchronized (messages) {
280             Iterator JavaDoc names = props.keySet().iterator();
281             while (names.hasNext()) {
282                 String JavaDoc key = (String JavaDoc) names.next();
283                 if (log.isTraceEnabled()) {
284                     log.trace(" Saving message key '" + messageKey(localeKey, key));
285                 }
286                 messages.put(messageKey(localeKey, key), props.getProperty(key));
287             }
288         }
289
290     }
291
292
293 }
294
Popular Tags