Package com.opengamma.core.security.impl

Source Code of com.opengamma.core.security.impl.NonVersionedRedisSecuritySource$GetWorker

/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.core.security.impl;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.fudgemsg.FudgeContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.base.Charsets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.change.ChangeManager;
import com.opengamma.core.change.DummyChangeManager;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
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.util.ArgumentChecker;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.fudgemsg.OpenGammaFudgeContext;
import com.opengamma.util.metric.MetricProducer;

/*
* REDIS DATA STRUCTURES:
* UniqueIds for each ExternalId:
*     Key["EXT-"ExternalId] -> Set[UniqueId]
* Data for a particular security by UniqueId:
*     Key["UNQ-"UniqueId] -> Hash
*       Hash["DATA"] -> Fudge encoded security document
*
* While this data structure is more than necessary (in that you could cut out the hash for
* the security data), it allows future expansion if more data is required to be stored
* later without reformatting the Redis instance.
*
*/

/**
* A lightweight {@link SecuritySource} that cannot handle any versioning, and
* which stores all Security documents as a Fudge-encoded BLOB in Redis as a
* backing store.
*/
public class NonVersionedRedisSecuritySource implements SecuritySource, MetricProducer {
  private static final Logger s_logger = LoggerFactory.getLogger(NonVersionedRedisSecuritySource.class);
  private final JedisPool _jedisPool;
  private final FudgeContext _fudgeContext;
  private final String _redisPrefix;
  private Timer _getTimer = new Timer();
  private Timer _putTimer = new Timer();
 
  private static final byte[] DATA_NAME_AS_BYTES = "DATA".getBytes(Charsets.UTF_8);
  private static final byte[] CLASS_NAME_AS_BYTES = "CLASS".getBytes(Charsets.UTF_8);
 
  /**
   * The default scheme for unique identifiers.
   */
  public static final String IDENTIFIER_SCHEME_DEFAULT = "RedisSec";
 
  public NonVersionedRedisSecuritySource(JedisPool jedisPool) {
    this(jedisPool, "");
  }
 
  public NonVersionedRedisSecuritySource(JedisPool jedisPool, String redisPrefix) {
    this(jedisPool, redisPrefix, OpenGammaFudgeContext.getInstance());
  }
 
  public NonVersionedRedisSecuritySource(JedisPool jedisPool, String redisPrefix, FudgeContext fudgeContext) {
    ArgumentChecker.notNull(jedisPool, "jedisPool");
    ArgumentChecker.notNull(redisPrefix, "redisPrefix");
    ArgumentChecker.notNull(fudgeContext, "fudgeContext");
   
    _jedisPool = jedisPool;
    _redisPrefix = redisPrefix;
    _fudgeContext = fudgeContext;
  }

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

  /**
   * Gets the fudgeContext.
   * @return the fudgeContext
   */
  protected FudgeContext getFudgeContext() {
    return _fudgeContext;
  }
 
  /**
   * Gets the redisPrefix.
   * @return the redisPrefix
   */
  protected String getRedisPrefix() {
    return _redisPrefix;
  }

  @Override
  public void registerMetrics(MetricRegistry summaryRegistry, MetricRegistry detailRegistry, String namePrefix) {
    _getTimer = summaryRegistry.timer(namePrefix + ".get");
    _putTimer = summaryRegistry.timer(namePrefix + ".put");
  }


  // ---------------------------------------------------------------------
  // REDIS KEY MANAGEMENT
  // ---------------------------------------------------------------------
 
