1 /*
2 * File: HolidayEnumeratorFactory.java
3 * Copyright (c) 2004-2007 Peter Kliem (Peter.Kliem@jaret.de)
4 * A commercial license is available, see http://www.jaret.de.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Common Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/cpl-v10.html
10 */
11 package de.jaret.util.date.holidayenumerator;
12
13 import java.lang.reflect.Constructor;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Locale;
18 import java.util.Map;
19 import java.util.StringTokenizer;
20
21 /**
22 * Factory for supplying a configured HolidayEnumerator. HolidayEnumerators are charcterized by a locale and an optional
23 * additional RegionID. The latter is used to differentiate regions in a country and should be used more finegrained
24 * than the Locale's variant.
25 * <p>
26 * This factory searches in the package de.jaret.util.date.holidayenumertor for classes named "HolidayEnumerator_"+
27 * locale string represenation (i.e. "de_DE"). They should have a no argument constructor or a constructor taking the
28 * regionId as an argument.
29 * </p>
30 *
31 * @author Peter Kliem
32 * @version $Id: HolidayEnumeratorFactory.java 293 2007-03-11 17:50:57Z olk $
33 */
34 public class HolidayEnumeratorFactory {
35 /** Basename for holiday enumerator implementations. */
36 private static final String BASENAME = "de.jaret.util.date.holidayenumerator.HolidayEnumerator_";
37
38 /** map for storing already instantiated HolidayEnumerators. */
39 private static Map<String, HolidayEnumerator> __enumerators = new HashMap<String, HolidayEnumerator>();
40
41 /**
42 * Supply a configured HolidayEnumerator for a locale and a RegionID. The RegionID is an addition to the locale
43 * concept, allowing differentiation beetween areas in a country.
44 *
45 * @param locale Locale for the HolidayEnumerator
46 * @param regionId optional RegionID. (may be <code>null</code>).
47 * @return configured HolidayEnumerator or <code>null</code> if no HolidayEnumerator is available for the
48 * specified locale.
49 */
50 public static HolidayEnumerator getHolidayEnumeratorInstance(Locale locale, String regionId) {
51 // try to find exact match
52 HolidayEnumerator he = __enumerators.get(getHolidayEnumeratorId(locale, regionId));
53 if (he != null) {
54 return he;
55 }
56 // not found: try to instantiate a HolidayEnumerator
57 he = instantiateHolidayEnumerator(locale, regionId);
58 if (he != null) {
59 __enumerators.put(getHolidayEnumeratorId(locale, regionId), he);
60 }
61 return he; // result may be null
62 }
63
64 /**
65 * Supply holidayenumerator for a combinated String of language and country (e.g. de_DE) and an optional regionID.
66 *
67 * @param languageAndCountry languag_country
68 * @param regionId optional region ID
69 * @return holidayenumerator or <code>null</code> if not available or arguments not valid
70 */
71 public static HolidayEnumerator getHolidayEnumeratorInstance(String languageAndCountry, String regionId) {
72 StringTokenizer tokenizer = new StringTokenizer(languageAndCountry, "_");
73 String language = null;
74 String country = null;
75 if (tokenizer.hasMoreTokens()) {
76 language = tokenizer.nextToken();
77 }
78 if (tokenizer.hasMoreTokens()) {
79 country = tokenizer.nextToken();
80 }
81 if (country == null || language == null) {
82 return null;
83 }
84
85 Locale locale = new Locale(language, country);
86 return getHolidayEnumeratorInstance(locale, regionId);
87 }
88
89 /**
90 * Construct an identifying String for locale and regionId.
91 *
92 * @param locale locale of the he
93 * @param regionId region id of the he or <code>null</code>
94 * @return concatenation of locae identifying string an regionId
95 */
96 private static String getHolidayEnumeratorId(Locale locale, String regionId) {
97 return locale.toString() + "_" + (regionId != null ? regionId : "");
98 }
99
100 /**
101 * Get the class of a holiday enumerator for a given locale.
102 *
103 * @param locale Locale to lokk for
104 * @return Class of HoliayEnumerator or null.
105 */
106 @SuppressWarnings("unchecked")
107 private static Class<? extends HolidayEnumerator> getHolidayEnumeratorClass(Locale locale) {
108 // classname
109 String classname = BASENAME + locale.toString();
110 Class<? extends HolidayEnumerator> clazz = null;
111 try {
112 clazz = (Class<? extends HolidayEnumerator>) Class.forName(classname);
113 } catch (Exception e) {
114 // class not found -> does not matter
115 }
116 return clazz;
117 }
118
119 /**
120 * Tries to instantiate a suitable HolidayEnumeraotor for the given parameters. May ignore the regionId.
121 *
122 * @param locale locale for the holiday enumerator
123 * @param regionId regionId for the he
124 * @return a HolidayEnumerator matching the parameters or null indicating no HolidayEnumerator could be
125 * instantiated.
126 */
127 private static HolidayEnumerator instantiateHolidayEnumerator(Locale locale, String regionId) {
128 Class<? extends HolidayEnumerator> clazz = getHolidayEnumeratorClass(locale);
129 if (clazz == null) {
130 // no he found
131 return null;
132 }
133 Constructor<? extends HolidayEnumerator> constructor;
134 // try constructing with regionID
135 try {
136 constructor = clazz.getConstructor(new Class[] {String.class});
137 HolidayEnumerator he = (HolidayEnumerator) constructor.newInstance(new Object[] {regionId});
138 return he;
139 } catch (Exception e) {
140 // ignore ... next try without parameters
141 }
142 // if not succesful up to here try constructing without reginId
143 try {
144 constructor = clazz.getConstructor(new Class[] {});
145 HolidayEnumerator he = (HolidayEnumerator) constructor.newInstance(new Object[] {});
146 return he;
147 } catch (Exception e) {
148 // not succesful -> will return null
149 }
150 return null;
151 }
152
153 /** available he locales. */
154 private static List<Locale> _availableHolidayEnumeratorLocales;
155
156 /**
157 * Retrieve the list of Locales for that HolidayEnumerators can be found. This operation tries to
158 * instantiate the holiday enumerators, so it is quite expensive the first time called.
159 *
160 * @return List of Locales.
161 */
162 public static List<Locale> getAvailableHolidayEnumeratorLocales() {
163 if (_availableHolidayEnumeratorLocales != null) {
164 return _availableHolidayEnumeratorLocales;
165 }
166 List<Locale> result = new ArrayList<Locale>();
167 Locale[] locales = Locale.getAvailableLocales();
168 for (int i = 0; i < locales.length; i++) {
169 if (getHolidayEnumeratorClass(locales[i]) != null) {
170 result.add(locales[i]);
171 }
172 }
173 _availableHolidayEnumeratorLocales = result;
174 return result;
175 }
176
177 }