View Javadoc

1   /*
2    *  Copyright 2001-2009 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time.chrono;
17  
18  import java.lang.ref.WeakReference;
19  import java.text.DateFormatSymbols;
20  import java.util.Locale;
21  import java.util.TreeMap;
22  import java.util.WeakHashMap;
23  
24  import org.joda.time.DateTimeFieldType;
25  import org.joda.time.DateTimeUtils;
26  import org.joda.time.IllegalFieldValueException;
27  
28  /**
29   * Utility class used by a few of the GJDateTimeFields.
30   *
31   * @author Brian S O'Neill
32   * @since 1.0
33   */
34  class GJLocaleSymbols {
35      private static final int FAST_CACHE_SIZE = 64;
36  
37      private static final GJLocaleSymbols[] cFastCache = new GJLocaleSymbols[FAST_CACHE_SIZE];
38  
39      private static WeakHashMap<Locale, GJLocaleSymbols> cCache = new WeakHashMap<Locale, GJLocaleSymbols>();
40  
41      public static GJLocaleSymbols forLocale(Locale locale) {
42          if (locale == null) {
43              locale = Locale.getDefault();
44          }
45          int index = System.identityHashCode(locale) & (FAST_CACHE_SIZE - 1);
46          GJLocaleSymbols symbols = cFastCache[index];
47          if (symbols != null && symbols.iLocale.get() == locale) {
48              return symbols;
49          }
50          synchronized (cCache) {
51              symbols = cCache.get(locale);
52              if (symbols == null) {
53                  symbols = new GJLocaleSymbols(locale);
54                  cCache.put(locale, symbols);
55              }
56          }
57          cFastCache[index] = symbols;
58          return symbols;
59      }
60  
61      private static String[] realignMonths(String[] months) {
62          String[] a = new String[13];
63          for (int i=1; i<13; i++) {
64              a[i] = months[i - 1];
65          }
66          return a;
67      }
68  
69      private static String[] realignDaysOfWeek(String[] daysOfWeek) {
70          String[] a = new String[8];
71          for (int i=1; i<8; i++) {
72              a[i] = daysOfWeek[(i < 7) ? i + 1 : 1];
73          }
74          return a;
75      }
76  
77      private static void addSymbols(TreeMap<String, Integer> map, String[] symbols, Integer[] integers) {
78          for (int i=symbols.length; --i>=0; ) {
79              String symbol = symbols[i];
80              if (symbol != null) {
81                  map.put(symbol, integers[i]);
82              }
83          }
84      }
85  
86      private static void addNumerals(TreeMap<String, Integer> map, int start, int end, Integer[] integers) {
87          for (int i=start; i<=end; i++) {
88              map.put(String.valueOf(i).intern(), integers[i]);
89          }
90      }
91  
92      private static int maxLength(String[] a) {
93          int max = 0;
94          for (int i=a.length; --i>=0; ) {
95              String s = a[i];
96              if (s != null) {
97                  int len = s.length();
98                  if (len > max) {
99                      max = len;
100                 }
101             }
102         }
103         return max;
104     }
105 
106     private final WeakReference<Locale> iLocale;
107 
108     private final String[] iEras;
109     private final String[] iDaysOfWeek;
110     private final String[] iShortDaysOfWeek;
111     private final String[] iMonths;
112     private final String[] iShortMonths;
113     private final String[] iHalfday;
114 
115     private final TreeMap<String, Integer> iParseEras;
116     private final TreeMap<String, Integer> iParseDaysOfWeek;
117     private final TreeMap<String, Integer> iParseMonths;
118 
119     private final int iMaxEraLength;
120     private final int iMaxDayOfWeekLength;
121     private final int iMaxShortDayOfWeekLength;
122     private final int iMaxMonthLength;
123     private final int iMaxShortMonthLength;
124     private final int iMaxHalfdayLength;
125 
126     /**
127      * @param locale must not be null
128      */
129     private GJLocaleSymbols(Locale locale) {
130         iLocale = new WeakReference<Locale>(locale);
131         
132         DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(locale);
133         
134         iEras = dfs.getEras();
135         iDaysOfWeek = realignDaysOfWeek(dfs.getWeekdays());
136         iShortDaysOfWeek = realignDaysOfWeek(dfs.getShortWeekdays());
137         iMonths = realignMonths(dfs.getMonths());
138         iShortMonths = realignMonths(dfs.getShortMonths());
139         iHalfday = dfs.getAmPmStrings();
140 
141         Integer[] integers = new Integer[13];
142         for (int i=0; i<13; i++) {
143             integers[i] = Integer.valueOf(i);
144         }
145 
146         iParseEras = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
147         addSymbols(iParseEras, iEras, integers);
148         if ("en".equals(locale.getLanguage())) {
149             // Include support for parsing "BCE" and "CE" if the language is
150             // English. At some point Joda-Time will need an independent set of
151             // localized symbols and not depend on java.text.DateFormatSymbols.
152             iParseEras.put("BCE", integers[0]);
153             iParseEras.put("CE", integers[1]);
154         }
155 
156         iParseDaysOfWeek = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
157         addSymbols(iParseDaysOfWeek, iDaysOfWeek, integers);
158         addSymbols(iParseDaysOfWeek, iShortDaysOfWeek, integers);
159         addNumerals(iParseDaysOfWeek, 1, 7, integers);
160 
161         iParseMonths = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
162         addSymbols(iParseMonths, iMonths, integers);
163         addSymbols(iParseMonths, iShortMonths, integers);
164         addNumerals(iParseMonths, 1, 12, integers);
165 
166         iMaxEraLength = maxLength(iEras);
167         iMaxDayOfWeekLength = maxLength(iDaysOfWeek);
168         iMaxShortDayOfWeekLength = maxLength(iShortDaysOfWeek);
169         iMaxMonthLength = maxLength(iMonths);
170         iMaxShortMonthLength = maxLength(iShortMonths);
171         iMaxHalfdayLength = maxLength(iHalfday);
172     }
173 
174     public String eraValueToText(int value) {
175         return iEras[value];
176     }
177 
178     public int eraTextToValue(String text) {
179         Integer era = iParseEras.get(text);
180         if (era != null) {
181             return era.intValue();
182         }
183         throw new IllegalFieldValueException(DateTimeFieldType.era(), text);
184     }
185 
186     public int getEraMaxTextLength() {
187         return iMaxEraLength;
188     }
189 
190     public String monthOfYearValueToText(int value) {
191         return iMonths[value];
192     }
193 
194     public String monthOfYearValueToShortText(int value) {
195         return iShortMonths[value];
196     }
197 
198     public int monthOfYearTextToValue(String text) {
199         Integer month = iParseMonths.get(text);
200         if (month != null) {
201             return month.intValue();
202         }
203         throw new IllegalFieldValueException(DateTimeFieldType.monthOfYear(), text);
204     }
205 
206     public int getMonthMaxTextLength() {
207         return iMaxMonthLength;
208     }
209 
210     public int getMonthMaxShortTextLength() {
211         return iMaxShortMonthLength;
212     }
213 
214     public String dayOfWeekValueToText(int value) {
215         return iDaysOfWeek[value];
216     }
217 
218     public String dayOfWeekValueToShortText(int value) {
219         return iShortDaysOfWeek[value];
220     }
221 
222     public int dayOfWeekTextToValue(String text) {
223         Integer day = iParseDaysOfWeek.get(text);
224         if (day != null) {
225             return day.intValue();
226         }
227         throw new IllegalFieldValueException(DateTimeFieldType.dayOfWeek(), text);
228     }
229 
230     public int getDayOfWeekMaxTextLength() {
231         return iMaxDayOfWeekLength;
232     }
233 
234     public int getDayOfWeekMaxShortTextLength() {
235         return iMaxShortDayOfWeekLength;
236     }
237 
238     public String halfdayValueToText(int value) {
239         return iHalfday[value];
240     }
241 
242     public int halfdayTextToValue(String text) {
243         String[] halfday = iHalfday;
244         for (int i = halfday.length; --i>=0; ) {
245             if (halfday[i].equalsIgnoreCase(text)) {
246                 return i;
247             }
248         }
249         throw new IllegalFieldValueException(DateTimeFieldType.halfdayOfDay(), text);
250     }
251 
252     public int getHalfdayMaxTextLength() {
253         return iMaxHalfdayLength;
254     }
255 }