All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jamonapi.utils.LocaleContext Maven / Gradle / Ivy

There is a newer version: 2.82
Show newest version

package com.jamonapi.utils;


import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;

/**
 * 
 * Provides a context for localized parameters, mainly formatters, in thread local scope.
 * Note normally the Formatting classes are not thread safe.
 * This class uses ThreadLocal to return a unique object to each thread, so the getFloatingPointFormatter
 * returns the same object in one thread, and getIntegerFormatter returns another one in the same thread.
 * By using only LocaleContext to get Format objects instead of constructing Format objects
 * otherwise, thread-safety is ensured. This class is tuned for performance: constructing a Format
 * object is rather expensive, this class only creates them when really needed.
 * 
 */

public final class LocaleContext {

    /** the thread local storage for the locale specific formatters */
    private static ThreadLocalFormatterStorage formatterStorage = new ThreadLocalFormatterStorage();

    /** @return the thread local storage for the fixed-point number formatting specific for the locale */
    public static DecimalFormat getFloatingPointFormatter() {
        return getFormatters().getFloatingPointFormatter();
    }

    /** @return the thread local storage for the integral number formatting specific for the locale */
    public static DecimalFormat getIntegerFormatter() {
        return getFormatters().getIntegerFormatter();
    }

    /** @return the thread local storage for the percent number formatting specific for the locale */
    public static DecimalFormat getPercentFormatter() {
        return getFormatters().getPercentFormatter();
    }

    /** @return the thread local storage for the currency formatting specific for the locale */
    public static DecimalFormat getCurrencyFormatter() {
        return getFormatters().getCurrencyFormatter();
    }

    /**
     * @return the thread local storage for the number formatting decimal grouping separator
     *         specific for the locale
     */
    public static char getDecimalGroupSeparator() {
        return getFormatters().getDecimalGroupSeparator();
    }

    /** @return the locale specific date time formatter */
    public static DateFormat getDateFormatter() {
        return getFormatters().getDateFormatter();
    }

    /**
     * Sets the locale to apply for formatting.
     * 
     * @param locale the locale to apply for formatting.
     */
    public static void setLocale(Locale locale) {
        getFormatters().setLocale(locale);
    }

    /**
     * Reset thread local variables.  For example this can be called when an application is 'undeployed'.
     * This was done to fix a memory leak in tomcat that happened when the app context was destroyed.
     * The context couldn't be properly destroyed as objects were still in the threadlocal map.
     */
    public static void reset() {
        formatterStorage = new ThreadLocalFormatterStorage();
    }

    /**
     * @return Returns the thread associated, locale specific formatters
     */
    private static Formatters getFormatters() {
        return (Formatters) formatterStorage.get();
    }

    /** Inner class for storage of thread-associated formatters */
    private static final class ThreadLocalFormatterStorage extends ThreadLocal {
        /**
         * @return the current thread's initial value for this thread-local variable. This method
         *         will be invoked at most once per accessing thread for each thread-local.
         */
        @Override
        protected Object initialValue() {
            return new Formatters();
        }
    }

    /** Inner class of thread-associated formatters */
    private static class Formatters {
        private Locale locale;
        private DecimalFormat floatingPointFormatter;
        private DecimalFormat integerFormatter;

        /** the number formatting decimal grouping separator */
        private char decimalSeparator = 0;
        private DateFormat dateFormatter;
        private DecimalFormat percentFormatter;
        private DecimalFormat currencyFormatter;

        void setLocale(Locale locale) {
            this.locale = locale;
            // now all formatters need to re-created when needed, to apply the new locale
            floatingPointFormatter = null;
            integerFormatter = null;
            decimalSeparator = 0;
            dateFormatter = null;
            percentFormatter = null;
            currencyFormatter = null;
        }

        Locale getLocale() {
            if (locale == null) { // if no locale specified from client
                locale = Locale.getDefault();
            }
            return locale;
        }

        DecimalFormat getFloatingPointFormatter() {
            if (floatingPointFormatter == null) {
                floatingPointFormatter = (DecimalFormat) NumberFormat.getNumberInstance(getLocale());
                floatingPointFormatter.applyPattern("#,###.#");
            }
            return floatingPointFormatter;
        }

        DecimalFormat getIntegerFormatter() {
            if (integerFormatter == null) {
                integerFormatter = (DecimalFormat) NumberFormat.getNumberInstance(getLocale());
                integerFormatter.applyPattern("#,###");
            }
            return integerFormatter;
        }

        DecimalFormat getPercentFormatter() {
            if (percentFormatter == null) {
                percentFormatter = (DecimalFormat) NumberFormat.getPercentInstance(getLocale());
            }
            return percentFormatter;
        }

        DecimalFormat getCurrencyFormatter() {
            if (currencyFormatter == null) {
                currencyFormatter = (DecimalFormat) NumberFormat.getCurrencyInstance(getLocale());
            }
            return currencyFormatter;
        }

        char getDecimalGroupSeparator() {
            if (decimalSeparator == 0) {
                DecimalFormatSymbols symbols = new DecimalFormatSymbols(getLocale());
                decimalSeparator = (new Character(symbols.getGroupingSeparator())).charValue();
            }
            return decimalSeparator;
        }

        DateFormat getDateFormatter() {
            if (dateFormatter == null) {
                dateFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT,
                        DateFormat.DEFAULT, getLocale());
            }
            return dateFormatter;
        }

    }

    /** contructs a new LocaleContext, for private use only */
    private LocaleContext() {
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy