FileDocCategorySizeDatePackage
LocaleSupport.javaAPI DocGlassfish v2 API20984Sat May 05 19:17:14 BST 2007javax.servlet.jsp.jstl.fmt

LocaleSupport

public class LocaleSupport extends Object
Class which exposes the locale-determination logic for resource bundles through convenience methods.

This class may be useful to any tag handler implementation that needs to produce localized messages. For example, this might be useful for exception messages that are intended directly for user consumption on an error page.

author
Jan Luehe

Fields Summary
private static final String
UNDEFINED_KEY
private static final char
HYPHEN
private static final char
UNDERSCORE
private static final String
REQUEST_CHAR_SET
private static final Locale
EMPTY_LOCALE
Constructors Summary
Methods Summary
private static LocalizationContextfindMatch(javax.servlet.jsp.PageContext pageContext, java.lang.String basename)

	LocalizationContext locCtxt = null;
	
	// Determine locale from client's browser settings.
        
	for (Enumeration enum_ = getRequestLocales(
                            (HttpServletRequest)pageContext.getRequest());
	     enum_.hasMoreElements(); ) {
	    Locale pref = (Locale) enum_.nextElement();
	    ResourceBundle match = findMatch(basename, pref);
	    if (match != null) {
		locCtxt = new LocalizationContext(match, pref);
		break;
	    }
	}
        	
	return locCtxt;
    
private static java.util.ResourceBundlefindMatch(java.lang.String basename, java.util.Locale pref)

	ResourceBundle match = null;

	try {
	    ResourceBundle bundle =
		ResourceBundle.getBundle(basename, pref,
					 Thread.currentThread().getContextClassLoader());
	    Locale avail = bundle.getLocale();
	    if (pref.equals(avail)) {
		// Exact match
		match = bundle;
	    } else {
                /*
                 * We have to make sure that the match we got is for
                 * the specified locale. The way ResourceBundle.getBundle()
                 * works, if a match is not found with (1) the specified locale,
                 * it tries to match with (2) the current default locale as 
                 * returned by Locale.getDefault() or (3) the root resource 
                 * bundle (basename).
                 * We must ignore any match that could have worked with (2) or (3).
                 * So if an exact match is not found, we make the following extra
                 * tests:
                 *     - avail locale must be equal to preferred locale
                 *     - avail country must be empty or equal to preferred country
                 *       (the equality match might have failed on the variant)
		 */
                if (pref.getLanguage().equals(avail.getLanguage())
		    && ("".equals(avail.getCountry()) || pref.getCountry().equals(avail.getCountry()))) {
		    /*
		     * Language match.
		     * By making sure the available locale does not have a 
		     * country and matches the preferred locale's language, we
		     * rule out "matches" based on the container's default
		     * locale. For example, if the preferred locale is 
		     * "en-US", the container's default locale is "en-UK", and
		     * there is a resource bundle (with the requested base
		     * name) available for "en-UK", ResourceBundle.getBundle()
		     * will return it, but even though its language matches
		     * that of the preferred locale, we must ignore it,
		     * because matches based on the container's default locale
		     * are not portable across different containers with
		     * different default locales.
		     */
		    match = bundle;
		}
	    }
	} catch (MissingResourceException mre) {
	}

	return match;
    
private static java.util.LocalegetLocale(javax.servlet.jsp.PageContext pageContext, java.lang.String name)

	Locale loc = null;

	Object obj = Config.find(pageContext, name);
	if (obj != null) {
	    if (obj instanceof Locale) {
		loc = (Locale) obj;
	    } else {
		loc = parseLocale((String) obj);
	    }
	}

	return loc;
    
private static LocalizationContextgetLocalizationContext(javax.servlet.jsp.PageContext pc)
Gets the default I18N localization context.

param
pc Page in which to look up the default I18N localization context

	LocalizationContext locCtxt = null;

	Object obj = Config.find(pc, Config.FMT_LOCALIZATION_CONTEXT);
	if (obj == null) {
	    return null;
	}

	if (obj instanceof LocalizationContext) {
	    locCtxt = (LocalizationContext) obj;
	} else {
	    // localization context is a bundle basename
	    locCtxt = getLocalizationContext(pc, (String) obj);
	}

	return locCtxt;
    
