org.apereo.portal.i18n.LocaleManager.java Source code

Java tutorial

Introduction

Here is the source code for org.apereo.portal.i18n.LocaleManager.java

Source

/**
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apereo.portal.i18n;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.properties.PropertiesManager;
import org.apereo.portal.security.IPerson;
import org.apereo.portal.utils.DocumentFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Manages locales on behalf of a user. 
 * This class currently keeps track of locales at the following levels:<br>
 * <ol>
 *   <li>User's locale preferences (associated with a user ID)</li>
 *   <li>Browser's locale preferences (from the Accept-Language request header)</li>
 *   <li>Session's locale preferences (set via the portal request parameter uP_locales)</li>
 *   <li>Portal's locale preferences (set in portal.properties)</li>
 * </ol>
 * Eventually, this class will also keep track of locale preferences at
 * the following levels:<br>
 * <ol>
 *   <li>Layout node's locale preferences</li>
 *   <li>User profile's locale preferences</li>
 * </ol>
 * @author Shoji Kajita <a href="mailto:">kajita@itc.nagoya-u.ac.jp</a>
 * @author Ken Weiner, kweiner@unicon.net
 * @version $Revision$
 */
public class LocaleManager implements Serializable {

    private static final Log log = LogFactory.getLog(LocaleManager.class);

    /**
     * Default value for localeAware.
     * This value will be used when the corresponding property cannot be loaded.
     */
    public static final boolean DEFAULT_LOCALE_AWARE = false;

    private static boolean localeAware = PropertiesManager
            .getPropertyAsBoolean("org.apereo.portal.i18n.LocaleManager.locale_aware", DEFAULT_LOCALE_AWARE);
    private static Locale jvmLocale;
    private static Locale[] portalLocales;

    private final IPerson person;
    private Locale[] sessionLocales;
    private Locale[] browserLocales;
    private Locale[] userLocales;

    /**
     * Constructor that associates a locale manager with a user.
     * @param person the user
     */
    public LocaleManager(IPerson person, Locale[] userLocales) {
        this.person = person;
        jvmLocale = Locale.getDefault();
        if (localeAware) {
            portalLocales = loadPortalLocales();
            try {
                this.userLocales = userLocales;
            } catch (Exception e) {
                log.error("Error populating userLocals", e);
            }
        }
    }

    /**
     * Constructor that sets up locales according to
     * the <code>Accept-Language</code> request header
     * from a user's browser.
     * @param person the user
     * @param acceptLanguage the Accept-Language request header from a user's browser
     */
    public LocaleManager(IPerson person, Locale[] userLocales, String acceptLanguage) {
        this(person, userLocales);
        this.browserLocales = parseLocales(acceptLanguage);
    }

    // Getters
    public static boolean isLocaleAware() {
        return localeAware;
    }

    public static Locale getJvmLocale() {
        return jvmLocale;
    }

    public static Locale[] getPortalLocales() {
        return portalLocales;
    }

    public Locale[] getBrowserLocales() {
        return browserLocales;
    }

    public Locale[] getUserLocales() {
        return userLocales;
    }

    public Locale[] getSessionLocales() {
        return sessionLocales;
    }

    // Setters
    public static void setJvmLocale(Locale jvmLocale) {
        LocaleManager.jvmLocale = jvmLocale;
    }

    public static void setPortalLocales(Locale[] portalLocales) {
        LocaleManager.portalLocales = portalLocales;
    }

    public void setBrowserLocales(Locale[] browserLocales) {
        this.browserLocales = browserLocales;
    }

    public void setUserLocales(Locale[] userLocales) {
        this.userLocales = userLocales;
        this.sessionLocales = userLocales;
    }

    public void setSessionLocales(Locale[] sessionLocales) {
        this.sessionLocales = sessionLocales;
    }

    /**
     * Read and parse portal_locales from portal.properties.
     * portal_locales will be in the form of a comma-separated 
     * list, e.g. en_US,ja_JP,sv_SE 
     */
    private Locale[] loadPortalLocales() {
        String portalLocalesString = PropertiesManager
                .getProperty("org.apereo.portal.i18n.LocaleManager.portal_locales");
        return parseLocales(portalLocalesString);
    }

    /**
     * Produces a sorted list of locales according to locale preferences
     * obtained from several places.  The following priority is given:
     * session, user, browser, portal, and jvm.
     * @return the sorted list of locales
     */
    public Locale[] getLocales() {
        // Need logic to construct ordered locale list.
        // Consider creating a separate ILocaleResolver 
        // interface to do this work.
        List locales = new ArrayList();
        // Add highest priority locales first
        addToLocaleList(locales, sessionLocales);
        addToLocaleList(locales, userLocales);
        // We will ignore browser locales until we know how to
        // translate them into proper java.util.Locales
        //addToLocaleList(locales, browserLocales);
        addToLocaleList(locales, portalLocales);
        addToLocaleList(locales, new Locale[] { jvmLocale });
        return (Locale[]) locales.toArray(new Locale[0]);
    }

    /**
     * Add locales to the locale list if they aren't in there already
     */
    private void addToLocaleList(List localeList, Locale[] locales) {
        if (locales != null) {
            for (int i = 0; i < locales.length; i++) {
                if (locales[i] != null && !localeList.contains(locales[i]))
                    localeList.add(locales[i]);
            }
        }
    }

