View Javadoc

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 }