Package com.opengamma.core.holiday.impl

Source Code of com.opengamma.core.holiday.impl.NonVersionedRedisHolidaySource

/**
* Copyright (C) 2013 - 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.HashMap;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.LocalDate;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.opengamma.OpenGammaRuntimeException;
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.MutableUniqueIdentifiable;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.timeseries.date.localdate.LocalDateToIntConverter;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.metric.MetricProducer;
import com.opengamma.util.money.Currency;

/*
* REDIS DATA STRUCTURES:
* Data structure for holiday metadata:
*     Key["UNQ-"UniqueId] -> Hash
*        Hash[REGION_SCHEME] -> Region Scheme
*        Hash[REGION] -> Region code
*        Hash[EXCHANGE_SCHEME] -> Exchange scheme
*        Hash[EXCHANGE] -> Exchange code
*        Hash[CURRENCY] -> ISO currency code
*        Hash[TYPE] -> HolidayType
* Data structure for holiday days themselves:
*     Key["UNQ-"UniqueId"-DAYS"] -> Sorted Set (days as ints)
*    
* Those give the core data, but we need search capabilities as well.
*
*     Key["EXT-"ExternalId"-TYPE-"HolidayType] -> Hash
*        Hash[UNIQUE_ID] -> UniqueId
*     Key["CUR-"currencyCode] -> Hash
*        Hash[UNIQUE_ID] -> UniqueId
*
* While this data structure is more than necessary (in that you could cut out the hash for
* the lookups), it allows future expansion if more data is required to be stored
* later without reformatting the Redis instance.
*/

/**
* A lightweight {@link HolidaySource} that cannot handle any versioning, and
* which stores all Holiday documents as individual Redis elements using direct
* Redis types rather than Fudge encoding.
*/
public class NonVersionedRedisHolidaySource implements HolidaySource, MetricProducer {
  private static final Logger s_logger = LoggerFactory.getLogger(NonVersionedRedisHolidaySource.class);
  private static final String EXCHANGE = "EXCHANGE";
  private static final String EXCHANGE_SCHEME = "EXCHANGE_SCHEME";
  /** Currency key */
  public static final String CURRENCY = "CURRENCY";
  /** Type key */
  public static final String TYPE = "TYPE";
  /** UniqueId key */
  public static final String UNIQUE_ID = "UNIQUE_ID";
  /** Region value key */
  public static final String REGION = "REGION";
  /** Region scheme key */
  public static final String REGION_SCHEME = "REGION_SCHEME";
  /** The default scheme for unique identifiers. */
  public static final String IDENTIFIER_SCHEME_DEFAULT = "RedisHol";
 
  private final JedisPool _jedisPool;
  private final String _redisPrefix;
  private Timer _getTimer = new Timer();
  private Timer _putTimer = new Timer();
  private Timer _isHolidayTimer = new Timer();
 

  public NonVersionedRedisHolidaySource(JedisPool jedisPool) {
    this(jedisPool, "");
  }
 
  public NonVersionedRedisHolidaySource(JedisPool jedisPool, String redisPrefix) {
    ArgumentChecker.notNull(jedisPool, "jedisPool");
    ArgumentChecker.notNull(redisPrefix, "redisPrefix");
   
    _jedisPool = jedisPool;
    _redisPrefix = redisPrefix;
  }
 
  @Override
  public void registerMetrics(MetricRegistry summaryRegistry, MetricRegistry detailRegistry, String namePrefix) {
    _getTimer = summaryRegistry.timer(namePrefix + ".get");
    _putTimer = summaryRegistry.timer(namePrefix + ".put");
    _isHolidayTimer = summaryRegistry.timer(namePrefix + ".isHoliday");
  }

  /**
   * Gets the jedisPool.
   * @return the jedisPool
   */
  public JedisPool getJedisPool() {
    return _jedisPool;
  }

  /**
   * Gets the redisPrefix.
   * @return the redisPrefix
   */
  public String getRedisPrefix() {
    return _redisPrefix;
  }

  // ---------------------------------------------------------------------
  // REDIS KEY MANAGEMENT
  // ---------------------------------------------------------------------
 