private static LocalizationContextgetLocalizationContext(javax.servlet.jsp.PageContext pc, java.lang.String basename)
Gets the resource bundle with the given base name, whose locale is determined as follows: Check if a match exists between the ordered set of preferred locales and the available locales, for the given base name. The set of preferred locales consists of a single locale (if the javax.servlet.jsp.jstl.fmt.locale configuration setting is present) or is equal to the client's preferred locales determined from the client's browser settings.

If no match was found in the previous step, check if a match exists between the fallback locale (given by the javax.servlet.jsp.jstl.fmt.fallbackLocale configuration setting) and the available locales, for the given base name.

param
pageContext Page in which the resource bundle with the given base name is requested
param
basename Resource bundle base name
return
Localization context containing the resource bundle with the given base name and the locale that led to the resource bundle match, or the empty localization context if no resource bundle match was found

	LocalizationContext locCtxt = null;
	ResourceBundle bundle = null;

	if ((basename == null) || basename.equals("")) {
	    return new LocalizationContext();
	}

	// Try preferred locales
	Locale pref = getLocale(pc, Config.FMT_LOCALE);
	if (pref != null) {
	    // Preferred locale is application-based
	    bundle = findMatch(basename, pref);
	    if (bundle != null) {
		locCtxt = new LocalizationContext(bundle, pref);
	    }
	} else {
	    // Preferred locales are browser-based
	    locCtxt = findMatch(pc, basename);
	}
	
	if (locCtxt == null) {
	    // No match found with preferred locales, try using fallback locale
	    pref = getLocale(pc, Config.FMT_FALLBACK_LOCALE);
	    if (pref != null) {
		bundle = findMatch(basename, pref);
		if (bundle != null) {
		    locCtxt = new LocalizationContext(bundle, pref);
		}
	    }
	}

	if (locCtxt == null) {
	    // try using the root resource bundle with the given basename
	    try {
		bundle = ResourceBundle.getBundle(basename, EMPTY_LOCALE,
						  Thread.currentThread().getContextClassLoader());
		if (bundle != null) {
		    locCtxt = new LocalizationContext(bundle, null);
		}
	    } catch (MissingResourceException mre) {
		// do nothing
	    }
	}
		 
	if (locCtxt != null) {
	    // set response locale
	    if (locCtxt.getLocale() != null) {
		setResponseLocale(pc, locCtxt.getLocale());
	    }
	} else {
	    // create empty localization context
	    locCtxt = new LocalizationContext();
	}

	return locCtxt;
    
public static java.lang.StringgetLocalizedMessage(javax.servlet.jsp.PageContext pageContext, java.lang.String key)
Retrieves the localized message corresponding to the given key.

The given key is looked up in the resource bundle of the default I18N localization context, which is retrieved from the javax.servlet.jsp.jstl.fmt.localizationContext configuration setting.

If the configuration setting is empty, or the default I18N localization context does not contain any resource bundle, or the given key is undefined in its resource bundle, the string "???<key>???" is returned, where "<key>" is replaced with the given key.

param
pageContext the page in which to get the localized message corresponding to the given key
param
key the message key
return
the localized message corresponding to the given key


                                                                                                                          
         
                                               
	return getLocalizedMessage(pageContext, key, null, null);
    
public static java.lang.StringgetLocalizedMessage(javax.servlet.jsp.PageContext pageContext, java.lang.String key, java.lang.String basename)
Retrieves the localized message corresponding to the given key.

The given key is looked up in the resource bundle with the given base name.

If no resource bundle with the given base name exists, or the given key is undefined in the resource bundle, the string "???<key>???" is returned, where "<key>" is replaced with the given key.

param
pageContext the page in which to get the localized message corresponding to the given key
param
key the message key
param
basename the resource bundle base name
return
the localized message corresponding to the given key

	return getLocalizedMessage(pageContext, key, null, basename);
    
public static java.lang.StringgetLocalizedMessage(javax.servlet.jsp.PageContext pageContext, java.lang.String key, java.lang.Object[] args)
Retrieves the localized message corresponding to the given key, and performs parametric replacement using the arguments specified via args.

See the specification of the <fmt:message> action for a description of how parametric replacement is implemented.

