The Apache Commons Resources Package.

[Overview] [Dependencies] [Using Resources] [Using Messages] [Implementing Resources]

Overview

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):

The following standard Resources implementations, with corresponding ResourcesFactory implementations, are included (in the org.apache.commons.resources.impl package):

Dependencies

Applications utilizing the commons-resources package will have the following mandatory and conditional dependencies on other packages, as follows:

Using Resources

Using the Commons Resources package to retrieve localized resources is a simple three-step process:

These steps are illustrated in more detail below.

Acquiring a ResourcesFactory Instance

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.

Acquiring a Resources Instance

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 resources = factory.getResources
      ("messages", "http://localhost/mymessages");
Calling a Content Retrieval Method

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);

Using Messages

Parameterized Message Strings

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
Shortcut for Application Classes

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):

See the Javadocs for java.util.ResourceBundle and java.util.PropertyResourceBundle for more information on the mapping of property file names to locales.

Implementing Resources

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:

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.