The Jakarta Commons Resources Package.
The Jakarta Commons Resources Package provides a general
framework for retrieving localized application resources (based on either an
explicitly specified java.util.Locale instance, or the system
default Locale). In addition, since a very common use case for
localized resources is to prepare prompt and error messages for a user
interface, convenient mechanisms are provided to retrieve a localized message
string (suitable for use with the java.text.MessageFormat class)
plus substitution parameters, and prepare a localized and customized message
string.
The Commons Resources package is organized around the following fundamental
interfaces and classes (in the org.apache.commons.resources
package):
resource key, and optional
java.util.Locale and java.util.TimeZone
parameters.Resources instances with a specified logical name,
configured by a parameter String whose meaning is defined by the
particular ResourcesFactory implementation you are
using.Resources instance that provides
message formatting services (including parameter substitution), as
long as the resources are legal arguments to the format()
method of the java.text.MessageFormat class.The following standard Resources implementations, with
corresponding ResourcesFactory implementations, are
included (in the org.apache.commons.resources.impl package):
java.util.ResourceBundle), and
a .properties extension.ResourceBundle implementation classes (or properties
files) loaded from the classpath of the application.java.util.ResourceBundle), and
a .xml extension.PropertyResources where the configuration parameter is the
base name that will be passed to
ServletContext.getResource() calls.PropertyResources where the configuration parameter is the
base name that will be passed to
ServletContext.getResource() calls.Applications utilizing the commons-resources package will have
the following mandatory and conditional dependencies on other packages,
as follows:
XMLResources
or WebappXMLResources.XMLResources
or WebappXMLResources.XMLResources
or WebappXMLResources.ResourcesFactoryFinder.Resources implementations.WebappPropertyResources
or WebappXMLResources.XMLResources.Using the Commons Resources package to retrieve localized resources is a simple three-step process:
ResourcesFactory instance for the type
of Resources implementation you wish to use.Resources instance of the desired type
by calling the getResources() method of
the ResourcesFactory acquired in the previous step.Resources instance,
in the desired format, by specifying a resource identifier, an
optional Locale, and an optional TimeZone
parameter to one of the content retrieval methods.These steps are illustrated in more detail below.
The simplest way to acquire a ResourcesFactory instance is to
simply construct a new one, since ResourcesFactory implementations
are required to provide a public zeo-arguments constructor:
ResourcesFactory factory = new XMLResourcesFactory();
However, doing this hard codes into your application the knowledge of which
particular ResourcesFactory implementation will be used. It is
also possible to defer this decision until runtime, where a check for any
available implementation available on the class path can be performed:
ResourcesFactory factory =
ResourcesFactoryFinder.getResourcesFactory();
Using this technique allows you to select a particular implementation at
runtime based on the rules defined by the
commons-discovery
package, through the use of either a system property or including a JAR file
(with a ResourcesFactory implementation included) that includes
a META-INF/services/org.apache.commons.resources.ResourcesFactory
file that specifies the actual implementation class to be used.
Once you have a ResourcesFactory instance, use the
getResources() method to retrieve a Resources
instance for your use. You will specify either one or two parameters to
this method:
Resources
instance you wish to utilize. Most ResourcesFactory
implementations (including all of the standard ones) will cache
previously created Resources instance by name, so that
repeated requests for the same name will return the same instance.Resources implementation class
that is being utilized. For example, the configuration parameter for
an instance of XMLResources contains the base URL for the
family of XML documents that comprise the name/value mappings (one
XML document per Locale).
Resources resources = factory.getResources
("messages", "http://localhost/mymessages");
Now that you have a Resources instance available, you can
utilize its content retrieval methods to acquire a localized resource value
for the specified resource identifier. The actual content of the resource
value can be retrieved in different formats (byte array, input stream, object,
reader, or String), but the most common use of resources is for strings.
Locale locale =
... locale to use for localization ...;
String message =
resources.getString("invalid.login", locale, null);
The most common use for localized resources is to support
internationalization of prompts and messages when you create the user interface
for an application intended for use by an international audience. Beyond the
basic capability of looking up the localized strings (which is already
supported by the Resources implementations described above),
it would also be very useful to treat the retrieved message string as a
format argument to an instance of java.text.MessageFormat,
complete with substitution parameters. The Commons Resources package
includes a class
(Messages) that
supports these extra features.
A typical message resource will use substitution patterns to
identify where the replacement text should go. Consider a properties file
(for a PropertyResources or ResourceBundleResources
instance) with the following line:
invalid.value=The value you entered ({0}) is not valid
where the {0} will be replaced by the first of the replacement
values that you include. See the Javadocs for
java.text.MessageFormat for a description of all the possible
syntaxes that are supported.
You can use a Messages instance as a wrapper around any
Resources instance that you have previously acquired (decorator
pattern):
String input = ...; // Input value from user
Locale locale = ...; // User's locale
Resources resources = ...; // Desired resources
Messages messages = new Messages(resources);
String message =
messages.getMessage("invalid.value", locale, input);
which, if the input string has a value "ABC" will result in the following message value:
The value you entered (ABC) is not valid
In addition to user interfaces, a common requirement for internationalized
applications is to support the localization of log messages, and exception
descriptions, that are rendered by an application. To support these
requirements, the Messages class includes additional shortcut
features that make it easy to meet them. Consider the following class:
package com.mycompany.mypackage;
public class MyClass {
private static Messages messages =
Messages.getMessages("com.mycompany.mypackage.LocalStrings");
public class do() {
try {
...
} catch (Exception e) {
log.error(messages.getMessage("got.exception"), e);
}
}
}
The getMessages() method acquires an instance of
ResourceBundleResources for a resource bundle with the package
and name you specify (normally the
package containing this class) on the class path for your application.
Most people will find it convenient to specify the actual resources
with property files that are included in the JAR file (or directory)
that your application is running from. Thus, an application that
includes the above class might have the following files in its
JAR file (or application directory):
com/mycompany/mypackage/LocalStrings.properties -
Default resources (if not overridden by more specific ones)com/mycompany/mypackage/LocalStrings_en.properties -
Resources for English users.com/mycompany/mypackage/LocalStrings_en_US.properties -
Resources for English users in the United States.See the Javadocs for java.util.ResourceBundle and
java.util.PropertyResourceBundle for more information on the
mapping of property file names to locales.
It is straightforward to create your own custom implementations of
ResourcesFactory and Resources. The following
information describes the recommended approach.
First, create a new class that implements the ResourcesFactory
interface, or (recommended) subclasses the provided abstract base class
(
ResourcesFactoryBase). The provided base class implements the common
functionality of most ResourcesFactory implementations (such
as caching created Resources instances by logical name. It
only requires you to implement the createResources() method to
construct a Resources instance (given the specified name
and configuration parameter string). Be sure that your implementation
calls the init() method on the Resources instance
that is created before returning it.
Next, create a new class that implements Resources or
(recommended) subclasses one of the provided abstract base classes. You have
a choice of two abstract base classes to start from:
getObject(), which
must be implemented by the concrete subclass.Resources implementations
(including the standard PropertyResources and
XMLResources implementations) share a "family of related
files with a common base URL" design paradigm, and can also choose to
represent the name/value mappings for each locale as an instance of
java.util.Map. In addition, this class assumes that
resources for a particular Locale can be inherited from
more general locales, using the algorithms described in the Javadocs
for java.util.ResourceBundle.
The only method that must be implemented
by a concrete subclass is getLocaleMap(Locale), which will
be called only once per Locale.If you wish to utilize your custom implementation in an application
environment that uses the ResourcesFactoryFinder class to
discover the desired implementation at runtime, you should also package
your ResourcesFactory and Resources implementation
classes (plus any additional support classes that they need) into a JAR file
that includes a services identifier file named
META-INF/services/org.apache.commons.resources.ResourcesFactory
whose first line contains the fully qualified Java class name of your
ResourcesFactory implementation class. See the documentation
for the Commons
Discovery package for more information about automatic service
discovery.