The localized message is retrieved as in {@link #getLocalizedMessage(javax.servlet.jsp.PageContext,java.lang.String) getLocalizedMessage(pageContext, key)}.

param
pageContext the page in which to get the localized message corresponding to the given key
param
key the message key
param
args the arguments for parametric replacement
return
the localized message corresponding to the given key

	return getLocalizedMessage(pageContext, key, args, null);
    
public static java.lang.StringgetLocalizedMessage(javax.servlet.jsp.PageContext pageContext, java.lang.String key, java.lang.Object[] args, java.lang.String basename)
Retrieves the localized message corresponding to the given key, and performs parametric replacement using the arguments specified via args.

See the specification of the <fmt:message> action for a description of how parametric replacement is implemented.

The localized message is retrieved as in {@link #getLocalizedMessage(javax.servlet.jsp.PageContext,java.lang.String, java.lang.String) getLocalizedMessage(pageContext, key, basename)}.

param
pageContext the page in which to get the localized message corresponding to the given key
param
key the message key
param
args the arguments for parametric replacement
param
basename the resource bundle base name
return
the localized message corresponding to the given key

	LocalizationContext locCtxt = null;
	String message = UNDEFINED_KEY + key + UNDEFINED_KEY;

	if (basename != null) {
	    locCtxt = getLocalizationContext(pageContext, basename);
	} else {
	    locCtxt = getLocalizationContext(pageContext);
	}

	if (locCtxt != null) {
	    ResourceBundle bundle = locCtxt.getResourceBundle();
	    if (bundle != null) {
		try {
		    message = bundle.getString(key);
		    if (args != null) {
			MessageFormat formatter = new MessageFormat("");
			if (locCtxt.getLocale() != null) {
			    formatter.setLocale(locCtxt.getLocale());
			}
			formatter.applyPattern(message);
			message = formatter.format(args);
		    }
		} catch (MissingResourceException mre) {
		}
	    }
	}

	return message;
    
private static java.util.EnumerationgetRequestLocales(javax.servlet.http.HttpServletRequest request)
HttpServletRequest.getLocales() returns the server's default locale if the request did not specify a preferred language. We do not want this behavior, because it prevents us from using the fallback locale. We therefore need to return an empty Enumeration if no preferred locale has been specified. This way, the logic for the fallback locale will be able to kick in.

        
        Enumeration values = request.getHeaders("accept-language");
        if (values.hasMoreElements()) {
            // At least one "accept-language". Simply return
            // the enumeration returned by request.getLocales().
            // System.out.println("At least one accept-language");
            return request.getLocales();
        } else {
            // No header for "accept-language". Simply return
            // the empty enumeration.
            // System.out.println("No accept-language");
            return values;
        }
    
private static java.util.LocaleparseLocale(java.lang.String locale)
See parseLocale(String, String) for details.

	return parseLocale(locale, null);
    
private static java.util.LocaleparseLocale(java.lang.String locale, java.lang.String variant)
Parses the given locale string into its language and (optionally) country components, and returns the corresponding java.util.Locale object. If the given locale string is null or empty, the runtime's default locale is returned.

param
locale the locale string to parse
param
variant the variant
return
java.util.Locale object corresponding to the given locale string, or the runtime's default locale if the locale string is null or empty
throws
IllegalArgumentException if the given locale does not have a language component or has an empty country component


	Locale ret = null;
	String language = locale;
	String country = null;
	int index = -1;

	if (((index = locale.indexOf(HYPHEN)) > -1)
	        || ((index = locale.indexOf(UNDERSCORE)) > -1)) {
	    language = locale.substring(0, index);
	    country = locale.substring(index+1);
	}

	if ((language == null) || (language.length() == 0)) {
	    throw new IllegalArgumentException(
		"Missing language component in 'value' attribute in setLocale");
	}

	if (country == null) {
	    if (variant != null)
		ret = new Locale(language, "", variant);
	    else
		ret = new Locale(language, "");
	} else if (country.length() > 0) {
	    if (variant != null)
		ret = new Locale(language, country, variant);
	    else
		ret = new Locale(language, country);
	} else {
	    throw new IllegalArgumentException(
		"Empty country component in 'value' attribute in setLocale");
	}

	return ret;
    
private static voidsetResponseLocale(javax.servlet.jsp.PageContext pc, java.util.Locale locale)

	// set response locale
	ServletResponse response = pc.getResponse();
	response.setLocale(locale);
	
	// get response character encoding and store it in session attribute
	if (pc.getSession() != null) {
            try {
	        pc.setAttribute(REQUEST_CHAR_SET,
			        response.getCharacterEncoding(),
			        PageContext.SESSION_SCOPE);
            } catch (IllegalStateException ex) {} // invalidated session ignored
	}