The Apache Commons Resources Package.
The Apache 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.