    /**
     * Helper method to produce a <code>java.util.Locale</code> array from
     * a comma-delimited locale string list, e.g. "en_US,ja_JP"
     * @param localeStringList the locales to parse
     * @return an array of locales representing the locale string list
     */
    public static Locale[] parseLocales(String localeStringList) {
        Locale[] locales = null;
        if (localeStringList != null) {
            StringTokenizer st = new StringTokenizer(localeStringList, ",");
            locales = new Locale[st.countTokens()];
            for (int i = 0; st.hasMoreTokens(); i++) {
                String localeString = st.nextToken().trim();
                locales[i] = parseLocale(localeString);
            }
        }
        return locales;
    }

    /**
     * Helper method to produce a <code>java.util.Locale</code> object from
     * a locale string such as en_US or ja_JP.
     * @param localeString a locale string such as en_US
     * @return a java.util.Locale object representing the locale string
     */
    public static Locale parseLocale(String localeString) {
        String language = null;
        String country = null;
        String variant = null;

        // Sometimes people specify "en-US" instead of "en_US", so
        // we'll try to clean that up.
        localeString = localeString.replaceAll("-", "_");

        StringTokenizer st = new StringTokenizer(localeString, "_");

        if (st.hasMoreTokens()) {
            language = st.nextToken();
        }
        if (st.hasMoreTokens()) {
            country = st.nextToken();
        }
        if (st.hasMoreTokens()) {
            variant = st.nextToken();
        }

        Locale locale = null;

        if (variant != null) {
            locale = new Locale(language, country, variant);
        } else if (country != null) {
            locale = new Locale(language, country);
        } else if (language != null) {
            // Uncomment the following line
            // when we can count on JDK 1.4!
            //locale = new Locale(language);
            locale = new Locale(language, "");
        }

        return locale;
    }

    /**
     * Constructs a comma-delimited list of locales
     * that could be parsed back into a Locale
     * array with parseLocales(String localeStringList).
     * @param locales the list of locales
     * @return a string representing the list of locales
     */
    public static String stringValueOf(Locale[] locales) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < locales.length; i++) {
            Locale locale = locales[i];
            sb.append(locale.toString());
            if (i < locales.length - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    /**
     * Stores the user locales persistantly.
     * @param userLocales the user locales preference
     * @throws Exception
     */
    public void persistUserLocales(Locale[] userLocales) throws Exception {
        setUserLocales(userLocales);
    }

    /**
     * Creates an XML representation of a list of locales.
     * @param locales the locale list
     * @return the locale list as XML
     */
    public static Document xmlValueOf(Locale[] locales) {
        return xmlValueOf(locales, null);
    }

    /**
     * Creates an XML representation of a list of locales.
     * If a selected locale is supplied, the XML element representing
     * the selected locale will have an attribute of selected with value
     * of true.  This is helpful when constructing user interfaces that
     * indicate which locale is selected.
     * @param locales the locale list
     * @param selectedLocale a locale that should be selected if it is in the list
     * @return the locale list as XML
     */
    public static Document xmlValueOf(Locale[] locales, Locale selectedLocale) {
        Document doc = DocumentFactory.getThreadDocument();

        // <locales>
        Element localesE = doc.createElement("locales");
        for (int i = 0; i < locales.length; i++) {
            Element locE = doc.createElement("locale");
            locE.setAttribute("displayName", locales[i].getDisplayName(locales[0]));
            locE.setAttribute("code", locales[i].toString());

            // Mark which locale is the user's preference
            if (selectedLocale != null && selectedLocale.equals(locales[i])) {
                locE.setAttribute("selected", "true");
            }

            // <language iso2="..." iso3="..." displayName="..."/>
            Element languageE = doc.createElement("language");
            languageE.setAttribute("iso2", locales[i].getLanguage());
            try {
                languageE.setAttribute("iso3", locales[i].getISO3Language());
            } catch (Exception e) {
                // Do nothing
            }
            languageE.setAttribute("displayName", locales[i].getDisplayLanguage(locales[0]));
            locE.appendChild(languageE);

            // <country iso2="..." iso3="..." displayName="..."/>
            Element countryE = doc.createElement("country");
            countryE.setAttribute("iso2", locales[i].getCountry());
            try {
                countryE.setAttribute("iso3", locales[i].getISO3Country());
            } catch (Exception e) {
                // Do nothing
            }
            countryE.setAttribute("displayName", locales[i].getDisplayCountry(locales[0]));
            locE.appendChild(countryE);

            // <variant code="..." displayName="..."/>
            Element variantE = doc.createElement("variant");
            variantE.setAttribute("code", locales[i].getVariant());
            variantE.setAttribute("displayName", locales[i].getDisplayVariant(locales[0]));
            locE.appendChild(variantE);

            localesE.appendChild(locE);
        }
        doc.appendChild(localesE);
        return doc;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer(1024);
        sb.append("LocaleManager's locales").append("\n");
        sb.append("-----------------------").append("\n");
        sb.append("Session locales: ");
        if (sessionLocales != null) {
            sb.append(stringValueOf(sessionLocales));
        }
        sb.append("\n");
        sb.append("User locales: ");
        if (userLocales != null) {
            sb.append(stringValueOf(userLocales));
        }
        sb.append("\n");
        sb.append("Browser locales: ");
        if (browserLocales != null) {
            sb.append(stringValueOf(browserLocales));
        }
        sb.append("\n");
        sb.append("Portal locales: ");
        if (portalLocales != null) {
            sb.append(stringValueOf(portalLocales));
        }
        sb.append("\n");
        sb.append("JVM locale: ");
        if (jvmLocale != null) {
            sb.append(jvmLocale.toString());
        }
        sb.append("\n");
        sb.append("Sorted locales: ");
        Locale[] sortedLocales = getLocales();
        if (sortedLocales != null) {
            sb.append(stringValueOf(sortedLocales));
        }
        sb.append("\n");
        return sb.toString();
    }

}