  protected byte[] 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();
    byte[] bytes = keyText.getBytes(Charsets.UTF_8);
    return bytes;
  }
 
  protected byte[] toRedisKey(ObjectId objectId) {
    return toRedisKey(UniqueId.of(objectId, null));
  }
 
  protected String toRedisKey(ExternalId externalId) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append("EXT-");
    sb.append(externalId);
    return sb.toString();
  }
 
  // ---------------------------------------------------------------------
  // DATA SETTING/UPDATING OPERATIONS
  // UNIQUE TO THIS CLASS
  // ---------------------------------------------------------------------
 
  public UniqueId put(Security security) {
    ArgumentChecker.notNull(security, "security");
    //ArgumentChecker.notNull(security.getUniqueId(), "security uniqueId");
   
    UniqueId uniqueId = security.getUniqueId();
    if (uniqueId == null) {
      uniqueId = UniqueId.of(IDENTIFIER_SCHEME_DEFAULT, GUIDGenerator.generate().toString());
    }
    if (uniqueId.getVersion() != null) {
      uniqueId = UniqueId.of(uniqueId.getObjectId(), null);
    }
    if (security instanceof MutableUniqueIdentifiable) {
      MutableUniqueIdentifiable mutableSecurity = (MutableUniqueIdentifiable) security;
      mutableSecurity.setUniqueId(uniqueId);
    }
   
    try (Timer.Context context = _putTimer.time()) {
      byte[] securityData = SecurityFudgeUtil.convertToFudge(getFudgeContext(), security);

      Jedis jedis = getJedisPool().getResource();
      try {
       
        for (ExternalId externalId : security.getExternalIdBundle()) {
          String redisKey = toRedisKey(externalId);
         
          jedis.sadd(redisKey, uniqueId.toString());
          if (jedis.scard(redisKey) > 1) {
            s_logger.warn("Multiple securities with same ExternalId {}. Probable misuse.", externalId);
          }
        }
       
        byte[] redisKey = toRedisKey(uniqueId);
        jedis.hset(redisKey, DATA_NAME_AS_BYTES, securityData);
        jedis.hset(redisKey, CLASS_NAME_AS_BYTES, security.getClass().getName().getBytes(Charsets.UTF_8));
       
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to put security " + security, e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to put security " + security, e);
      }
     
    }
    return uniqueId;
  }
 
  // ---------------------------------------------------------------------
  // IMPLEMENTATION OF SECURITYSOURCE
  // ---------------------------------------------------------------------
 
  private interface GetWorker<T> {
    T query(Jedis jedis);
  }
 
  protected <T> T executeGet(GetWorker<T> getWorker) {
    try (Timer.Context context = _getTimer.time()) {
      Jedis jedis = getJedisPool().getResource();
     
      T result = null;
      try {
        result = getWorker.query(jedis);
        getJedisPool().returnResource(jedis);
      } catch (Exception e) {
        s_logger.error("Unable to execute get", e);
        getJedisPool().returnBrokenResource(jedis);
        throw new OpenGammaRuntimeException("Unable to execute get()", e);
      }
     
      return result;
    }
  }

  @Override
  public Collection<Security> get(ExternalIdBundle bundle, VersionCorrection versionCorrection) {
    return get(bundle);
  }

  @Override
  public Map<ExternalIdBundle, Collection<Security>> getAll(Collection<ExternalIdBundle> bundles, VersionCorrection versionCorrection) {
    Map<ExternalIdBundle, Collection<Security>> result = new HashMap<ExternalIdBundle, Collection<Security>>();
   
    for (ExternalIdBundle bundle : bundles) {
      result.put(bundle, get(bundle));
    }
   
    return result;
  }

  @Override
  public Collection<Security> get(ExternalIdBundle bundle) {
    Security security = getSingle(bundle);
    if (security == null) {
      return Collections.emptySet();
    } else {
      return Collections.singleton(security);
    }
  }

  @Override
  public Security getSingle(ExternalIdBundle bundle) {
    ArgumentChecker.notNull(bundle, "bundle");
   
    if (bundle.size() != 1) {
      s_logger.warn("Possible bad use of NonVersionedRedisSecuritySource: bundle size {} not equal to 1.", bundle);
    }
   
    final ExternalId externalId = bundle.iterator().next();
    Security result = executeGet(new GetWorker<Security>() {
      @Override
      public Security query(Jedis jedis) {
        Set<String> uniqueIds = jedis.smembers(toRedisKey(externalId));
        if (uniqueIds.isEmpty()) {
          return null;
        }
        if (uniqueIds.size() > 1) {
          s_logger.info("Following unique IDs for externalId {} : {}. Choosing randomly.", externalId, uniqueIds);
        }
        UniqueId uniqueId = UniqueId.parse(uniqueIds.iterator().next());
       
        return getInJedis(jedis, uniqueId);
      }
     
    });
    return result;
  }

  @Override
  public Security getSingle(ExternalIdBundle bundle, VersionCorrection versionCorrection) {
    return getSingle(bundle);
  }

  @Override
  public Map<ExternalIdBundle, Security> getSingle(Collection<ExternalIdBundle> bundles, VersionCorrection versionCorrection) {
    Map<ExternalIdBundle, Security> result = new HashMap<ExternalIdBundle, Security>();
   
    for (ExternalIdBundle bundle : bundles) {
      Security security = getSingle(bundle);
      result.put(bundle, security);
    }
   
    return result;
  }

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

    Security result = executeGet(new GetWorker<Security>() {
      public Security query(Jedis jedis) {
        return getInJedis(jedis, uniqueId);
      }
    });
    return result;
  }

  @Override
  public Security get(final ObjectId objectId, VersionCorrection versionCorrection) {
    ArgumentChecker.notNull(objectId, "objectId");

    Security result = executeGet(new GetWorker<Security>() {
      public Security query(Jedis jedis) {
        return getInJedis(jedis, UniqueId.of(objectId, null));
      }
    });
    return result;
  }

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

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

  @Override
  public ChangeManager changeManager() {
    return DummyChangeManager.INSTANCE;
  }
 
  protected Security getInJedis(Jedis jedis, UniqueId uniqueId) {
    byte[] redisKey = toRedisKey(uniqueId);
    byte[] securityData = jedis.hget(redisKey, DATA_NAME_AS_BYTES);
    byte[] classNameData = jedis.hget(redisKey, CLASS_NAME_AS_BYTES);
    if (securityData == null) {
      s_logger.warn("No data for security unique ID {}", uniqueId);
      return null;
    } else {
      String className = Charsets.UTF_8.decode(ByteBuffer.wrap(classNameData)).toString();
      Security security = null;
      try {
        security = SecurityFudgeUtil.convertFromFudge(getFudgeContext(), className, securityData);
      } catch (Exception ex) {
        s_logger.warn("Unable to convert from fudge for security unique ID " + uniqueId, ex);
      }
      return security;
    }
   
  }

}
TOP

Related Classes of com.opengamma.core.security.impl.NonVersionedRedisSecuritySource$GetWorker

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.