/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.core.holiday.impl; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.threeten.bp.LocalDate; import com.opengamma.core.AbstractSource; import com.opengamma.core.holiday.Holiday; import com.opengamma.core.holiday.HolidaySource; import com.opengamma.core.holiday.HolidayType; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.id.ObjectId; import com.opengamma.id.UniqueId; import com.opengamma.id.VersionCorrection; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.map.HashMap2; import com.opengamma.util.map.HashMap3; import com.opengamma.util.map.Map2; import com.opengamma.util.map.Map3; import com.opengamma.util.money.Currency; /** * A cached {@link HolidaySource} using a concurrent hash map and * no eviction policy. This is better than having no cache but is * not very efficient. Also does not listen for changes to the underlying * data. */ public class CachedHolidaySource extends AbstractSource<Holiday> implements HolidaySource { private static final Object NULL = new Object(); private final HolidaySource _underlying; private final ConcurrentMap<UniqueId, Object> _getHoliday1 = new ConcurrentHashMap<>(); private final Map2<VersionCorrection, ObjectId, Object> _getHoliday2 = new HashMap2<>(HashMap2.WEAK_KEYS); private final ConcurrentMap<Currency, Object> _getHoliday3 = new ConcurrentHashMap<>(); private final Map2<HolidayType, ExternalIdBundle, Object> _getHoliday4 = new HashMap2<>(HashMap2.WEAK_KEYS); private final ConcurrentMap<Currency, ConcurrentMap<LocalDate, Object>> _isHoliday1 = new ConcurrentHashMap<>(); private final Map3<LocalDate, HolidayType, ExternalIdBundle, Object> _isHoliday2 = new HashMap3<>(); private final Map3<LocalDate, HolidayType, ExternalId, Object> _isHoliday3 = new HashMap3<>(); public CachedHolidaySource(final HolidaySource underlying) { ArgumentChecker.notNull(underlying, "underlying"); _underlying = underlying; } protected HolidaySource getUnderlying() { return _underlying; } @SuppressWarnings("unchecked") protected <T> T getOrThrow(final Object o) { if (o instanceof RuntimeException) { throw (RuntimeException) o; } else if (o == NULL) { return null; } else { return (T) o; } } protected Object safeNull(final Object o) { if (o != null) { return o; } else { return NULL; } } @Override public Holiday get(final UniqueId uniqueId) { Object result = _getHoliday1.get(uniqueId); if (result != null) { return getOrThrow(result); } try { final Holiday h = getUnderlying().get(uniqueId); result = _getHoliday1.putIfAbsent(uniqueId, safeNull(h)); if (result != null) { return getOrThrow(result); } return h; } catch (RuntimeException ex) { _getHoliday1.putIfAbsent(uniqueId, ex); throw ex; } } @Override public Holiday get(final ObjectId objectId, final VersionCorrection versionCorrection) { Object result = _getHoliday2.get(versionCorrection, objectId); if (result != null) { return getOrThrow(result); } try { final Holiday h = getUnderlying().get(objectId, versionCorrection); result = _getHoliday2.putIfAbsent(versionCorrection, objectId, safeNull(h)); if (result != null) { return getOrThrow(result); } return h; } catch (RuntimeException ex) { _getHoliday2.putIfAbsent(versionCorrection, objectId, ex); throw ex; } } @Override public Collection<Holiday> get(Currency currency) { Object result = _getHoliday3.get(currency); if (result != null) { return getOrThrow(result); } try { Collection<Holiday> holidays = getUnderlying().get(currency); result = _getHoliday3.putIfAbsent(currency, holidays); if (result != null) { return getOrThrow(result); } else { return holidays; } } catch (RuntimeException ex) { _getHoliday3.putIfAbsent(currency, ex); throw ex; } } @Override public Collection<Holiday> get(HolidayType holidayType, ExternalIdBundle regionOrExchangeIds) { Object result = _getHoliday4.get(holidayType, regionOrExchangeIds); if (result != null) { return getOrThrow(result); } try { Collection<Holiday> holidays = getUnderlying().get(holidayType, regionOrExchangeIds); result = _getHoliday4.putIfAbsent(holidayType, regionOrExchangeIds, safeNull(holidays)); if (result != null) { return getOrThrow(result); } else { return holidays; } } catch (RuntimeException ex) { _getHoliday4.putIfAbsent(holidayType, regionOrExchangeIds, ex); throw ex; } } @Override public boolean isHoliday(final LocalDate dateToCheck, final Currency currency) { ConcurrentMap<LocalDate, Object> dates = _isHoliday1.get(currency); if (dates == null) { dates = new ConcurrentHashMap<>(); final ConcurrentMap<LocalDate, Object> existing = _isHoliday1.putIfAbsent(currency, dates); if (existing != null) { dates = existing; } } Object result = dates.get(dateToCheck); if (result != null) { return (Boolean) getOrThrow(result); } try { final boolean isHoliday = getUnderlying().isHoliday(dateToCheck, currency); dates.putIfAbsent(dateToCheck, isHoliday); return isHoliday; } catch (RuntimeException ex) { dates.putIfAbsent(dateToCheck, ex); throw ex; } } @Override public boolean isHoliday(final LocalDate dateToCheck, final HolidayType holidayType, final ExternalIdBundle regionOrExchangeIds) { Object result = _isHoliday2.get(dateToCheck, holidayType, regionOrExchangeIds); if (result != null) { return (Boolean) getOrThrow(result); } try { final boolean isHoliday = getUnderlying().isHoliday(dateToCheck, holidayType, regionOrExchangeIds); _isHoliday2.putIfAbsent(dateToCheck, holidayType, regionOrExchangeIds, isHoliday); return isHoliday; } catch (RuntimeException ex) { _isHoliday2.putIfAbsent(dateToCheck, holidayType, regionOrExchangeIds, ex); throw ex; } } @Override public boolean isHoliday(final LocalDate dateToCheck, final HolidayType holidayType, final ExternalId regionOrExchangeId) { Object result = _isHoliday3.get(dateToCheck, holidayType, regionOrExchangeId); if (result != null) { return (Boolean) getOrThrow(result); } try { final boolean isHoliday = getUnderlying().isHoliday(dateToCheck, holidayType, regionOrExchangeId); _isHoliday3.putIfAbsent(dateToCheck, holidayType, regionOrExchangeId, isHoliday); return isHoliday; } catch (RuntimeException ex) { _isHoliday3.putIfAbsent(dateToCheck, holidayType, regionOrExchangeId, ex); throw ex; } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } CachedHolidaySource that = (CachedHolidaySource) o; if (!_underlying.equals(that._underlying)) { return false; } return true; } @Override public int hashCode() { return _underlying.hashCode(); } }