  public String toRedisKey(UniqueId uniqueId) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append("UNQ-");
    sb.append(uniqueId);
    String keyText = sb.toString();
    return keyText;
  }
 
  protected String toRedisKey(ObjectId objectId) {
    return toRedisKey(UniqueId.of(objectId, null));
  }
 
  public String toRedisKey(ExternalId externalId, HolidayType holidayType) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append("EXT-");
    sb.append(externalId);
    sb.append("-");
    sb.append(holidayType.name());
    return sb.toString();
  }
 
  private String toRedisKey(Currency currency) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append("CUR-");
    sb.append(currency.getCode());
    return sb.toString();
  }
 
 
  // ---------------------------------------------------------------------
  // DATA MANIPULATION
  // ---------------------------------------------------------------------
 
  /**
   * Add a fully manifested holiday.
   * Where the holiday has been loaded from a file or another source, this is
   * a bulk operation.
   *
   * @param holiday The holiday to be added.
   */
  public void addHoliday(Holiday holiday) {
    ArgumentChecker.notNull(holiday, "holiday");
   
    UniqueId uniqueId = (holiday.getUniqueId() == null) ? generateUniqueId() : holiday.getUniqueId();
    if (holiday instanceof MutableUniqueIdentifiable) {
      ((MutableUniqueIdentifiable) holiday).setUniqueId(uniqueId);
    }
    try (Timer.Context context = _putTimer.time()) {
      Jedis jedis = getJedisPool().getResource();
      try {
        String uniqueRedisKey = toRedisKey(uniqueId);
        String daysKey = uniqueRedisKey + "-DAYS";
        jedis.del(uniqueRedisKey, daysKey);
        jedis.hset(uniqueRedisKey, TYPE, holiday.getType().toString());
        if (holiday.getCurrency() != null) {
          jedis.hset(uniqueRedisKey, CURRENCY, holiday.getCurrency().getCode());
          jedis.hset(toRedisKey(holiday.getCurrency()), UNIQUE_ID, uniqueId.toString());
        }
        if (holiday.getRegionExternalId() != null) {
          jedis.hset(uniqueRedisKey, REGION_SCHEME, holiday.getRegionExternalId().getScheme().getName());
          jedis.hset(uniqueRedisKey, REGION, holiday.getRegionExternalId().getValue());
          jedis.hset(toRedisKey(holiday.getRegionExternalId(), holiday.getType()), UNIQUE_ID, uniqueId.toString());
        }
        if (holiday.getExchangeExternalId() != null) {
          jedis.hset(uniqueRedisKey, EXCHANGE_SCHEME, holiday.getExchangeExternalId().getScheme().getName());
          jedis.hset(uniqueRedisKey, EXCHANGE, holiday.getExchangeExternalId().getValue());
          jedis.hset(toRedisKey(holiday.getExchangeExternalId(), holiday.getType()), UNIQUE_ID, uniqueId.toString());
        }
       
        for (LocalDate holidayDate : holiday.getHolidayDates()) {
          jedis.zadd(daysKey, LocalDateToIntConverter.convertToInt(holidayDate), holidayDate.toString());
        }
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to add holiday " + holiday, e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to add holiday " + holiday, e);
      }
    }
  }
 
  private UniqueId generateUniqueId() {
    return UniqueId.of(IDENTIFIER_SCHEME_DEFAULT, GUIDGenerator.generate().toString());
  }

  // ---------------------------------------------------------------------
  // IMPLEMENTATION OF HOLIDAY SOURCE
  // ---------------------------------------------------------------------
 
  /**
   * @param days
   * @param simpleHoliday
   */
  private void convertDaysToLocalDates(Set<String> days, SimpleHoliday simpleHoliday) {
    for (String dayText : days) {
      LocalDate localDate = LocalDate.parse(dayText);
      simpleHoliday.addHolidayDate(localDate);
    }
  }

  @Override
  public Holiday get(UniqueId uniqueId) {
    ArgumentChecker.notNull(uniqueId, "uniqueId");

    Holiday result = null;
    try (Timer.Context context = _getTimer.time()) {
      Jedis jedis = getJedisPool().getResource();
      try {
        result = loadFromRedis(jedis, uniqueId);
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to load holiday " + uniqueId, e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to load holiday " + uniqueId, e);
      }
    }
    return result;
  }
 
  protected Holiday loadFromRedis(Jedis jedis, UniqueId uniqueId) {
    String uniqueRedisKey = toRedisKey(uniqueId);
    String daysKey = uniqueRedisKey + "-DAYS";
    Map<String, String> hashValues = jedis.hgetAll(uniqueRedisKey);
    Set<String> days = jedis.zrange(daysKey, 0, -1);
   
    if ((hashValues != null) && !hashValues.isEmpty()) {
      SimpleHoliday simpleHoliday = new SimpleHoliday();
     
      simpleHoliday.setUniqueId(uniqueId);
      if (hashValues.containsKey(EXCHANGE_SCHEME)) {
        simpleHoliday.setExchangeExternalId(ExternalId.of(hashValues.get(EXCHANGE_SCHEME), hashValues.get(EXCHANGE)));
      }
      if (hashValues.containsKey(REGION_SCHEME)) {
        simpleHoliday.setRegionExternalId(ExternalId.of(hashValues.get(REGION_SCHEME), hashValues.get(REGION)));
      }
      if (hashValues.containsKey(CURRENCY)) {
        simpleHoliday.setCurrency(Currency.of(hashValues.get(CURRENCY)));
      }
      simpleHoliday.setType(HolidayType.valueOf(hashValues.get(TYPE)));
      convertDaysToLocalDates(days, simpleHoliday);
     
      return simpleHoliday;
    }
    return null;
  }

  @Override
  public Holiday get(ObjectId objectId, VersionCorrection versionCorrection) {
    UniqueId uniqueId = UniqueId.of(objectId, null);
    return get(uniqueId);
  }

  @Override
  public Map<UniqueId, Holiday> get(Collection<UniqueId> uniqueIds) {
    Map<UniqueId, Holiday> result = new HashMap<UniqueId, Holiday>();
   
    for (UniqueId uniqueId : uniqueIds) {
      result.put(uniqueId, get(uniqueId));
    }
   
    return result;
  }

  @Override
  public Map<ObjectId, Holiday> get(Collection<ObjectId> objectIds, VersionCorrection versionCorrection) {
    Map<ObjectId, Holiday> result = new HashMap<ObjectId, Holiday>();
   
    for (ObjectId objectId : objectIds) {
      result.put(objectId, get(objectId, null));
    }
   
    return result;
  }

  @Override
  public boolean isHoliday(LocalDate dateToCheck, Currency currency) {
    ArgumentChecker.notNull(dateToCheck, "dateToCheck");
    ArgumentChecker.notNull(currency, "currency");
   
    boolean result = false;
   
    try (Timer.Context context = _isHolidayTimer.time()) {
      Jedis jedis = getJedisPool().getResource();
      try {
       
        String currencyIdKey = toRedisKey(currency);
        String uniqueId = jedis.hget(currencyIdKey, UNIQUE_ID);
        if (uniqueId != null) {
          String daysKey = toRedisKey(UniqueId.parse(uniqueId)) + "-DAYS";
          if (jedis.zscore(daysKey, dateToCheck.toString()) != null) {
            result = true;
          }
        }
       
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to check if holiday " + dateToCheck + " - " + currency, e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to check if holiday " + dateToCheck + " - " + currency, e);
      }
    }
   
    return result;
  }

  @Override
  public boolean isHoliday(LocalDate dateToCheck, HolidayType holidayType, ExternalIdBundle regionOrExchangeIds) {
    // Any is the only supported type underneath, so we use the same logic.
    ArgumentChecker.notNull(dateToCheck, "dateToCheck");
    ArgumentChecker.notNull(holidayType, "holidayType");
    ArgumentChecker.notNull(regionOrExchangeIds, "regionOrExchangeIds");
   
    boolean foundHoliday = false;
    boolean result = false;
   
    try (Timer.Context context = _isHolidayTimer.time()) {
      Jedis jedis = getJedisPool().getResource();
      try {
        for (ExternalId externalId : regionOrExchangeIds) {
          String uniqueIdText = jedis.hget(toRedisKey(externalId, holidayType), UNIQUE_ID);
          if (uniqueIdText == null) {
            continue;
          }
          UniqueId uniqueId = UniqueId.parse(uniqueIdText);
          String uniqueIdKey = toRedisKey(uniqueId);
          Map<String, String> hash = jedis.hgetAll(uniqueIdKey);
          if (holidayType.name().equals(hash.get(TYPE))) {
            foundHoliday = true;
            String daysKey = uniqueIdKey + "-DAYS";
            if (jedis.zscore(daysKey, dateToCheck.toString()) != null) {
              result = true;
            }
            break;
          }
        }
       
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to check if holiday " + dateToCheck + " - " + holidayType + " - " + regionOrExchangeIds, e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to check if holiday " + dateToCheck + " - " + holidayType + " - " + regionOrExchangeIds, e);
      }
    }
   
    // NOTE kirk 2013-06-05 -- The whole use of foundHoliday is basically to make it easy
    // to set a breakpoint inside the block below so that you can tell the difference in a debugger
    // between the two cases: one where you've actually found the holiday entry and you know
    // definitively whether it's a holiday, and one where you haven't so you really don't know.
    if (foundHoliday) {
      return result;
    }
   
    return false;
  }

  @Override
  public boolean isHoliday(LocalDate dateToCheck, HolidayType holidayType, ExternalId regionOrExchangeId) {
    return isHoliday(dateToCheck, holidayType, ExternalIdBundle.of(regionOrExchangeId));
  }
 
}
TOP

Related Classes of com.opengamma.core.holiday.impl.NonVersionedRedisHolidaySource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.