001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.util;
051:
052: import java.io.*;
053: import java.util.*;
054: import org.apache.struts.util.MessageResourcesFactory;
055:
056: /**
057: * Concrete subclass of <code>MessageResources</code> that reads message keys
058: * and corresponding strings from named property resources in the same manner
059: * that java.util.PropertyResourceBundle does. The
060: * base property defines the base property resource name, and
061: * must be specified.
062: *
063: * IMPLEMENTATION NOTE - This class trades memory for
064: * speed by caching all messages located via generalizing the Locale under
065: * the original locale as well.
066: * This results in specific messages being stored in the message cache
067: * more than once, but improves response time on subsequent requests for
068: * the same locale + key combination.
069: *
070: * This class is based on the struts class org.apache.struts.util.PropertyMessageResources
071: * It loads the properties file using File I/O. This allows us to view the changes to the file, without having to reload the webapp.
072: * It supports the flushing of the message-resource cache.
073: * @author GautamJ
074: */
075: public class PropertyMessageResources extends
076: org.apache.struts.util.PropertyMessageResources {
077:
078: /**
079: * Construct a new PropertyMessageResources according to the
080: * specified parameters.
081: *
082: * @param factory The MessageResourcesFactory that created us
083: * @param config The configuration parameter for this MessageResources
084: */
085: public PropertyMessageResources(MessageResourcesFactory factory,
086: String config) {
087: super (factory, config);
088: }
089:
090: /**
091: * Construct a new PropertyMessageResources according to the
092: * specified parameters.
093: *
094: * @param factory The MessageResourcesFactory that created us
095: * @param config The configuration parameter for this MessageResources
096: * @param returnNull The returnNull property we should initialize with
097: */
098: public PropertyMessageResources(MessageResourcesFactory factory,
099: String config, boolean returnNull) {
100: super (factory, config, returnNull);
101: }
102:
103: /** This method flushes the cache that holds all the messages read from the resource.
104: */
105: public synchronized void flushCache() {
106: synchronized (super .formats) {
107: super .formats.clear();
108: }
109: synchronized (super .messages) {
110: super .messages.clear();
111: }
112: super .locales.clear();
113: }
114:
115: /** This method is a copy of the implementation in the base class
116: * The only difference is that it tries to first load the properties file using File I/O; if that doesn't work, then it uses the ClassLoader to load the file.
117: *
118: * Load the messages associated with the specified Locale key. For this
119: * implementation, the <code>config</code> property should contain a fully
120: * qualified package and resource name, separated by periods, of a series
121: * of property resources to be loaded from the class loader that created
122: * this PropertyMessageResources instance. This is exactly the same name
123: * format you would use when utilizing the
124: * <code>java.util.PropertyResourceBundle</code> class.
125: *
126: * @param localeKey Locale key for the messages to be retrieved
127: */
128: protected synchronized void loadLocale(String localeKey) {
129:
130: if (log.isTraceEnabled()) {
131: log.trace("loadLocale(" + localeKey + ")");
132: }
133:
134: // Have we already attempted to load messages for this locale?
135: if (locales.get(localeKey) != null) {
136: return;
137: }
138: locales.put(localeKey, localeKey);
139:
140: // Set up to load the property resource for this locale key, if we can
141: String name = config.replace('.', '/');
142: if (localeKey.length() > 0) {
143: name += "_" + localeKey;
144: }
145: name += ".properties";
146: InputStream is = null;
147: Properties props = new Properties();
148:
149: // Load the specified property resource
150: if (log.isTraceEnabled()) {
151: log.trace(" Loading resource '" + name + "'");
152: }
153:
154: //ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
155: //if (classLoader == null) {
156: //classLoader = this.getClass().getClassLoader();
157: //}
158: //is = classLoader.getResourceAsStream(name);
159:
160: // Try to load the file using ClassLoader.getResource(name).openStream()
161: // This allows us to view the changes to the file, without having to reload the webapp
162: try {
163: is = URLHelper.getInputStream(name);
164: } catch (Exception e) {
165: log.error("loadLocale()", e);
166: }
167:
168: if (is != null) {
169: try {
170: props.load(is);
171:
172: } catch (IOException e) {
173: log.error("loadLocale()", e);
174: } finally {
175: try {
176: is.close();
177: } catch (IOException e) {
178: log.error("loadLocale()", e);
179: }
180: }
181: }
182:
183: if (log.isTraceEnabled()) {
184: log.trace(" Loading resource completed");
185: }
186:
187: // Copy the corresponding values into our cache
188: if (props.size() < 1) {
189: return;
190: }
191:
192: synchronized (messages) {
193: Iterator names = props.keySet().iterator();
194: while (names.hasNext()) {
195: String key = (String) names.next();
196: if (log.isTraceEnabled()) {
197: log.trace(" Saving message key '"
198: + messageKey(localeKey, key));
199: }
200: messages.put(messageKey(localeKey, key), props
201: .getProperty(key));
202: }
203: }
204:
205: }
206:
207: }
|