You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@locus.apache.org on 2000/12/15 04:08:13 UTC
cvs commit: jakarta-struts/src/share/org/apache/struts/util MessageResourcesFactory.java PropertyMessageResources.java PropertyMessageResourcesFactory.java ServletContextWriter.java MessageResources.java
craigmcc 00/12/14 19:08:12
Modified: src/share/org/apache/struts/action ActionServlet.java
src/share/org/apache/struts/util MessageResources.java
Added: src/share/org/apache/struts/util
MessageResourcesFactory.java
PropertyMessageResources.java
PropertyMessageResourcesFactory.java
ServletContextWriter.java
Log:
Replace the previous implementation of MessageResources with a set of
classes offering the following features:
- The MessageResources instance is now Serializable, to make it work
in application servers that require this even for application scope
beans
- The MessageResources implementation class (and the implementation class
for the corresponding MessageResourcesFactory) are pluggable at run time
so that you can provide your own MessageResources implementations.
- The Struts controller servlet accepts a new "factory" initialization
parameter to set the name of the MessageResourcesFactory class to use.
- The default implementation reads resource property files from the
web app class path, just as the previous version did.
- No changes in existing classes are required if you always want the
currently registered default implementation class.
Revision Changes Path
1.42 +29 -6 jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java
Index: ActionServlet.java
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- ActionServlet.java 2000/12/06 19:15:58 1.41
+++ ActionServlet.java 2000/12/15 03:08:09 1.42
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.41 2000/12/06 19:15:58 craigmcc Exp $
- * $Revision: 1.41 $
- * $Date: 2000/12/06 19:15:58 $
+ * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.42 2000/12/15 03:08:09 craigmcc Exp $
+ * $Revision: 1.42 $
+ * $Date: 2000/12/15 03:08:09 $
*
* ====================================================================
*
@@ -85,6 +85,8 @@
import org.apache.struts.util.BeanUtils;
import org.apache.struts.util.GenericDataSource;
import org.apache.struts.util.MessageResources;
+import org.apache.struts.util.MessageResourcesFactory;
+import org.apache.struts.util.ServletContextWriter;
import org.xml.sax.SAXException;
@@ -161,6 +163,9 @@
* <li><strong>detail</strong> - The debugging detail level for the Digester
* we utilize in <code>initMapping()</code>, which logs to System.out
* instead of the servlet log. [0]</li>
+ * <li><strong>factory</strong> - The Java class name of the
+ * <code>MessageResourcesFactory</code> used to create the application
+ * <code>MessageResources</code> object.</li>
* <li><strong>forward</strong> - The Java class name of the ActionForward
* implementation to use [org.apache.struts.action.ActionForward].
* Two convenient classes you may wish to use are:
@@ -203,7 +208,7 @@
* </ul>
*
* @author Craig R. McClanahan
- * @version $Revision: 1.41 $ $Date: 2000/12/06 19:15:58 $
+ * @version $Revision: 1.42 $ $Date: 2000/12/15 03:08:09 $
*/
public class ActionServlet
@@ -259,6 +264,13 @@
/**
+ * The Java class name of the <code>MessageResourcesFactory</code>
+ * class for the application message resources bundle.
+ */
+ protected String factoryClass = null;
+
+
+ /**
* The Java class name of the ActionFormBean implementation class to use.
*/
protected String formBeanClass =
@@ -887,10 +899,21 @@
String value = getServletConfig().getInitParameter("application");
if (value == null)
return;
+ String factory =
+ getServletConfig().getInitParameter("factory");
if (debug >= 1)
log(internal.getMessage("applicationLoading", value));
try {
- application = MessageResources.getMessageResources(value);
+ MessageResourcesFactory.setDefaultWriter
+ (new ServletContextWriter(getServletContext()));
+ String oldFactory =
+ MessageResourcesFactory.getFactoryClass();
+ if (factory != null)
+ MessageResourcesFactory.setFactoryClass(factory);
+ MessageResourcesFactory factoryObject =
+ MessageResourcesFactory.createFactory();
+ application = factoryObject.createResources(value);
+ MessageResourcesFactory.setFactoryClass(oldFactory);
value = getServletConfig().getInitParameter("null");
if (value == null)
value = "true";
@@ -899,7 +922,7 @@
application.setReturnNull(true);
else
application.setReturnNull(false);
- } catch (MissingResourceException e) {
+ } catch (Throwable e) {
log(internal.getMessage("applicationResources", value), e);
throw new UnavailableException
(internal.getMessage("applicationResources", value));
1.5 +164 -213 jakarta-struts/src/share/org/apache/struts/util/MessageResources.java
Index: MessageResources.java
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/MessageResources.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- MessageResources.java 2000/08/01 20:04:02 1.4
+++ MessageResources.java 2000/12/15 03:08:10 1.5
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/MessageResources.java,v 1.4 2000/08/01 20:04:02 craigmcc Exp $
- * $Revision: 1.4 $
- * $Date: 2000/08/01 20:04:02 $
+ * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/MessageResources.java,v 1.5 2000/12/15 03:08:10 craigmcc Exp $
+ * $Revision: 1.5 $
+ * $Date: 2000/12/15 03:08:10 $
*
* ====================================================================
*
@@ -63,169 +63,130 @@
package org.apache.struts.util;
+import java.io.PrintWriter;
+import java.io.Serializable;
import java.text.MessageFormat;
-import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.HashMap;
import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
/**
- * General purpose utility module that wraps the named resource bundle
- * passed to our constructor and produces messages from it, with parametric
- * replacement of MessageFormat parameters. Convenience methods allow
- * retrieval of messages for either the default Locale or a specified Locale.
+ * General purpose abstract class that describes an API for retrieving
+ * Locale-sensitive messages from underlying resource locations of an
+ * unspecified design, and optionally utilizing the <code>MessageFormat</code>
+ * class to produce internationalized messages with parametric replacement.
+ * <p>
+ * Calls to <code>getMessage()</code> variants without a <code>Locale</code>
+ * argument are presumed to be requesting a message string in the default
+ * <code>Locale</code> for this JVM.
+ * <p>
+ * Calls to <code>getMessage()</code> with an unknown key, or an unknown
+ * <code>Locale</code> will return <code>null</code> if the
+ * <code>returnNull</code> property is set to <code>true</code>. Otherwise,
+ * a suitable error message will be returned instead.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Classes that extend this class
+ * must be Serializable so that instances may be used in distributable
+ * application server environments.
*
* @author Craig R. McClanahan
- * @version $Revision: 1.4 $ $Date: 2000/08/01 20:04:02 $
+ * @version $Revision: 1.5 $ $Date: 2000/12/15 03:08:10 $
*/
-public final class MessageResources {
+public abstract class MessageResources implements Serializable {
- // ----------------------------------------------------------- Constructors
+ // ------------------------------------------------------------- Properties
/**
- * Construct a new resources object that wraps the named ResourceBundles.
- *
- * @param base Base name of the ResourceBundles to be wrapped
- *
- * @exception MissingResourceException if the specified bundle cannot
- * be loaded
+ * The configuration parameter used to initialize this MessageResources.
*/
- public MessageResources(String base) throws MissingResourceException {
-
- super();
- this.base = base;
- this.bundle = ResourceBundle.getBundle(base);
+ protected String config = null;
+ public String getConfig() {
+ return (this.config);
}
- // ----------------------------------------------------- Instance Variables
-
-
- /**
- * The base name of resource bundles used for resolving requests for
- * messages.
- */
- private String base = null;
-
-
/**
- * The resource bundle to be used for resolving requests for messages
- * when no Locale is specified (i.e. the bundle that will be used for
- * the default Locale).
+ * The default Locale for our environment.
*/
- private ResourceBundle bundle = null;
+ protected Locale defaultLocale = Locale.getDefault();
/**
- * The set of resource bundles from which we access resources, keyed by
- * the key computed in <code>getLocaleKey()</code>.
+ * The <code>MessageResourcesFactory</code> that created this instance.
*/
- private Hashtable bundles = new Hashtable();
+ protected MessageResourcesFactory factory = null;
-
- /**
- * The default Locale for our installation.
- */
- private static final Locale defaultLocale = Locale.getDefault();
+ public MessageResourcesFactory getFactory() {
+ return (this.factory);
+ }
/**
- * The set of previously created message format objects, keyed by
- * the key computed in <code>getResourceKey()</code>.
+ * The set of previously created MessageFormat objects, keyed by the
+ * key computed in <code>messageKey()</code>.
*/
- private Hashtable formats = new Hashtable();
+ private HashMap formats = new HashMap();
/**
- * Should we return <code>null</code> for message keys that are not
- * found (instead of an error code that includes the offending key)?
+ * Should we return <code>null</code> instead of an error message string
+ * if an unknown Locale or key is requested?
*/
- private boolean returnNull = true;
-
+ protected boolean returnNull = false;
- // ------------------------------------------------------------- Properties
-
-
- /**
- * Return the "return null" property.
- */
public boolean getReturnNull() {
-
- return (this.returnNull);
-
+ return (this.returnNull);
}
-
- /**
- * Set the "return null" property.
- *
- * @param returnNull The new "return null" property
- */
public void setReturnNull(boolean returnNull) {
-
- this.returnNull = returnNull;
-
+ this.returnNull = returnNull;
}
-
- // --------------------------------------------------------- Public Methods
+ // ----------------------------------------------------------- Constructors
/**
- * Return the resource bundle that will be used to resolve message
- * requests for the default Locale.
+ * Construct a new MessageResources according to the specified parameters.
*
- * @exception MissingResourceException if a suitable bundle cannot
- * be located
+ * @param factory The MessageResourcesFactory that created us
+ * @param config The configuration parameter for this MessageResources
*/
- public ResourceBundle getBundle() throws MissingResourceException {
+ public MessageResources(MessageResourcesFactory factory, String config) {
- return (getBundle(null));
+ this(factory, config, false);
}
/**
- * Return the resource bundle that will be used to resolve message
- * requests for the specified Locale, if there is one. Otherwise,
- * return <code>null</code>
- *
- * @param locale The locale used to select a resource bundle
+ * Construct a new MessageResources according to the specified parameters.
*
- * @exception MissingResourceException if a suitable bundle cannot
- * be located
+ * @param factory The MessageResourcesFactory that created us
+ * @param config The configuration parameter for this MessageResources
+ * @param returnNull The returnNull property we should initialize with
*/
- public ResourceBundle getBundle(Locale locale)
- throws MissingResourceException {
-
- if (locale == null)
- return (bundle);
- String localeKey = getLocaleKey(locale);
+ public MessageResources(MessageResourcesFactory factory, String config,
+ boolean returnNull) {
- ResourceBundle bundle = null;
- synchronized (bundles) {
- bundle = (ResourceBundle) bundles.get(localeKey);
- if (bundle == null) {
- bundle = ResourceBundle.getBundle(base, locale);
- bundles.put(localeKey, bundle);
- }
- }
- return (bundle);
+ super();
+ this.factory = factory;
+ this.config = config;
+ this.returnNull = returnNull;
}
+ // --------------------------------------------------------- Public Methods
+
+
+
/**
* Returns a text message for the specified key, for the default Locale.
- * A null string result will be returned by this method if no relevant
- * message resource is found.
*
* @param key The message key to look up
*/
@@ -238,8 +199,7 @@
/**
* Returns a text message after parametric replacement of the specified
- * parameter placeholders. A null string result will be returned by
- * this method if no resource bundle has been configured.
+ * parameter placeholders.
*
* @param key The message key to look up
* @param args An array of replacement parameters for placeholders
@@ -253,13 +213,12 @@
/**
* Returns a text message after parametric replacement of the specified
- * parameter placeholders. A null string result will never be returned
- * by this method.
+ * parameter placeholders.
*
* @param key The message key to look up
* @param arg0 The replacement for placeholder {0} in the message
*/
- public String getMessage(String key, String arg0) {
+ public String getMessage(String key, Object arg0) {
return (getMessage((Locale) null, key, arg0));
@@ -268,14 +227,13 @@
/**
* Returns a text message after parametric replacement of the specified
- * parameter placeholders. A null string result will never be returned
- * by this method.
+ * parameter placeholders.
*
* @param key The message key to look up
* @param arg0 The replacement for placeholder {0} in the message
* @param arg1 The replacement for placeholder {1} in the message
*/
- public String getMessage(String key, String arg0, String arg1) {
+ public String getMessage(String key, Object arg0, Object arg1) {
return (getMessage((Locale) null, key, arg0, arg1));
@@ -284,16 +242,15 @@
/**
* Returns a text message after parametric replacement of the specified
- * parameter placeholders. A null string result will never be returned
- * by this method.
+ * parameter placeholders.
*
* @param key The message key to look up
* @param arg0 The replacement for placeholder {0} in the message
* @param arg1 The replacement for placeholder {1} in the message
* @param arg2 The replacement for placeholder {2} in the message
*/
- public String getMessage(String key, String arg0, String arg1,
- String arg2) {
+ public String getMessage(String key, Object arg0, Object arg1,
+ Object arg2) {
return (getMessage((Locale) null, key, arg0, arg1, arg2));
@@ -302,8 +259,7 @@
/**
* Returns a text message after parametric replacement of the specified
- * parameter placeholders. A null string result will never be returned
- * by this method.
+ * parameter placeholders.
*
* @param key The message key to look up
* @param arg0 The replacement for placeholder {0} in the message
@@ -311,8 +267,8 @@
* @param arg2 The replacement for placeholder {2} in the message
* @param arg3 The replacement for placeholder {3} in the message
*/
- public String getMessage(String key, String arg0, String arg1,
- String arg2, String arg3) {
+ public String getMessage(String key, Object arg0, Object arg1,
+ Object arg2, Object arg3) {
return (getMessage((Locale) null, key, arg0, arg1, arg2, arg3));
@@ -322,20 +278,19 @@
/**
* Returns a text message for the specified key, for the default Locale.
* A null string result will be returned by this method if no relevant
- * message resource is found.
+ * message resource is found for this key or Locale, if the
+ * <code>returnNull</code> property is set. Otherwise, an appropriate
+ * error message will be returned.
+ * <p>
+ * This method must be implemented by a concrete subclass.
*
* @param locale The requested message Locale, or <code>null</code>
* for the system default Locale
* @param key The message key to look up
*/
- public String getMessage(Locale locale, String key) {
+ public abstract String getMessage(Locale locale, String key);
- Object args[] = new Object[0];
- return (getMessage(locale, key, args));
- }
-
-
/**
* Returns a text message after parametric replacement of the specified
* parameter placeholders. A null string result will be returned by
@@ -349,20 +304,22 @@
public String getMessage(Locale locale, String key, Object args[]) {
// Cache MessageFormat instances as they are accessed
+ if (locale == null)
+ locale = defaultLocale;
MessageFormat format = null;
- String messageKey = getResourceKey(locale, key);
+ String formatKey = messageKey(locale, key);
synchronized (formats) {
- format = (MessageFormat) formats.get(messageKey);
+ format = (MessageFormat) formats.get(formatKey);
if (format == null) {
- String formatString = (String) getResource(locale, key);
+ String formatString = getMessage(locale, key);
if (formatString == null) {
if (returnNull)
return (null);
else
- return ("???" + key + "???");
+ return ("???" + formatKey + "???");
}
format = new MessageFormat(formatString);
- formats.put(messageKey, format);
+ formats.put(formatKey, format);
}
}
@@ -381,7 +338,7 @@
* @param key The message key to look up
* @param arg0 The replacement for placeholder {0} in the message
*/
- public String getMessage(Locale locale, String key, String arg0) {
+ public String getMessage(Locale locale, String key, Object arg0) {
Object args[] = new Object[1];
args[0] = arg0;
@@ -402,7 +359,7 @@
* @param arg1 The replacement for placeholder {1} in the message
*/
public String getMessage(Locale locale,
- String key, String arg0, String arg1) {
+ String key, Object arg0, Object arg1) {
Object args[] = new Object[2];
args[0] = arg0;
@@ -425,8 +382,8 @@
* @param arg2 The replacement for placeholder {2} in the message
*/
public String getMessage(Locale locale,
- String key, String arg0, String arg1,
- String arg2) {
+ String key, Object arg0, Object arg1,
+ Object arg2) {
Object args[] = new Object[3];
args[0] = arg0;
@@ -451,8 +408,8 @@
* @param arg3 The replacement for placeholder {3} in the message
*/
public String getMessage(Locale locale,
- String key, String arg0, String arg1,
- String arg2, String arg3) {
+ String key, Object arg0, Object arg1,
+ Object arg2, Object arg3) {
Object args[] = new Object[4];
args[0] = arg0;
@@ -464,121 +421,115 @@
}
+ // ------------------------------------------------------ Protected Methods
+
+
/**
- * Returns a resource for the specified message key, or <code>null</code>
- * if no corresponding resource can be found, for the default Locale.
+ * Compute and return a key to be used in caching information by a Locale.
+ * <strong>NOTE</strong> - The locale key for the default Locale in our
+ * environment is a zero length String.
*
- * @param key The resource key to look up
+ * @param locale The locale for which a key is desired
*/
- public Object getResource(String key) {
+ protected String localeKey(Locale locale) {
- return (getResource((Locale) null, key));
+ if (locale == null)
+ return ("");
+ else if (locale.equals(defaultLocale))
+ return ("");
+ else
+ return (locale.toString());
}
/**
- * Returns a resource for the specified message key, or <code>null</code>
- * if no corresponding resource can be found, for the specified Locale.
+ * Compute and return a key to be used in caching information
+ * by Locale and message key.
*
- * @param locale The requested message Locale, or <code>null</code>
- * for the system default Locale
- * @param key The resource key to look up
+ * @param locale The Locale for which this format key is calculated
+ * @param key The message key for which this format key is calculated
*/
- public Object getResource(Locale locale, String key) {
+ protected String messageKey(Locale locale, String key) {
- // Look up the resource bundle we will use
- ResourceBundle bundle = null;
- try {
- bundle = getBundle(locale);
- } catch (Exception e) {
- return (null);
- }
-
- // Look up the resource itself in this resource bundle
- Object result = null;
- try {
- result = bundle.getString(key);
- } catch (MissingResourceException e) {
- return (null);
- }
- return (result);
+ return (localeKey(locale) + "." + key);
}
- // -------------------------------------------------------- Private Methods
-
-
/**
- * Returns the key under which resources for a particular Locale may be
- * uniquely accessed.
+ * Compute and return a key to be used in caching information
+ * by locale key and message key.
*
- * @param locale The locale for which a key is to be computed, or
- * <code>null</code> for the system default Locale
+ * @param localeKey The locale key for which this cache key is calculated
+ * @param key The message key for which this cache key is calculated
*/
- private String getLocaleKey(Locale locale) {
+ protected String messageKey(String localeKey, String key) {
- if (locale == null)
- locale = defaultLocale;
- StringBuffer sb = new StringBuffer();
- sb.append(locale.getCountry());
- sb.append(".");
- sb.append(locale.getLanguage());
- sb.append(".");
- String variant = locale.getVariant();
- if (variant != null) {
- sb.append(variant);
- sb.append(".");
- }
- return (sb.toString());
+ return (localeKey + "." + key);
}
+ // --------------------------------------------------------- Static Methods
+
+
/**
- * Returns the key under which a message format for a particular message,
- * from the resource bundle for a particular locale, may be uniquely
- * accessed.
- *
- * @param locale Locale for which this message key is computed
- * @param id Message identifier for which this message key is computed
+ * The default MessageResourcesFactory used to create MessageResources
+ * instances.
*/
- private String getResourceKey(Locale locale, String id) {
+ protected static MessageResourcesFactory defaultFactory = null;
- return (getLocaleKey(locale) + "." + id);
- }
+ /**
+ * Create and return an instance of <code>MessageResources</code> for the
+ * created by the default <code>MessageResourcesFactory</code>.
+ *
+ * @param config Configuration parameter for this message bundle.
+ */
+ public synchronized static MessageResources
+ getMessageResources(String config) {
+ if (defaultFactory == null)
+ defaultFactory = MessageResourcesFactory.createFactory();
+ return defaultFactory.createResources(config);
- // --------------------------------------------------------- Static Methods
+ }
/**
- * The MessageResources instances that have been created so far,
- * keyed by base name.
+ * Log a message to the Writer that has been configured for our use.
+ *
+ * @param message The message to be logged
*/
- private static Hashtable cache = new Hashtable();
+ public void log(String message) {
+ PrintWriter writer = factory.getWriter();
+ if (writer != null) {
+ writer.print("MessageResources: ");
+ writer.println(message);
+ writer.flush();
+ }
+ }
+
+
/**
- * Return an instance of MessageResources for the specified base name.
+ * Log a message and exception to the Writer that has been configured
+ * for our use.
*
- * @param base Base name of the ResourceBundles to be wrapped
- *
- * @exception MissingResourcesException if no default resources
- * can be loaded
+ * @param message The message to be logged
+ * @param throwable The exception to be logged
*/
- public synchronized static MessageResources
- getMessageResources(String base) throws MissingResourceException {
+ public void log(String message, Throwable throwable) {
- MessageResources messageResources =
- (MessageResources) cache.get(base);
- if (messageResources != null)
- return (messageResources);
- messageResources = new MessageResources(base);
- cache.put(base, messageResources);
- return (messageResources);
+ PrintWriter writer = factory.getWriter();
+ if (writer != null) {
+ writer.print("MessageResources: ");
+ writer.println(message);
+ throwable.printStackTrace(writer);
+ writer.flush();
+ }
}
1.1 jakarta-struts/src/share/org/apache/struts/util/MessageResourcesFactory.java
Index: MessageResourcesFactory.java
===================================================================
/*
* $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/MessageResourcesFactory.java,v 1.1 2000/12/15 03:08:11 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/12/15 03:08:11 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.struts.util;
import java.io.PrintWriter;
/**
* Factory for <code>MessageResources</code> instances. The general usage
* pattern for this class is:
* <ul>
* <li>Call <code>MessageResourcesFactory().createFactory()</code> to retrieve
* a <code>MessageResourcesFactory</code> instance.</li>
* <li>Set properties as required to configure this factory instance to create
* <code>MessageResources</code> instances with desired
* characteristics.</li>
* <li>Call the <code>createResources()</code> method of the factory to
* retrieve a newly instantiated <code>MessageResources</code>
* instance.</li>
* </ul>
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/12/15 03:08:11 $
*/
public abstract class MessageResourcesFactory {
// ---------------------------------------------------- Instance Properties
/**
* The "return null" property value to which newly created
* MessageResourcess should be initialized.
*/
protected boolean returnNull = true;
public boolean getReturnNull() {
return (this.returnNull);
}
public void setReturnNull(boolean returnNull) {
this.returnNull = returnNull;
}
/**
* The PrintWriter to which we can log debugging and error information,
* if any.
*/
protected PrintWriter writer = null;
public PrintWriter getWriter() {
return (this.writer);
}
public void setWriter(PrintWriter writer) {
this.writer = writer;
}
// --------------------------------------------------------- Public Methods
/**
* Create and return a newly instansiated <code>MessageResources</code>.
* This method must be implemented by concrete subclasses.
*
* @param config Configuration parameter(s) for the requested bundle
*/
public abstract MessageResources createResources(String config);
// ------------------------------------------------------ Static Properties
/**
* The Java class to be used for
* <code>MessageResourcesFactory</code> instances.
*/
protected static Class clazz = null;
/**
* The fully qualified class name to be used for
* <code>MessageResourcesFactory</code> instances.
*/
protected static String factoryClass =
"org.apache.struts.util.PropertyMessageResourcesFactory";
public static String getFactoryClass() {
return (MessageResourcesFactory.factoryClass);
}
public static void setFactoryClass(String factoryClass) {
MessageResourcesFactory.factoryClass = factoryClass;
MessageResourcesFactory.clazz = null;
}
/**
* The PrintWriter to which we can log error and debugging information,
* if any.
*/
protected static PrintWriter defaultWriter = null;
public static PrintWriter getDefaultWriter() {
return (MessageResourcesFactory.defaultWriter);
}
public static void setDefaultWriter(PrintWriter writer) {
MessageResourcesFactory.defaultWriter = writer;
}
// --------------------------------------------------------- Static Methods
/**
* Create and return a <code>MessageResourcesFactory</code> instance of the
* appropriate class, which can be used to create customized
* <code>MessageResources</code> instances. If no such factory can be
* created, return <code>null</code> instead.
*/
public static MessageResourcesFactory createFactory() {
// Construct a new instance of the specified factory class
try {
if (clazz == null)
clazz = Class.forName(factoryClass);
MessageResourcesFactory factory =
(MessageResourcesFactory) clazz.newInstance();
factory.setWriter(defaultWriter);
return (factory);
} catch (Throwable t) {
if (defaultWriter != null) {
defaultWriter.println("MessageResourcesFactory.createFactory");
t.printStackTrace(defaultWriter);
defaultWriter.flush();
}
return (null);
}
}
}
1.1 jakarta-struts/src/share/org/apache/struts/util/PropertyMessageResources.java
Index: PropertyMessageResources.java
===================================================================
/*
* $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyMessageResources.java,v 1.1 2000/12/15 03:08:11 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/12/15 03:08:11 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.struts.util;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
/**
* Concrete subclass of <code>MessageResources</code> that reads message keys
* and corresponding strings from named property resources in the same manner
* that <code>java.util.PropertyResourceBundle</code> does. The
* <code>base</code> property defines the base property resource name, and
* must be specified.
* <p>
* <strong>IMPLEMENTATION NOTE</strong> - This class trades memory for
* speed by caching all messages located via generalizing the Locale under
* the original locale as well.
* This results in specific messages being stored in the message cache
* more than once, but improves response time on subsequent requests for
* the same locale + key combination.
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/12/15 03:08:11 $
*/
public class PropertyMessageResources extends MessageResources {
// ----------------------------------------------------------- Constructors
/**
* Construct a new PropertyMessageResources according to the
* specified parameters.
*
* @param factory The MessageResourcesFactory that created us
* @param config The configuration parameter for this MessageResources
*/
public PropertyMessageResources(MessageResourcesFactory factory,
String config) {
super(factory, config);
}
/**
* Construct a new PropertyMessageResources according to the
* specified parameters.
*
* @param factory The MessageResourcesFactory that created us
* @param config The configuration parameter for this MessageResources
* @param returnNull The returnNull property we should initialize with
*/
public PropertyMessageResources(MessageResourcesFactory factory,
String config, boolean returnNull) {
super(factory, config, returnNull);
}
// ------------------------------------------------------------- Properties
/**
* The set of locale keys for which we have already loaded messages, keyed
* by the value calculated in <code>localeKey()</code>.
*/
protected HashMap locales = new HashMap();
/**
* The cache of messages we have accumulated over time, keyed by the
* value calculated in <code>messageKey()</code>.
*/
protected HashMap messages = new HashMap();
// --------------------------------------------------------- Public Methods
/**
* Returns a text message for the specified key, for the default Locale.
* A null string result will be returned by this method if no relevant
* message resource is found for this key or Locale, if the
* <code>returnNull</code> property is set. Otherwise, an appropriate
* error message will be returned.
* <p>
* This method must be implemented by a concrete subclass.
*
* @param locale The requested message Locale, or <code>null</code>
* for the system default Locale
* @param key The message key to look up
*/
public String getMessage(Locale locale, String key) {
// Initialize variables we will require
String localeKey = localeKey(locale);
String originalKey = messageKey(localeKey, key);
String messageKey = null;
String message = null;
int underscore = 0;
boolean addIt = false; // Add if not found under the original key
// Loop from specific to general Locales looking for this message
while (true) {
// Load this Locale's messages if we have not done so yet
loadLocale(localeKey);
// Check if we have this key for the current locale key
messageKey = messageKey(localeKey, key);
synchronized (messages) {
message = (String) messages.get(messageKey);
if (message != null) {
if (addIt)
messages.put(originalKey, message);
return (message);
}
}
// Strip trailing modifiers to try a more general locale key
addIt = true;
underscore = localeKey.lastIndexOf("_");
if (underscore < 0)
break;
localeKey = localeKey.substring(0, underscore);
}
// As a last resort, try the default Locale
localeKey = localeKey(defaultLocale);
messageKey = messageKey(localeKey, key);
loadLocale(localeKey);
synchronized (messages) {
message = (String) messages.get(messageKey);
if (message != null) {
if (addIt)
messages.put(originalKey, message);
return (message);
}
}
// Return an appropriate error indication
if (returnNull)
return (null);
else
return ("???" + messageKey(locale, key) + "???");
}
// ------------------------------------------------------ Protected Methods
/**
* Load the messages associated with the specified Locale key. For this
* implementation, the <code>config</code> property should contain a fully
* qualified package and resource name, separated by periods, of a series
* of property resources to be loaded from the class loader that created
* this PropertyMessageResources instance. This is exactly the same name
* format you would use when utilizing the
* <code>java.util.PropertyResourceBundle</code> class.
*
* @param localeKey Locale key for the messages to be retrieved
*/
protected void loadLocale(String localeKey) {
// Have we already attempted to load messages for this locale?
synchronized (locales) {
if (locales.get(localeKey) != null)
return;
locales.put(localeKey, localeKey);
}
// Set up to load the property resource for this locale key, if we can
String name = config.replace('.', '/');
if (localeKey.length() > 0)
name += "_" + localeKey;
name += ".properties";
InputStream is = null;
Properties props = new Properties();
// Load the specified property resource
try {
is = this.getClass().getClassLoader().getResourceAsStream(name);
if (is != null) {
props.load(is);
is.close();
}
} catch (Throwable t) {
if (is != null) {
try {
is.close();
} catch (Throwable u) {
;
}
}
}
// Copy the corresponding values into our cache
if (props.size() < 1)
return;
synchronized (messages) {
Enumeration names = props.keys();
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
messages.put(messageKey(localeKey, key),
props.getProperty(key));
}
}
}
}
1.1 jakarta-struts/src/share/org/apache/struts/util/PropertyMessageResourcesFactory.java
Index: PropertyMessageResourcesFactory.java
===================================================================
/*
* $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyMessageResourcesFactory.java,v 1.1 2000/12/15 03:08:11 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/12/15 03:08:11 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.struts.util;
/**
* Factory for <code>PropertyMessageResources</code> instances. The
* configuration paramter for such instances is the base Java package
* name of the resources entries from which our keys and values will be
* loaded.
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/12/15 03:08:11 $
*/
public class PropertyMessageResourcesFactory extends MessageResourcesFactory {
// --------------------------------------------------------- Public Methods
/**
* Create and return a newly instansiated <code>MessageResources</code>.
* This method must be implemented by concrete subclasses.
*
* @param config Configuration parameter(s) for the requested bundle
*/
public MessageResources createResources(String config) {
return new PropertyMessageResources(this, config, this.returnNull);
}
}
1.1 jakarta-struts/src/share/org/apache/struts/util/ServletContextWriter.java
Index: ServletContextWriter.java
===================================================================
/*
* $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/ServletContextWriter.java,v 1.1 2000/12/15 03:08:11 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/12/15 03:08:11 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.struts.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletContext;
/**
* A PrintWriter implementation that uses the logging facilities of a
* <code>javax.servlet.ServletContext</code> to output its results. Output
* will be buffered until a newline character is output, <code>flush()</code>
* is called, or until one of the <code>println()</code> methods is called.
* Along the way, carriage return characters are skipped.
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/12/15 03:08:11 $
*/
public class ServletContextWriter extends PrintWriter {
// ----------------------------------------------------------- Constructors
/**
* Construct a ServletContextWriter associated with the specified
* ServletContext instance.
*
* @param context The associated servlet context
*/
public ServletContextWriter(ServletContext context) {
super(new StringWriter());
this.context = context;
}
// ------------------------------------------------------------- Properties
/**
* The buffer into which we accumulate lines to be logged.
*/
protected StringBuffer buffer = new StringBuffer();
/**
* The servlet context with which we are associated.
*/
protected ServletContext context = null;
/**
* The error state for this stream.
*/
protected boolean error = false;
// --------------------------------------------------------- Public Methods
/**
* Flush the stream and check for its error state. <strong>IMPLEMENTATION
* NOTE</strong> - our associated servlet context gives no indication of
* problems with logging, so the only way this method will return
* <code>true</code> is if <code>setError()</code> is called.
*/
public boolean checkError() {
flush();
return (error);
}
/**
* Close the stream.
*/
public void close() {
flush();
}
/**
* Flush the stream.
*/
public void flush() {
if (buffer.length() > 0) {
context.log(buffer.toString());
buffer.setLength(0);
}
}
/**
* Print a boolean value.
*
* @param b The value to be printed
*/
public void print(boolean b) {
write(String.valueOf(b));
}
/**
* Print a character value.
*
* @param c The value to be printed
*/
public void print(char c) {
write(c);
}
/**
* Print a character array.
*
* @param c The character array to be printed
*/
public void print(char c[]) {
for (int i = 0; i < c.length; i++)
write(c[i]);
}
/**
* Print a double value.
*
* @param d The value to be printed
*/
public void print(double d) {
write(String.valueOf(d));
}
/**
* Print a float value.
*
* @param f The value to be printed
*/
public void print(float f) {
write(String.valueOf(f));
}
/**
* Print an integer value.
*
* @param i The value to be printed
*/
public void print(int i) {
write(String.valueOf(i));
}
/**
* Print a long value.
*
* @param l The value to be printed
*/
public void print(long l) {
write(String.valueOf(l));
}
/**
* Print an object.
*
* @param o The value to be printed
*/
public void print(Object o) {
write(o.toString());
}
/**
* Print a String value.
*
* @param s The value to be printed
*/
public void print(String s) {
int len = s.length();
for (int i = 0; i < len; i++)
write(s.charAt(i));
}
/**
* Terminate the current line and flush the buffer.
*/
public void println() {
flush();
}
/**
* Print a boolean value and terminate the line.
*
* @param b The value to be printed
*/
public void println(boolean b) {
println(String.valueOf(b));
}
/**
* Print a character value and terminate the line.
*
* @param c The value to be printed
*/
public void println(char c) {
write(c);
println();
}
/**
* Print a character array and terminate the line.
*
* @param c The character array to be printed
*/
public void println(char c[]) {
for (int i = 0; i < c.length; i++)
print(c[i]);
println();
}
/**
* Print a double value and terminate the line.
*
* @param d The value to be printed
*/
public void println(double d) {
println(String.valueOf(d));
}
/**
* Print a float value and terminate the line.
*
* @param f The value to be printed
*/
public void println(float f) {
println(String.valueOf(f));
}
/**
* Print an integer value and terminate the line.
*
* @param i The value to be printed
*/
public void println(int i) {
println(String.valueOf(i));
}
/**
* Print a long value and terminate the line.
*
* @param l The value to be printed
*/
public void println(long l) {
println(String.valueOf(l));
}
/**
* Print an object and terminate the line.
*
* @param o The value to be printed
*/
public void println(Object o) {
println(o.toString());
}
/**
* Print a String value and terminate the line.
*
* @param s The value to be printed
*/
public void println(String s) {
int len = s.length();
for (int i = 0; i < len; i++)
print(s.charAt(i));
println();
}
/**
* Set the error state for this stream.
*/
public void setError() {
this.error = true;
}
/**
* Write a single character to this stream.
*
* @param c The character to be written
*/
public void write(char c) {
if (c == '\n')
flush();
else if (c != '\r')
buffer.append(c);
}
/**
* Write a single character to this stream.
*
* @param c The character to be written
*/
public void write(int c) {
write((char) c);
}
/**
* Write an array of charaters to this stream.
*
* @param buf The character array to be written
*/
public void write(char buf[]) {
for (int i = 0; i < buf.length; i++)
write(buf[i]);
}
/**
* Write the specified subset of an array of characters to this stream.
*
* @param buf The character array from which to write
* @param off The zero-relative starting offset to write
* @param len The number of characters to write
*/
public void write(char buf[], int off, int len) {
for (int i = off; i < len; i++)
write(buf[i]);
}
/**
* Write a String to this stream.
*
* @param s The string to be written
*/
public void write(String s) {
int len = s.length();
for (int i = 0; i < len; i++)
write(s.charAt(i));
}
/**
* Write the specified portion of a String to this stream.
*
* @param s The String from which to write
* @param off The zero-relative starting offset to write
* @param len The number of characters to write
*/
public void write(String s, int off, int len) {
for (int i = off; i < len; i++)
write(s.charAt(i));
}
}