/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.convention.calendar; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.ResourceBundle; import org.joda.convert.FromString; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.financial.convention.AbstractNamedInstanceFactory; /** * Factory to obtain instances of {@code Calendar}. * <p> * The holidays and country details are read from a properties file. */ public final class CalendarFactory extends AbstractNamedInstanceFactory<Calendar> { // REVIEW: This is really quite a bad implementation. Bank Holiday dates need to be pulled // from a database or a more easily updated source. It should probably be possible // to update the data with the system running instead of at initialization. // emcleod 20-8-2013 This factory is only used in testing, so can probably be safely // deleted /** * Singleton instance. */ public static final CalendarFactory INSTANCE = new CalendarFactory(); /** * Map of calendar by country. */ private final Map<String, Calendar> _countryMap = new HashMap<>(); //------------------------------------------------------------------------- /** * Finds a convention by name, ignoring case. * * @param name the name of the instance to find, not null * @return the convention, not null * @throws IllegalArgumentException if the name is not found */ @FromString public static Calendar of(final String name) { return INSTANCE.instance(name); } //------------------------------------------------------------------------- /** * Restricted constructor, loading the properties file. */ private CalendarFactory() { super(Calendar.class); loadCalendarInstances(); loadCountryDefinitions(); } private void loadCalendarInstances() { final ResourceBundle calendars = ResourceBundle.getBundle(Calendar.class.getName()); for (final String calendarName : calendars.keySet()) { try { String uri = null; String clazzName = calendars.getString(calendarName); if (clazzName.indexOf(':') > 0) { uri = clazzName.substring(clazzName.indexOf(':') + 1); final URL url = getClass().getClassLoader().getResource(uri); if (url != null) { uri = url.toString(); } clazzName = clazzName.substring(0, clazzName.indexOf(':')); } final Class<? extends Calendar> clazz = Class.forName(clazzName).asSubclass(Calendar.class); final Constructor<?>[] constructors = clazz.getDeclaredConstructors(); int noArgConstructor = -1; int nameConstructor = -1; int nameURIConstructor = -1; for (int i = 0; i < constructors.length; i++) { final Class<?>[] params = constructors[i].getParameterTypes(); if (params.length == 0) { noArgConstructor = i; } else if (params.length == 1) { if (params[0].equals(String.class)) { nameConstructor = i; } } else if (params.length == 2) { if (params[0].equals(String.class) && params[1].equals(String.class)) { nameURIConstructor = i; } } } Calendar instance; if ((uri != null) && (nameURIConstructor >= 0)) { instance = (Calendar) constructors[nameURIConstructor].newInstance(calendarName, uri); } else if (nameConstructor >= 0) { instance = (Calendar) constructors[nameConstructor].newInstance(calendarName); } else if (noArgConstructor >= 0) { instance = (Calendar) constructors[noArgConstructor].newInstance(); } else { throw new OpenGammaRuntimeException("No suitable constructor for '" + calendarName + "'"); } addInstance(instance); } catch (final InstantiationException ex) { throw new OpenGammaRuntimeException("Error initialising Calendars", ex); } catch (final IllegalAccessException ex) { throw new OpenGammaRuntimeException("Error initialising Calendars", ex); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Error initialising Calendars", ex); } catch (final IllegalArgumentException ex) { throw new OpenGammaRuntimeException("Error initialising Calendars", ex); } catch (final InvocationTargetException ex) { throw new OpenGammaRuntimeException("Error initialising Calendars", ex); } } } private void loadCountryDefinitions() { final ResourceBundle countries = ResourceBundle.getBundle("com.opengamma.financial.convention.calendar.Country"); for (final String countryCode : countries.keySet()) { final String calendarName = countries.getString(countryCode); try { final Calendar calendar = instance(calendarName); _countryMap.put(countryCode, calendar); } catch (RuntimeException ex) { throw new OpenGammaRuntimeException("Cannot find calendar '" + calendarName + "' for country '" + countryCode + "'"); } } } // ------------------------------------------------------------------------- /** * Gets a working day calendar by name. * Matching is case insensitive. * * @param name the name, not null * @return the convention, null if not found * @deprecated Use {@link #of(String)} or {@link #instance(String)}. */ @Deprecated public Calendar getCalendar(final String name) { try { return instance(name); } catch (IllegalArgumentException ex) { return null; } } /** * Gets a working day calendar by 3-letter country code. * * @param country the country code, not null * @return the convention, null if not found */ public Calendar getCalendarByCountry(final String country) { return _countryMap.get(country); } }