Source Code Cross Referenced for PropertyMessageResources.java in  » Web-Framework » struts-1.3.8 » org » apache » struts » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » struts 1.3.8 » org.apache.struts.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: PropertyMessageResources.java 480549 2006-11-29 12:16:15Z niallp $
003:         *
004:         * Licensed to the Apache Software Foundation (ASF) under one
005:         * or more contributor license agreements.  See the NOTICE file
006:         * distributed with this work for additional information
007:         * regarding copyright ownership.  The ASF licenses this file
008:         * to you under the Apache License, Version 2.0 (the
009:         * "License"); you may not use this file except in compliance
010:         * with the License.  You may obtain a copy of the License at
011:         *
012:         *  http://www.apache.org/licenses/LICENSE-2.0
013:         *
014:         * Unless required by applicable law or agreed to in writing,
015:         * software distributed under the License is distributed on an
016:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017:         * KIND, either express or implied.  See the License for the
018:         * specific language governing permissions and limitations
019:         * under the License.
020:         */
021:        package org.apache.struts.util;
022:
023:        import org.apache.commons.logging.Log;
024:        import org.apache.commons.logging.LogFactory;
025:
026:        import java.io.IOException;
027:        import java.io.InputStream;
028:
029:        import java.util.HashMap;
030:        import java.util.Iterator;
031:        import java.util.Locale;
032:        import java.util.Properties;
033:
034:        /**
035:         * Concrete subclass of <code>MessageResources</code> that reads message keys
036:         * and corresponding strings from named property resources in a <b><i>similar</i></b> manner
037:         * (see <i>modes</i> below) that <code>java.util.PropertyResourceBundle</code> does.  The
038:         * <code>base</code> property defines the base property resource name, and
039:         * must be specified. <p> <strong>IMPLEMENTATION NOTE</strong> - This class
040:         * trades memory for speed by caching all messages located via generalizing
041:         * the Locale under the original locale as well. This results in specific
042:         * messages being stored in the message cache more than once, but improves
043:         * response time on subsequent requests for the same locale + key
044:         * combination.
045:         *
046:         * <h2>Operating Modes</h2>
047:         * This implementation can be configured to operate in one of three modes:
048:         * <ul>
049:         *    <li>1. <b>Default</b> - default, backwardly compatible, Struts behaviour (i.e. the way
050:         *    its always worked).</li>
051:         *    <li>2. <b>JSTL</b> - compatible with how JSTL finds messages
052:         *        (fix for <a href="http://issues.apache.org/struts/browse/STR-2925">STR-2925</a>)</li>
053:         *    <li>3. <b>Resource</b> - compatible with how Java's <code>PropertyResourceBundle</code>
054:         *        finds messages (fix for
055:         *        <a href="http://issues.apache.org/struts/browse/STR-2077">STR-2077</a>)</li>
056:         * </ul>
057:         *
058:         * <h3>1. Default Mode</h3>
059:         * <i>Default mode</i> is the way this implementation has always operated. It searches
060:         * for a message key for property resources in the following sequence:
061:         * <pre>
062:         *      base + "_" + localeLanguage + "_" + localeCountry + "_" + localeVariant
063:         *      base + "_" + localeLanguage + "_" + localeCountry
064:         *      base + "_" + localeLanguage
065:         *      base + "_" + default locale
066:         *      base
067:         * </pre>
068:         * <p>
069:         * This mode is the <i>default</i> and requires no additional configuration.
070:         *
071:         * <h3>2. JSTL Mode</h3>
072:         * <i>JSTL mode</i> is compatible with how JSTL operates and the default Locale
073:         * is not used when looking for a message key. <i>JSTL mode</i> searches for
074:         * a message key for property resources in the following sequence:
075:         * <pre>
076:         *      base + "_" + localeLanguage + "_" + localeCountry + "_" + localeVariant
077:         *      base + "_" + localeLanguage + "_" + localeCountry
078:         *      base + "_" + localeLanguage
079:         *      base
080:         * </pre>
081:         * <p>
082:         * Configure <code>PropertyMessageResources</code> to operate in this mode by
083:         * specifying a value of <code>JSTL</code> for the <code>mode</code>
084:         * key in your <code>struts-config.xml</code>:
085:         * <pre>
086:         *      &lt;message-resources parameter="mypackage.MyMessageResources"&gt;
087:         *          &lt;set-property key="mode" value="JSTL"/&gt;
088:         *      &lt;/message-resources&gt;
089:         * </pre>
090:         *
091:         * <h3>3. Resource Mode</h3>
092:         * <i>Resource mode</i> is compatible with how Java's <code>PropertyResourceBundle</code>
093:         * operates. <i>Resource mode</i> searches first through the specified Locale's language,
094:         * country and variant, then through the default Locale's language,
095:         * country and variant and finally using just the <code>base</code>:
096:         * <pre>
097:         *      base + "_" + localeLanguage + "_" + localeCountry + "_" + localeVariant
098:         *      base + "_" + localeLanguage + "_" + localeCountry
099:         *      base + "_" + localeLanguage
100:         *      base + "_" + defaultLanguage + "_" + defaultCountry + "_" + defaultVariant
101:         *      base + "_" + defaultLanguage + "_" + defaultCountry
102:         *      base + "_" + defaultLanguage
103:         *      base
104:         * </pre>
105:         * <p>
106:         * Configure <code>PropertyMessageResources</code> to operate in this mode by
107:         * specifying a value of <code>resource</code> for the <code>mode</code>
108:         * key in your <code>struts-config.xml</code>:
109:         * <pre>
110:         *      &lt;message-resources parameter="mypackage.MyMessageResources"&gt;
111:         *          &lt;set-property key="mode" value="resource"/&gt;
112:         *      &lt;/message-resources&gt;
113:         * </pre>
114:         * 
115:         * @version $Rev: 480549 $ $Date: 2006-11-29 06:16:15 -0600 (Wed, 29 Nov 2006) $
116:         */
117:        public class PropertyMessageResources extends MessageResources {
118:
119:            /** Indicates compatibility with how PropertyMessageResources has always looked up messages */
120:            private static final int MODE_DEFAULT = 0;
121:
122:            /** Indicates compatibility with how JSTL looks up messages */
123:            private static final int MODE_JSTL = 1;
124:
125:            /** Indicates compatibility with how java's PropertyResourceBundle looks up messages */
126:            private static final int MODE_RESOURCE_BUNDLE = 2;
127:
128:            /**
129:             * The <code>Log</code> instance for this class.
130:             */
131:            protected static final Log log = LogFactory
132:                    .getLog(PropertyMessageResources.class);
133:
134:            // ------------------------------------------------------------- Properties
135:
136:            /**
137:             * The set of locale keys for which we have already loaded messages, keyed
138:             * by the value calculated in <code>localeKey()</code>.
139:             */
140:            protected HashMap locales = new HashMap();
141:
142:            /**
143:             * The cache of messages we have accumulated over time, keyed by the value
144:             * calculated in <code>messageKey()</code>.
145:             */
146:            protected HashMap messages = new HashMap();
147:
148:            /**
149:             * Compatibility mode that PropertyMessageResources is operating in.
150:             */
151:            private int mode = MODE_DEFAULT;
152:
153:            // ----------------------------------------------------------- Constructors
154:
155:            /**
156:             * Construct a new PropertyMessageResources according to the specified
157:             * parameters.
158:             *
159:             * @param factory The MessageResourcesFactory that created us
160:             * @param config  The configuration parameter for this MessageResources
161:             */
162:            public PropertyMessageResources(MessageResourcesFactory factory,
163:                    String config) {
164:                super (factory, config);
165:                log.trace("Initializing, config='" + config + "'");
166:            }
167:
168:            /**
169:             * Construct a new PropertyMessageResources according to the specified
170:             * parameters.
171:             *
172:             * @param factory    The MessageResourcesFactory that created us
173:             * @param config     The configuration parameter for this
174:             *                   MessageResources
175:             * @param returnNull The returnNull property we should initialize with
176:             */
177:            public PropertyMessageResources(MessageResourcesFactory factory,
178:                    String config, boolean returnNull) {
179:                super (factory, config, returnNull);
180:                log.trace("Initializing, config='" + config + "', returnNull="
181:                        + returnNull);
182:            }
183:
184:            // --------------------------------------------------------- Public Methods
185:
186:            /**
187:             * Set the compatibility mode this implementation uses for message lookup.
188:             *
189:             * @param mode <code>JSTL</code> for JSTL compatibility,
190:             *  <code>resource</code> for PropertyResourceBundle compatibility or
191:             *  <code>default</code> for Struts backward compatibility.
192:             */
193:            public void setMode(String mode) {
194:                String value = (mode == null ? null : mode.trim());
195:                if ("jstl".equalsIgnoreCase(value)) {
196:                    this .mode = MODE_JSTL;
197:                    if (log.isDebugEnabled()) {
198:                        log.info("Operating in JSTL compatible mode [" + mode
199:                                + "]");
200:                    }
201:                } else if ("resource".equalsIgnoreCase(value)) {
202:                    this .mode = MODE_RESOURCE_BUNDLE;
203:                    if (log.isDebugEnabled()) {
204:                        log
205:                                .info("Operating in PropertyResourceBundle compatible mode ["
206:                                        + mode + "]");
207:                    }
208:                } else {
209:                    this .mode = MODE_DEFAULT;
210:                    if (log.isDebugEnabled()) {
211:                        log.info("Operating in Default mode [" + mode + "]");
212:                    }
213:                }
214:            }
215:
216:            /**
217:             * Returns a text message for the specified key, for the specified or default
218:             * Locale. A null string result will be returned by this method if no relevant
219:             * message resource is found for this key or Locale, if the
220:             * <code>returnNull</code> property is set.  Otherwise, an appropriate
221:             * error message will be returned. <p> This method must be implemented by
222:             * a concrete subclass.
223:             *
224:             * @param locale The requested message Locale, or <code>null</code> for
225:             *               the system default Locale
226:             * @param key    The message key to look up
227:             * @return text message for the specified key and locale
228:             */
229:            public String getMessage(Locale locale, String key) {
230:                if (log.isDebugEnabled()) {
231:                    log.debug("getMessage(" + locale + "," + key + ")");
232:                }
233:
234:                // Initialize variables we will require
235:                String localeKey = localeKey(locale);
236:                String originalKey = messageKey(localeKey, key);
237:                String message = null;
238:
239:                // Search the specified Locale
240:                message = findMessage(locale, key, originalKey);
241:                if (message != null) {
242:                    return message;
243:                }
244:
245:                // JSTL Compatibility - JSTL doesn't use the default locale
246:                if (mode == MODE_JSTL) {
247:
248:                    // do nothing (i.e. don't use default Locale)
249:
250:                    // PropertyResourcesBundle - searches through the hierarchy
251:                    // for the default Locale (e.g. first en_US then en)
252:                } else if (mode == MODE_RESOURCE_BUNDLE) {
253:
254:                    if (!defaultLocale.equals(locale)) {
255:                        message = findMessage(defaultLocale, key, originalKey);
256:                    }
257:
258:                    // Default (backwards) Compatibility - just searches the
259:                    // specified Locale (e.g. just en_US)
260:                } else {
261:
262:                    if (!defaultLocale.equals(locale)) {
263:                        localeKey = localeKey(defaultLocale);
264:                        message = findMessage(localeKey, key, originalKey);
265:                    }
266:
267:                }
268:                if (message != null) {
269:                    return message;
270:                }
271:
272:                // Find the message in the default properties file
273:                message = findMessage("", key, originalKey);
274:                if (message != null) {
275:                    return message;
276:                }
277:
278:                // Return an appropriate error indication
279:                if (returnNull) {
280:                    return (null);
281:                } else {
282:                    return ("???" + messageKey(locale, key) + "???");
283:                }
284:            }
285:
286:            // ------------------------------------------------------ Protected Methods
287:
288:            /**
289:             * Load the messages associated with the specified Locale key.  For this
290:             * implementation, the <code>config</code> property should contain a fully
291:             * qualified package and resource name, separated by periods, of a series
292:             * of property resources to be loaded from the class loader that created
293:             * this PropertyMessageResources instance.  This is exactly the same name
294:             * format you would use when utilizing the <code>java.util.PropertyResourceBundle</code>
295:             * class.
296:             *
297:             * @param localeKey Locale key for the messages to be retrieved
298:             */
299:            protected synchronized void loadLocale(String localeKey) {
300:                if (log.isTraceEnabled()) {
301:                    log.trace("loadLocale(" + localeKey + ")");
302:                }
303:
304:                // Have we already attempted to load messages for this locale?
305:                if (locales.get(localeKey) != null) {
306:                    return;
307:                }
308:
309:                locales.put(localeKey, localeKey);
310:
311:                // Set up to load the property resource for this locale key, if we can
312:                String name = config.replace('.', '/');
313:
314:                if (localeKey.length() > 0) {
315:                    name += ("_" + localeKey);
316:                }
317:
318:                name += ".properties";
319:
320:                InputStream is = null;
321:                Properties props = new Properties();
322:
323:                // Load the specified property resource
324:                if (log.isTraceEnabled()) {
325:                    log.trace("  Loading resource '" + name + "'");
326:                }
327:
328:                ClassLoader classLoader = Thread.currentThread()
329:                        .getContextClassLoader();
330:
331:                if (classLoader == null) {
332:                    classLoader = this .getClass().getClassLoader();
333:                }
334:
335:                is = classLoader.getResourceAsStream(name);
336:
337:                if (is != null) {
338:                    try {
339:                        props.load(is);
340:                    } catch (IOException e) {
341:                        log.error("loadLocale()", e);
342:                    } finally {
343:                        try {
344:                            is.close();
345:                        } catch (IOException e) {
346:                            log.error("loadLocale()", e);
347:                        }
348:                    }
349:                    if (log.isTraceEnabled()) {
350:                        log.trace("  Loading resource completed");
351:                    }
352:                } else {
353:                    if (log.isWarnEnabled()) {
354:                        log.warn("  Resource " + name + " Not Found.");
355:                    }
356:                }
357:
358:                // Copy the corresponding values into our cache
359:                if (props.size() < 1) {
360:                    return;
361:                }
362:
363:                synchronized (messages) {
364:                    Iterator names = props.keySet().iterator();
365:
366:                    while (names.hasNext()) {
367:                        String key = (String) names.next();
368:
369:                        if (log.isTraceEnabled()) {
370:                            log.trace("  Saving message key '"
371:                                    + messageKey(localeKey, key));
372:                        }
373:
374:                        messages.put(messageKey(localeKey, key), props
375:                                .getProperty(key));
376:                    }
377:                }
378:            }
379:
380:            // -------------------------------------------------------- Private Methods
381:
382:            /**
383:             * Returns a text message for the specified key, for the specified Locale.
384:             * <p>
385:             * A null string result will be returned by this method if no relevant
386:             * message resource is found. This method searches through the locale
387:             * <i>hierarchy</i> (i.e. variant --> languge --> country) for the message.
388:             *
389:             * @param locale The requested message Locale, or <code>null</code> for
390:             *  the system default Locale
391:             * @param key The message key to look up
392:             * @param originalKey The original message key to cache any found message under
393:             * @return text message for the specified key and locale
394:             */
395:            private String findMessage(Locale locale, String key,
396:                    String originalKey) {
397:
398:                // Initialize variables we will require
399:                String localeKey = localeKey(locale);
400:                String messageKey = null;
401:                String message = null;
402:                int underscore = 0;
403:
404:                // Loop from specific to general Locales looking for this message
405:                while (true) {
406:                    message = findMessage(localeKey, key, originalKey);
407:                    if (message != null) {
408:                        break;
409:                    }
410:
411:                    // Strip trailing modifiers to try a more general locale key
412:                    underscore = localeKey.lastIndexOf("_");
413:
414:                    if (underscore < 0) {
415:                        break;
416:                    }
417:
418:                    localeKey = localeKey.substring(0, underscore);
419:                }
420:
421:                return message;
422:
423:            }
424:
425:            /**
426:             * Returns a text message for the specified key, for the specified Locale.
427:             * <p>
428:             * A null string result will be returned by this method if no relevant
429:             * message resource is found.
430:             *
431:             * @param locale The requested key of the Locale
432:             * @param key The message key to look up
433:             * @param originalKey The original message key to cache any found message under
434:             * @return text message for the specified key and locale
435:             */
436:            private String findMessage(String localeKey, String key,
437:                    String originalKey) {
438:
439:                // Load this Locale's messages if we have not done so yet
440:                loadLocale(localeKey);
441:
442:                // Check if we have this key for the current locale key
443:                String messageKey = messageKey(localeKey, key);
444:
445:                // Add if not found under the original key
446:                boolean addIt = !messageKey.equals(originalKey);
447:
448:                synchronized (messages) {
449:                    String message = (String) messages.get(messageKey);
450:
451:                    if (message != null) {
452:                        if (addIt) {
453:                            messages.put(originalKey, message);
454:                        }
455:
456:                    }
457:                    return (message);
458:                }
459:            }
460:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.