~ubuntu-branches/ubuntu/trusty/libstruts1.2-java/trusty-proposed

« back to all changes in this revision

Viewing changes to src/share/org/apache/struts/util/PropertyMessageResources.java

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Vandyck
  • Date: 2004-11-19 15:35:25 UTC
  • Revision ID: james.westby@ubuntu.com-20041119153525-mdu08a76z4zo67xt
Tags: upstream-1.2.4
ImportĀ upstreamĀ versionĀ 1.2.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyMessageResources.java,v 1.12 2004/03/14 06:23:51 sraeburn Exp $
 
3
 * $Revision: 1.12 $
 
4
 * $Date: 2004/03/14 06:23:51 $
 
5
 *
 
6
 * Copyright 1999-2004 The Apache Software Foundation.
 
7
 * 
 
8
 * Licensed under the Apache License, Version 2.0 (the "License");
 
9
 * you may not use this file except in compliance with the License.
 
10
 * You may obtain a copy of the License at
 
11
 * 
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 * 
 
14
 * Unless required by applicable law or agreed to in writing, software
 
15
 * distributed under the License is distributed on an "AS IS" BASIS,
 
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
17
 * See the License for the specific language governing permissions and
 
18
 * limitations under the License.
 
19
 */ 
 
20
 
 
21
 
 
22
package org.apache.struts.util;
 
23
 
 
24
import java.io.IOException;
 
25
import java.io.InputStream;
 
26
import java.util.HashMap;
 
27
import java.util.Iterator;
 
28
import java.util.Locale;
 
29
import java.util.Properties;
 
30
 
 
31
import org.apache.commons.logging.Log;
 
32
import org.apache.commons.logging.LogFactory;
 
33
 
 
34
/**
 
35
 * Concrete subclass of <code>MessageResources</code> that reads message keys
 
36
 * and corresponding strings from named property resources in the same manner
 
37
 * that <code>java.util.PropertyResourceBundle</code> does.  The
 
38
 * <code>base</code> property defines the base property resource name, and
 
39
 * must be specified.
 
40
 * <p>
 
41
 * <strong>IMPLEMENTATION NOTE</strong> - This class trades memory for
 
42
 * speed by caching all messages located via generalizing the Locale under
 
43
 * the original locale as well.
 
44
 * This results in specific messages being stored in the message cache
 
45
 * more than once, but improves response time on subsequent requests for
 
46
 * the same locale + key combination.
 
47
 *
 
48
 * @version $Revision: 1.12 $ $Date: 2004/03/14 06:23:51 $
 
49
 */
 
50
public class PropertyMessageResources extends MessageResources {
 
51
 
 
52
 
 
53
    // ----------------------------------------------------------- Constructors
 
54
 
 
55
 
 
56
    /**
 
57
     * Construct a new PropertyMessageResources according to the
 
58
     * specified parameters.
 
59
     *
 
60
     * @param factory The MessageResourcesFactory that created us
 
61
     * @param config The configuration parameter for this MessageResources
 
62
     */
 
63
    public PropertyMessageResources(MessageResourcesFactory factory,
 
64
                                    String config) {
 
65
 
 
66
        super(factory, config);
 
67
        log.trace("Initializing, config='" + config + "'");
 
68
 
 
69
    }
 
70
 
 
71
 
 
72
    /**
 
73
     * Construct a new PropertyMessageResources according to the
 
74
     * specified parameters.
 
75
     *
 
76
     * @param factory The MessageResourcesFactory that created us
 
77
     * @param config The configuration parameter for this MessageResources
 
78
     * @param returnNull The returnNull property we should initialize with
 
79
     */
 
80
    public PropertyMessageResources(MessageResourcesFactory factory,
 
81
                                    String config, boolean returnNull) {
 
82
 
 
83
        super(factory, config, returnNull);
 
84
        log.trace("Initializing, config='" + config +
 
85
                 "', returnNull=" + returnNull);
 
86
 
 
87
    }
 
88
 
 
89
 
 
90
    // ------------------------------------------------------------- Properties
 
91
 
 
92
 
 
93
    /**
 
94
     * The set of locale keys for which we have already loaded messages, keyed
 
95
     * by the value calculated in <code>localeKey()</code>.
 
96
     */
 
97
    protected HashMap locales = new HashMap();
 
98
 
 
99
 
 
100
    /**
 
101
     * The <code>Log</code> instance for this class.
 
102
     */
 
103
        protected static final Log log =
 
104
                LogFactory.getLog(PropertyMessageResources.class);
 
105
 
 
106
 
 
107
    /**
 
108
     * The cache of messages we have accumulated over time, keyed by the
 
109
     * value calculated in <code>messageKey()</code>.
 
110
     */
 
111
    protected HashMap messages = new HashMap();
 
112
 
 
113
 
 
114
    // --------------------------------------------------------- Public Methods
 
115
 
 
116
 
 
117
    /**
 
118
     * Returns a text message for the specified key, for the default Locale.
 
119
     * A null string result will be returned by this method if no relevant
 
120
     * message resource is found for this key or Locale, if the
 
121
     * <code>returnNull</code> property is set.  Otherwise, an appropriate
 
122
     * error message will be returned.
 
123
     * <p>
 
124
     * This method must be implemented by a concrete subclass.
 
125
     *
 
126
     * @param locale The requested message Locale, or <code>null</code>
 
127
     *  for the system default Locale
 
128
     * @param key The message key to look up
 
129
     * @return text message for the specified key and locale
 
130
     */
 
131
    public String getMessage(Locale locale, String key) {
 
132
 
 
133
        if (log.isDebugEnabled()) {
 
134
            log.debug("getMessage(" + locale + "," + key + ")");
 
135
        }
 
136
 
 
137
        // Initialize variables we will require
 
138
        String localeKey = localeKey(locale);
 
139
        String originalKey = messageKey(localeKey, key);
 
140
        String messageKey = null;
 
141
        String message = null;
 
142
        int underscore = 0;
 
143
        boolean addIt = false;  // Add if not found under the original key
 
144
 
 
145
        // Loop from specific to general Locales looking for this message
 
146
        while (true) {
 
147
 
 
148
            // Load this Locale's messages if we have not done so yet
 
149
            loadLocale(localeKey);
 
150
 
 
151
            // Check if we have this key for the current locale key
 
152
            messageKey = messageKey(localeKey, key);
 
153
            synchronized (messages) {
 
154
                message = (String) messages.get(messageKey);
 
155
                if (message != null) {
 
156
                    if (addIt) {
 
157
                        messages.put(originalKey, message);
 
158
                    }
 
159
                    return (message);
 
160
                }
 
161
            }
 
162
 
 
163
            // Strip trailing modifiers to try a more general locale key
 
164
            addIt = true;
 
165
            underscore = localeKey.lastIndexOf("_");
 
166
            if (underscore < 0) {
 
167
                break;
 
168
            }
 
169
            localeKey = localeKey.substring(0, underscore);
 
170
 
 
171
        }
 
172
 
 
173
        // Try the default locale if the current locale is different
 
174
        if (!defaultLocale.equals(locale)) {
 
175
            localeKey = localeKey(defaultLocale);
 
176
            messageKey = messageKey(localeKey, key);
 
177
            loadLocale(localeKey);
 
178
            synchronized (messages) {
 
179
                message = (String) messages.get(messageKey);
 
180
                if (message != null) {
 
181
                    messages.put(originalKey, message);
 
182
                    return (message);
 
183
                }
 
184
            }
 
185
        }
 
186
 
 
187
        // As a last resort, try the default Locale
 
188
        localeKey = "";
 
189
        messageKey = messageKey(localeKey, key);
 
190
        loadLocale(localeKey);
 
191
        synchronized (messages) {
 
192
            message = (String) messages.get(messageKey);
 
193
            if (message != null) {
 
194
                messages.put(originalKey, message);
 
195
                return (message);
 
196
            }
 
197
        }
 
198
 
 
199
        // Return an appropriate error indication
 
200
        if (returnNull) {
 
201
            return (null);
 
202
        } else {
 
203
            return ("???" + messageKey(locale, key) + "???");
 
204
        }
 
205
 
 
206
    }
 
207
 
 
208
 
 
209
    // ------------------------------------------------------ Protected Methods
 
210
 
 
211
 
 
212
    /**
 
213
     * Load the messages associated with the specified Locale key.  For this
 
214
     * implementation, the <code>config</code> property should contain a fully
 
215
     * qualified package and resource name, separated by periods, of a series
 
216
     * of property resources to be loaded from the class loader that created
 
217
     * this PropertyMessageResources instance.  This is exactly the same name
 
218
     * format you would use when utilizing the
 
219
     * <code>java.util.PropertyResourceBundle</code> class.
 
220
     *
 
221
     * @param localeKey Locale key for the messages to be retrieved
 
222
     */
 
223
    protected synchronized void loadLocale(String localeKey) {
 
224
 
 
225
        if (log.isTraceEnabled()) {
 
226
            log.trace("loadLocale(" + localeKey + ")");
 
227
        }
 
228
        
 
229
        // Have we already attempted to load messages for this locale?
 
230
        if (locales.get(localeKey) != null) {
 
231
            return;
 
232
        }
 
233
        
 
234
        locales.put(localeKey, localeKey);
 
235
 
 
236
        // Set up to load the property resource for this locale key, if we can
 
237
        String name = config.replace('.', '/');
 
238
        if (localeKey.length() > 0) {
 
239
            name += "_" + localeKey;
 
240
        }
 
241
        
 
242
        name += ".properties";
 
243
        InputStream is = null;
 
244
        Properties props = new Properties();
 
245
 
 
246
        // Load the specified property resource
 
247
        if (log.isTraceEnabled()) {
 
248
            log.trace("  Loading resource '" + name + "'");
 
249
        }
 
250
        
 
251
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 
252
        if (classLoader == null) {
 
253
            classLoader = this.getClass().getClassLoader();
 
254
        }
 
255
        
 
256
        is = classLoader.getResourceAsStream(name);
 
257
        if (is != null) {
 
258
            try {
 
259
                props.load(is);
 
260
                
 
261
            } catch (IOException e) {
 
262
                log.error("loadLocale()", e);
 
263
            } finally {
 
264
                try {
 
265
                    is.close();
 
266
                } catch (IOException e) {
 
267
                    log.error("loadLocale()", e);
 
268
                }
 
269
            }
 
270
        }
 
271
        
 
272
        if (log.isTraceEnabled()) {
 
273
            log.trace("  Loading resource completed");
 
274
        }
 
275
 
 
276
        // Copy the corresponding values into our cache
 
277
        if (props.size() < 1) {
 
278
            return;
 
279
        }
 
280
        
 
281
        synchronized (messages) {
 
282
            Iterator names = props.keySet().iterator();
 
283
            while (names.hasNext()) {
 
284
                String key = (String) names.next();
 
285
                if (log.isTraceEnabled()) {
 
286
                    log.trace("  Saving message key '" + messageKey(localeKey, key));
 
287
                }
 
288
                messages.put(messageKey(localeKey, key), props.getProperty(key));
 
289
            }
 
290
        }
 
291
 
 
292
    }
 
293
 
 
294
 
 
295
}