Home

This Chapter
-Chapter 7: Internationalization
-New Supported Locales
-Locale Sensitive Services SPI
-Resource Bundle Enhancement
-ResourceBundle.Control
-Summary

Table of Contents
-Introduction
-Chapter 1: Core Libraries
-Chapter 2: Dynamic Compilation
-Chapter 3: Scripting
-Chapter 4: Networking
-Chapter 5: Swing Updates
-Chapter 6: Abstract Window Toolkit
-Chapter 7: Internationalization
-Chapter 8: Java Database Connectivity 4.0
-Chapter 9: XML Digital Signature API
-Chapter 10: Streaming API for XML
-Chapter 11: Java Architecture for XML Binding
-Chapter 12: Web Services
-Chapter 13: JavaBeans Activation Framework
-Chapter 14: User-Defined MXBeans
-Chapter 15: Concurrency Updates
-Appendix A: Enums
-Appendix B: Generics
-Appendix C: Annotations

Previous
Next

 

Locale Sensitive Services SPI

Most Java programmers must have used the java.text.DateFormat class, an abstract class for formatting and parsing dates. What is interesting is that you can format dates according to your locale of choice, by passing a Locale object to its getDateInstance, getTimeInstance, or getDateTimeInstance methods:

public static DateTime getDateInstance(int dateStyle,
        java.util.Locale locale)
public static DateTime getTimeInstance(int timeStyle,
        java.util.Locale locale)
public static DateTime getDateTimeInstance(int dateStyle,
        int timeStyle, java.util.Locale locale)

For example, to obtain a DateTime for the France locale, you call this method:

DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);

However, what if the JRE does not have a DateFormat for the locale you wish to use? With Mustang, this should not be a problem because it now has the Locale Sensitive Services SPI, where SPI stands for service provider interface. What it means is now you can write your own implementations for most locale sensitive classes in the java.text and java.util packages for locales that are not (yet) supported by the JRE. You create an implementation by subclassing corresponding the abstract provider class in the java.util.spi and java.text.spi packages. To be precise, with the new Java 6 feature, you can provide locale-sensitive implementations for the following entities.

A locale-specific implementation must return the list of all supported locales through its getAvailableLocales methods. The return value of this method will be added to the list returned by the getAvailableLocales method of the corresponding class, after the implementation is registered through the Java extension mechanism, which was introduced as a new feature in JDK 1.2. If you’re not familiar with the extension mechanism, read this tutorial at Sun’s Web site:

http://java.sun.com/docs/books/tutorial/ext/

The following example shows how to implement a new DateFormat provider for the Antarctica locale. Antarctica, as you may suspect, is a fictitious country whose people speak Antarctican English. A date and a date/time in Antarctica are written in this format:

year~month~date
year~month~date hour.minute.second

Notice that a tilde (~) is used to separate the year and the month as well as the month and the date. Therefore, the sixteenth day of April 2008 is written as 2008~4~16.

What a country!

To implement a DateFormat provider, you need to subclass the corresponding DateFormatProvider class from the java.text.spi package. Our class is given in Listing 7.2 and named DateFormatProviderImpl.

Listing 7.2: DateFormatProviderImpl class

package spi;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.spi.DateFormatProvider;
import java.util.Locale;

public class DateFormatProviderImpl extends DateFormatProvider {
    // Antarctica locale
    private Locale antarctica = new Locale("en", "AQ");

    public Locale[] getAvailableLocales() {
        return new Locale[] {antarctica};
    }

    // All styles return the same format: HH.mm.ss
    public DateFormat getTimeInstance(int style, Locale locale) {
        if (locale.equals(antarctica)) {
            return new SimpleDateFormat("HH.mm.ss");
        }
        return null;
    }

    // All styles return the same format: yyyy~MM~dd
    public DateFormat getDateInstance(int style, Locale locale) {
        if (locale.equals(antarctica)) {
            return new SimpleDateFormat("yyyy~MM~dd");
        }
        return null;
    }
    // All styles return the same format: yyyy~MM~dd HH.mm.ss
    public DateFormat getDateTimeInstance(int dateStyle,
            int timeStyle, Locale locale) {
        if (locale.equals(antarctica)) {
            return new SimpleDateFormat("yyyy~MM~dd HH.mm.ss");
        }
        return null;
    }
}

Now, to make spi.DateFormatProviderImpl usable, you need to ‘plug’ it into the JRE. You first need to create a file that describes the new class, build a directory structure that contains the class, and package it. Then, take the JAR file and copy it to the lib/ext directory under your JRE installation.

The descriptor for the DateFormatProviderImpl class must be named according to the fully-qualified name of the class that DateFormatProviderImpl extends, in this case java.text.sip.DateFormatProvider. This file is a simple text file containing the fully-qualified name of DateFormatProviderImpl. Listing 7.3 shows the content of the java.text.spi.DateFormatProvider file.

Listing 7.3: The descriptor file (java.text.spi.DateFormatProvider)

spi.DateFormatProviderImpl

The java.text.spi.DateFormatProvider file contains a single line.

Now, you need to package both the DateFormatProviderImpl.class and java.text.spi.DateFormatProvider files in a structure compliant with the Java Extension Mechanism. In our example, it would be like the one depicted in Figure 7.2.

Figure 7.2: The directory structure for creating a Java extension

The package directory is our working directory, it should not be part of the JAR file itself. There are two things that need to be under package:

To create a JAR file out of this directory structure, change directory to the package directory and type

jar -cf AntarcticaDateFormatProvider.jar *.*

An AntarcticaDateFormatProvider.jar file will be created in the package directory. Now, copy the jar file to lib/ext directory under your JRE. You can now use the provider you just implemented.

You can use the AntarcticaLocaleDemo class in Listing 7.3 to test your plug-in.

Listing 7.3: The AntarcticaLocaleDemo class

package spi;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class AntarcticaLocaleDemo {

    public static void main(String[] args) {
        // Display all available locales,
        // note there is a new locale named en_AQ
        System.out.println("Available locales:");
        Locale[] locales = Locale.getAvailableLocales();
        for (Locale locale : locales) {
            System.out.println(" xx " + locale);
        }
        System.out.println("");

        // Current time
        Date now = new Date();

        // Display using the default locale format
        DateFormat defaultFormat = DateFormat.getDateTimeInstance();
        String defaultString = defaultFormat.format(now);
        System.out.println("Default   : " + defaultString);

        // Display using the Antarctica locale format
        DateFormat antarcticaFormat =
                DateFormat.getDateTimeInstance(
                DateFormat.FULL, DateFormat.FULL,
                new Locale("en", "AQ"));

        String antarcticaString = antarcticaFormat.format(now);
        System.out.println("Antarctica: " + antarcticaString);
    }
}

If you run the AntarcticaLocaleDemo class, you will see the list of available locales, one of which is en_AQ. After the list comes the current date in two formats, your computer default format and one in Antarctica format. In my computer it looks like this:

Default   : Dec 4, 2006 10:52:19 PM
Antarctica: 2006~12~04 22.52.19

Previous
Next