001: /*
002:
003: * Project: JAMon
004:
005: * $RCSfile: LocaleContext.java,v $
006:
007: * $Revision: 1.8 $ ($Author: stevesouza $)
008:
009: * $Date: 2006/03/02 04:26:05 $
010:
011: */
012:
013: package com.jamonapi.utils;
014:
015: /**
016:
017: * Provides a context for localized parameters, mainly formatters, in thread local scope.
018:
019: * Note normally the Formatting classes are not thread safe.
020:
021: * This class uses ThreadLocal to return a unique object to each thread, so the getFloatingPointFormatter
022:
023: * returns the same object in one thread, and getIntegerFormatter returns another one in the same thread.
024:
025: * By using only LocaleContext to get Format objects instead of constructing Format objects
026:
027: * otherwise, thread-safity is ensured. This class is tuned for performance: constructing a Format
028:
029: * object is rather expensive, this class only creates them when really needed.
030:
031: *
032:
033: * @author Jeroen Borgers
034:
035: * @author Steve Souza
036:
037: */
038:
039: import java.text.DateFormat;
040:
041: import java.text.DecimalFormat;
042:
043: import java.text.DecimalFormatSymbols;
044:
045: import java.text.NumberFormat;
046:
047: import java.util.Locale;
048:
049: public final class LocaleContext {
050:
051: /** the thread local storage for the locale specific formatters */
052:
053: private static final ThreadLocalFormatterStorage formatterStorage = new ThreadLocalFormatterStorage();
054:
055: /** @return the thread local storage for the fixed-point number formatting specific for the locale */
056:
057: public static DecimalFormat getFloatingPointFormatter() {
058:
059: return getFormatters().getFloatingPointFormatter();
060:
061: }
062:
063: /** @return the thread local storage for the integral number formatting specific for the locale */
064:
065: public static DecimalFormat getIntegerFormatter() {
066:
067: return getFormatters().getIntegerFormatter();
068:
069: }
070:
071: /** @return the thread local storage for the percent number formatting specific for the locale */
072:
073: public static DecimalFormat getPercentFormatter() {
074:
075: return getFormatters().getPercentFormatter();
076:
077: }
078:
079: /** @return the thread local storage for the currency formatting specific for the locale */
080:
081: public static DecimalFormat getCurrencyFormatter() {
082:
083: return getFormatters().getCurrencyFormatter();
084:
085: }
086:
087: /**
088:
089: * @return the thread local storage for the number formatting decimal grouping separator
090:
091: * specific for the locale
092:
093: */
094:
095: public static char getDecimalGroupSeparator() {
096:
097: return getFormatters().getDecimalGroupSeparator();
098:
099: }
100:
101: /** @return the locale specific date time formatter */
102:
103: public static DateFormat getDateFormatter() {
104:
105: return getFormatters().getDateFormatter();
106:
107: }
108:
109: /**
110:
111: * Sets the locale to apply for formatting.
112:
113: *
114:
115: * @param locale the locale to apply for formatting.
116:
117: */
118:
119: public static void setLocale(Locale locale) {
120:
121: getFormatters().setLocale(locale);
122:
123: }
124:
125: /**
126:
127: * @return Returns the thread associated, locale specific formatters
128:
129: */
130:
131: private static Formatters getFormatters() {
132:
133: return (Formatters) formatterStorage.get();
134:
135: }
136:
137: /** Inner class for storage of thread-associated formatters */
138:
139: private static final class ThreadLocalFormatterStorage extends
140: ThreadLocal {
141:
142: /**
143:
144: * @return the current thread's initial value for this thread-local variable. This method
145:
146: * will be invoked at most once per accessing thread for each thread-local.
147:
148: */
149:
150: protected Object initialValue() {
151:
152: return new Formatters();
153:
154: }
155:
156: }
157:
158: /** Inner class of thread-associated formatters */
159:
160: private static class Formatters {
161:
162: private Locale locale;
163:
164: private DecimalFormat floatingPointFormatter;
165:
166: private DecimalFormat integerFormatter;
167:
168: /** the number formatting decimal grouping separator */
169:
170: private char decimalSeparator = 0;
171:
172: private DateFormat dateFormatter;
173:
174: private DecimalFormat percentFormatter;
175:
176: private DecimalFormat currencyFormatter;
177:
178: void setLocale(Locale locale) {
179:
180: this .locale = locale;
181:
182: // now all formatters need to re-created when needed, to apply the new locale
183:
184: floatingPointFormatter = null;
185:
186: integerFormatter = null;
187:
188: decimalSeparator = 0;
189:
190: dateFormatter = null;
191:
192: percentFormatter = null;
193:
194: currencyFormatter = null;
195:
196: }
197:
198: Locale getLocale() {
199:
200: if (locale == null) { // if no locale specified from client
201:
202: locale = Locale.getDefault();
203:
204: }
205:
206: return locale;
207:
208: }
209:
210: DecimalFormat getFloatingPointFormatter() {
211:
212: if (floatingPointFormatter == null) {
213:
214: floatingPointFormatter = (DecimalFormat) NumberFormat
215: .getNumberInstance(getLocale());
216:
217: floatingPointFormatter.applyPattern("#,###.#");
218:
219: }
220:
221: return floatingPointFormatter;
222:
223: }
224:
225: DecimalFormat getIntegerFormatter() {
226:
227: if (integerFormatter == null) {
228:
229: integerFormatter = (DecimalFormat) NumberFormat
230: .getNumberInstance(getLocale());
231:
232: integerFormatter.applyPattern("#,###");
233:
234: }
235:
236: return integerFormatter;
237:
238: }
239:
240: DecimalFormat getPercentFormatter() {
241:
242: if (percentFormatter == null) {
243:
244: percentFormatter = (DecimalFormat) NumberFormat
245: .getPercentInstance(getLocale());
246:
247: }
248:
249: return percentFormatter;
250:
251: }
252:
253: DecimalFormat getCurrencyFormatter() {
254:
255: if (currencyFormatter == null) {
256:
257: currencyFormatter = (DecimalFormat) NumberFormat
258: .getCurrencyInstance(getLocale());
259:
260: }
261:
262: return currencyFormatter;
263:
264: }
265:
266: char getDecimalGroupSeparator() {
267:
268: if (decimalSeparator == 0) {
269:
270: DecimalFormatSymbols symbols = new DecimalFormatSymbols(
271: getLocale());
272:
273: decimalSeparator = (new Character(symbols
274: .getGroupingSeparator())).charValue();
275:
276: }
277:
278: return decimalSeparator;
279:
280: }
281:
282: DateFormat getDateFormatter() {
283:
284: if (dateFormatter == null) {
285:
286: dateFormatter = DateFormat.getDateTimeInstance(
287: DateFormat.SHORT,
288:
289: DateFormat.DEFAULT, getLocale());
290:
291: }
292:
293: return dateFormatter;
294:
295: }
296:
297: }
298:
299: /** contructs a new LocaleContext, for private use only */
300:
301: private LocaleContext() {
302:
303: }
304:
305: }
|