001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.chrono;
017:
018: import java.lang.ref.WeakReference;
019: import java.text.DateFormatSymbols;
020: import java.util.WeakHashMap;
021: import java.util.Locale;
022: import java.util.TreeMap;
023:
024: import org.joda.time.DateTimeFieldType;
025: import org.joda.time.IllegalFieldValueException;
026:
027: /**
028: * Utility class used by a few of the GJDateTimeFields.
029: *
030: * @author Brian S O'Neill
031: * @since 1.0
032: */
033: class GJLocaleSymbols {
034: private static final int FAST_CACHE_SIZE = 64;
035:
036: private static final GJLocaleSymbols[] cFastCache = new GJLocaleSymbols[FAST_CACHE_SIZE];
037:
038: private static WeakHashMap cCache = new WeakHashMap();
039:
040: public static GJLocaleSymbols forLocale(Locale locale) {
041: if (locale == null) {
042: locale = Locale.getDefault();
043: }
044: int index = System.identityHashCode(locale)
045: & (FAST_CACHE_SIZE - 1);
046: GJLocaleSymbols symbols = cFastCache[index];
047: if (symbols != null && symbols.iLocale.get() == locale) {
048: return symbols;
049: }
050: synchronized (cCache) {
051: symbols = (GJLocaleSymbols) cCache.get(locale);
052: if (symbols == null) {
053: symbols = new GJLocaleSymbols(locale);
054: cCache.put(locale, symbols);
055: }
056: }
057: cFastCache[index] = symbols;
058: return symbols;
059: }
060:
061: private static String[] realignMonths(String[] months) {
062: String[] a = new String[13];
063: for (int i = 1; i < 13; i++) {
064: a[i] = months[i - 1];
065: }
066: return a;
067: }
068:
069: private static String[] realignDaysOfWeek(String[] daysOfWeek) {
070: String[] a = new String[8];
071: for (int i = 1; i < 8; i++) {
072: a[i] = daysOfWeek[(i < 7) ? i + 1 : 1];
073: }
074: return a;
075: }
076:
077: private static void addSymbols(TreeMap map, String[] symbols,
078: Integer[] integers) {
079: for (int i = symbols.length; --i >= 0;) {
080: String symbol = symbols[i];
081: if (symbol != null) {
082: map.put(symbol, integers[i]);
083: }
084: }
085: }
086:
087: private static void addNumerals(TreeMap map, int start, int end,
088: Integer[] integers) {
089: for (int i = start; i <= end; i++) {
090: map.put(String.valueOf(i).intern(), integers[i]);
091: }
092: }
093:
094: private static int maxLength(String[] a) {
095: int max = 0;
096: for (int i = a.length; --i >= 0;) {
097: String s = a[i];
098: if (s != null) {
099: int len = s.length();
100: if (len > max) {
101: max = len;
102: }
103: }
104: }
105: return max;
106: }
107:
108: private final WeakReference iLocale;
109:
110: private final String[] iEras;
111: private final String[] iDaysOfWeek;
112: private final String[] iShortDaysOfWeek;
113: private final String[] iMonths;
114: private final String[] iShortMonths;
115: private final String[] iHalfday;
116:
117: // These map Strings to Integers.
118: private final TreeMap iParseEras;
119: private final TreeMap iParseDaysOfWeek;
120: private final TreeMap iParseMonths;
121:
122: private final int iMaxEraLength;
123: private final int iMaxDayOfWeekLength;
124: private final int iMaxShortDayOfWeekLength;
125: private final int iMaxMonthLength;
126: private final int iMaxShortMonthLength;
127: private final int iMaxHalfdayLength;
128:
129: /**
130: * @param locale must not be null
131: */
132: private GJLocaleSymbols(Locale locale) {
133: iLocale = new WeakReference(locale);
134:
135: DateFormatSymbols dfs = new DateFormatSymbols(locale);
136:
137: iEras = dfs.getEras();
138: iDaysOfWeek = realignDaysOfWeek(dfs.getWeekdays());
139: iShortDaysOfWeek = realignDaysOfWeek(dfs.getShortWeekdays());
140: iMonths = realignMonths(dfs.getMonths());
141: iShortMonths = realignMonths(dfs.getShortMonths());
142: iHalfday = dfs.getAmPmStrings();
143:
144: Integer[] integers = new Integer[13];
145: for (int i = 0; i < 13; i++) {
146: integers[i] = new Integer(i);
147: }
148:
149: iParseEras = new TreeMap(String.CASE_INSENSITIVE_ORDER);
150: addSymbols(iParseEras, iEras, integers);
151: if ("en".equals(locale.getLanguage())) {
152: // Include support for parsing "BCE" and "CE" if the language is
153: // English. At some point Joda-Time will need an independent set of
154: // localized symbols and not depend on java.text.DateFormatSymbols.
155: iParseEras.put("BCE", integers[0]);
156: iParseEras.put("CE", integers[1]);
157: }
158:
159: iParseDaysOfWeek = new TreeMap(String.CASE_INSENSITIVE_ORDER);
160: addSymbols(iParseDaysOfWeek, iDaysOfWeek, integers);
161: addSymbols(iParseDaysOfWeek, iShortDaysOfWeek, integers);
162: addNumerals(iParseDaysOfWeek, 1, 7, integers);
163:
164: iParseMonths = new TreeMap(String.CASE_INSENSITIVE_ORDER);
165: addSymbols(iParseMonths, iMonths, integers);
166: addSymbols(iParseMonths, iShortMonths, integers);
167: addNumerals(iParseMonths, 1, 12, integers);
168:
169: iMaxEraLength = maxLength(iEras);
170: iMaxDayOfWeekLength = maxLength(iDaysOfWeek);
171: iMaxShortDayOfWeekLength = maxLength(iShortDaysOfWeek);
172: iMaxMonthLength = maxLength(iMonths);
173: iMaxShortMonthLength = maxLength(iShortMonths);
174: iMaxHalfdayLength = maxLength(iHalfday);
175: }
176:
177: public String eraValueToText(int value) {
178: return iEras[value];
179: }
180:
181: public int eraTextToValue(String text) {
182: Integer era = (Integer) iParseEras.get(text);
183: if (era != null) {
184: return era.intValue();
185: }
186: throw new IllegalFieldValueException(DateTimeFieldType.era(),
187: text);
188: }
189:
190: public int getEraMaxTextLength() {
191: return iMaxEraLength;
192: }
193:
194: public String monthOfYearValueToText(int value) {
195: return iMonths[value];
196: }
197:
198: public String monthOfYearValueToShortText(int value) {
199: return iShortMonths[value];
200: }
201:
202: public int monthOfYearTextToValue(String text) {
203: Integer month = (Integer) iParseMonths.get(text);
204: if (month != null) {
205: return month.intValue();
206: }
207: throw new IllegalFieldValueException(DateTimeFieldType
208: .monthOfYear(), text);
209: }
210:
211: public int getMonthMaxTextLength() {
212: return iMaxMonthLength;
213: }
214:
215: public int getMonthMaxShortTextLength() {
216: return iMaxShortMonthLength;
217: }
218:
219: public String dayOfWeekValueToText(int value) {
220: return iDaysOfWeek[value];
221: }
222:
223: public String dayOfWeekValueToShortText(int value) {
224: return iShortDaysOfWeek[value];
225: }
226:
227: public int dayOfWeekTextToValue(String text) {
228: Integer day = (Integer) iParseDaysOfWeek.get(text);
229: if (day != null) {
230: return day.intValue();
231: }
232: throw new IllegalFieldValueException(DateTimeFieldType
233: .dayOfWeek(), text);
234: }
235:
236: public int getDayOfWeekMaxTextLength() {
237: return iMaxDayOfWeekLength;
238: }
239:
240: public int getDayOfWeekMaxShortTextLength() {
241: return iMaxShortDayOfWeekLength;
242: }
243:
244: public String halfdayValueToText(int value) {
245: return iHalfday[value];
246: }
247:
248: public int halfdayTextToValue(String text) {
249: String[] halfday = iHalfday;
250: for (int i = halfday.length; --i >= 0;) {
251: if (halfday[i].equalsIgnoreCase(text)) {
252: return i;
253: }
254: }
255: throw new IllegalFieldValueException(DateTimeFieldType
256: .halfdayOfDay(), text);
257: }
258:
259: public int getHalfdayMaxTextLength() {
260: return iMaxHalfdayLength;
261: }
262: }
|