Package com.opengamma.core.config.impl

Source Code of com.opengamma.core.config.impl.NonVersionedRedisConfigSource

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

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.fudgemsg.FudgeContext;
import org.fudgemsg.mapping.FudgeObjectReader;
import org.fudgemsg.mapping.FudgeObjectWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

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.config.ConfigSource;
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;

/*
* REDIS DATA STRUCTURES:
* Key["ALL_CLASSES"] -> Set[ClassName]
* Key[ClassName] -> Set[ConfigName]
* Key[ClassName - ConfigName] -> Hash
*     Hash["UniqueId"] -> Text-encoded unique ID for the object
* Key[UniqueId] -> Hash
*     Hash["DATA"] -> Fudge encoded configuration data
*     Hash["CLASS"] -> Class name for the item
*     Hash["NAME"] -> Item name for the item
*
* While this data structure is more than necessary (in that you could cut out the hash for
* the configuration item), it allows future expansion if more data is required to be stored
* later without reformatting the Redis instance.
*
*/


/**
* A lightweight {@link ConfigSource} that cannot handle any versioning, and
* which stores all configuration documents as a Fudge-encoded BLOB in Redis as a
* backing store.
*/
public class NonVersionedRedisConfigSource implements ConfigSource {
  private static final Logger s_logger = LoggerFactory.getLogger(NonVersionedRedisConfigSource.class);
  private final JedisPool _jedisPool;
  private final FudgeContext _fudgeContext;
  private final String _redisPrefix;
  private final String _allClassesKey;
 
  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);
  private static final byte[] ITEM_NAME_AS_BYTES = "ITEM".getBytes(Charsets.UTF_8);
 
  /**
   * The default scheme for unique identifiers.
   */
  public static final String IDENTIFIER_SCHEME_DEFAULT = "RedisCfg";

 
  public NonVersionedRedisConfigSource(JedisPool jedisPool) {
    this(jedisPool, "");
  }
 
  public NonVersionedRedisConfigSource(JedisPool jedisPool, String redisPrefix) {
    this(jedisPool, redisPrefix, OpenGammaFudgeContext.getInstance());
  }
 
  public NonVersionedRedisConfigSource(JedisPool jedisPool, String redisPrefix, FudgeContext fudgeContext) {
    ArgumentChecker.notNull(jedisPool, "jedisPool");
    ArgumentChecker.notNull(redisPrefix, "redisPrefix");
    ArgumentChecker.notNull(fudgeContext, "fudgeContext");
   
    _jedisPool = jedisPool;
    _redisPrefix = redisPrefix;
    _fudgeContext = fudgeContext;
   
    String allClassesKey = null;
    if (redisPrefix.isEmpty()) {
      allClassesKey = "ALL_CLASSES";
    } else {
      allClassesKey = redisPrefix + "-" + "ALL_CLASSES";
    }
    _allClassesKey = allClassesKey;
  }

  /**
   * 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;
  }

  // ---------------------------------------------------------------------
  // REDIS UTILITIES AND KEY MANAGEMENT
  // ---------------------------------------------------------------------
 
  protected <R> String getClassKeyName(Class<R> clazz) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append(clazz.getName());
    return sb.toString();
  }
 
  protected <R> String getClassNameRedisKey(Class<R> clazz, String configName) {
    StringBuilder sb = new StringBuilder();
    sb.append(getClassKeyName(clazz));
    sb.append('-');
    sb.append(configName);
    String hashKeyName = sb.toString();
    return hashKeyName;
  }
 
  private byte[] getUniqueIdKey(UniqueId uniqueId) {
    StringBuilder sb = new StringBuilder();
    if (!getRedisPrefix().isEmpty()) {
      sb.append(getRedisPrefix());
      sb.append("-");
    }
    sb.append(uniqueId);
    String text = sb.toString();
    byte[] bytes = text.getBytes(Charsets.UTF_8);
    return bytes;
  }

  protected <R> R convertBytesToConfigurationObject(Class<R> clazz, byte[] dataAsBytes) {
    FudgeObjectReader objectReader = getFudgeContext().createObjectReader(new ByteArrayInputStream(dataAsBytes));
    R object = objectReader.read(clazz);
    return object;
  }
 
  // ---------------------------------------------------------------------
  // DATA SETTING/UPDATING OPERATIONS
  // UNIQUE TO THIS CLASS
  // ---------------------------------------------------------------------
 
  public <R> UniqueId put(Class<R> clazz, String configName, R object) {
    ArgumentChecker.notNull(clazz, "clazz");
    ArgumentChecker.notNull(configName, "configName");
    ArgumentChecker.notNull(object, "object");
    ArgumentChecker.isTrue(clazz.isAssignableFrom(object.getClass()), "Unable to assign " + object.getClass() + " to " + clazz);
   
    UniqueId uniqueId = UniqueId.of(IDENTIFIER_SCHEME_DEFAULT, GUIDGenerator.generate().toString());
   
    if (object instanceof MutableUniqueIdentifiable) {
      MutableUniqueIdentifiable identifiable = (MutableUniqueIdentifiable) object;
      identifiable.setUniqueId(uniqueId);
    }
   
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    FudgeObjectWriter objectWriter = getFudgeContext().createObjectWriter(baos);
    objectWriter.write(object);
    byte[] objectAsBytes = baos.toByteArray();
   
    String classKeyName = getClassKeyName(clazz);
    String classNameRedisKey = getClassNameRedisKey(clazz, configName);
    byte[] uniqueIdKey = getUniqueIdKey(uniqueId);
   
    Jedis jedis = getJedisPool().getResource();
    try {
      jedis.sadd(_allClassesKey, clazz.getName());
      jedis.sadd(classKeyName, configName);
      jedis.hset(classNameRedisKey, "UniqueId", uniqueId.toString());
      jedis.hset(uniqueIdKey, DATA_NAME_AS_BYTES, objectAsBytes);
      jedis.hset(uniqueIdKey, CLASS_NAME_AS_BYTES, clazz.getName().getBytes(Charsets.UTF_8));
      jedis.hset(uniqueIdKey, ITEM_NAME_AS_BYTES, configName.getBytes(Charsets.UTF_8));
     
      getJedisPool().returnResource(jedis);
    } catch (Exception e) {
      s_logger.warn("Unable to persist to Redis - " + clazz + " - " + configName, e);
      getJedisPool().returnBrokenResource(jedis);
      throw new OpenGammaRuntimeException("Unable to persist to Redis - " + clazz + " - " + configName, e);
    }
    return uniqueId;
  }
 
  public <R> void delete(Class<R> clazz, String configName) {
    ArgumentChecker.notNull(clazz, "clazz");
    ArgumentChecker.notNull(configName, "configName");
   
    String classKeyName = getClassKeyName(clazz);
    String classNameRedisKey = getClassNameRedisKey(clazz, configName);

    Jedis jedis = getJedisPool().getResource();
    try {
     
      jedis.srem(classKeyName, configName);
      String uniqueIdText = jedis.hget(classNameRedisKey, "UniqueId");
      if (uniqueIdText != null) {
        UniqueId uniqueId = UniqueId.parse(uniqueIdText);
        byte[] uniqueIdKey = getUniqueIdKey(uniqueId);
        jedis.del(uniqueIdKey);
      }
      jedis.del(classNameRedisKey);
     
      getJedisPool().returnResource(jedis);
    } catch (Exception e) {
      s_logger.warn("Unable to delete from Redis - " + clazz + " - " + configName, e);
      getJedisPool().returnBrokenResource(jedis);
      throw new OpenGammaRuntimeException("Unable to persist from Redis - " + clazz + " - " + configName, e);
    }
  }
 
  // ---------------------------------------------------------------------
  // CORE IMPLEMENTED METHODS ON CONFIGSOURCE
  // ---------------------------------------------------------------------
 
  @Override
  public <R> Collection<ConfigItem<R>> get(Class<R> clazz, String configName, VersionCorrection versionCorrection) {
    R latest = getLatestByName(clazz, configName);
    ConfigItem<R> configItem = ConfigItem.of(latest);
    configItem.setName(configName);
    // REVIEW kirk 2013-06-03 -- Do we need to do any more to the config item?
    return Collections.singleton(configItem);
  }

  @Override
  public <R> Collection<ConfigItem<R>> getAll(Class<R> clazz, VersionCorrection versionCorrection) {
    ArgumentChecker.notNull(clazz, "clazz");
   
    String classKeyName = getClassKeyName(clazz);
   
    List<ConfigItem<R>> items = new LinkedList<ConfigItem<R>>();
   
    Jedis jedis = getJedisPool().getResource();
    try {
     
      Set<String> itemNames = jedis.smembers(classKeyName);
     
      for (String itemName : itemNames) {
        String classNameRedisKey = getClassNameRedisKey(clazz, itemName);
        String uniqueIdText = jedis.hget(classNameRedisKey, "UniqueId");
        if (uniqueIdText != null) {
          UniqueId uniqueId = UniqueId.parse(uniqueIdText);
          byte[] uniqueIdKey = getUniqueIdKey(uniqueId);
          byte[] dataAsBytes = jedis.hget(uniqueIdKey, DATA_NAME_AS_BYTES);
          R config = convertBytesToConfigurationObject(clazz, dataAsBytes);
          ConfigItem<R> configItem = ConfigItem.of(config);
          configItem.setName(itemName);
          configItem.setType(clazz);
          configItem.setUniqueId(uniqueId);
          items.add(configItem);
        }
      }
     
      getJedisPool().returnResource(jedis);
    } catch (Exception e) {
      s_logger.warn("Unable to lookup from Redis - " + clazz, e);
      getJedisPool().returnBrokenResource(jedis);
      throw new OpenGammaRuntimeException("Unable to lookup from Redis - " + clazz, e);
    }
   
    return items;
  }

  @Override
  public <R> R getSingle(Class<R> clazz, String configName, VersionCorrection versionCorrection) {
    return getLatestByName(clazz, configName);
  }

  @Override
  public <R> R getLatestByName(Class<R> clazz, String configName) {
    ConfigItem<R> latestItem = getLatestItemByName(clazz, configName);
    if (latestItem == null) {
      return null;
    }
    return latestItem.getValue();
  }
 
  public <R> ConfigItem<R> getLatestItemByName(Class<R> clazz, String configName) {
    ArgumentChecker.notNull(clazz, "clazz");
    ArgumentChecker.notNull(configName, "configName");
   
    String classKeyName = getClassKeyName(clazz);
    String classNameRedisKey = getClassNameRedisKey(clazz, configName);
   
    byte[] dataAsBytes = null;
    UniqueId uniqueId = null;
   
    Jedis jedis = getJedisPool().getResource();
    try {
      if (jedis.sismember(classKeyName, configName)) {
        String uniqueIdText = jedis.hget(classNameRedisKey, "UniqueId");
        if (uniqueIdText != null) {
          uniqueId = UniqueId.parse(uniqueIdText);
          byte[] uniqueIdKey = getUniqueIdKey(uniqueId);
          dataAsBytes = jedis.hget(uniqueIdKey, DATA_NAME_AS_BYTES);
        }
      } else {
        s_logger.debug("No config named {} for class {}", configName, clazz);
      }
     
      getJedisPool().returnResource(jedis);
    } catch (Exception e) {
      s_logger.warn("Unable to lookup latest by name from Redis - " + clazz + " - " + configName, e);
      getJedisPool().returnBrokenResource(jedis);
      throw new OpenGammaRuntimeException("Unable to lookup latest by name from Redis - " + clazz + " - " + configName, e);
    }
   
    if (dataAsBytes == null) {
      s_logger.debug("No data for config named {} for class {}", configName, clazz);
      return null;
    }
   
    R config = convertBytesToConfigurationObject(clazz, dataAsBytes);
   
    ConfigItem<R> configItem = new ConfigItem<R>();
    configItem.setType(clazz);
    configItem.setValue(config);
    configItem.setUniqueId(uniqueId);
   
    return configItem;
  }
 
  // ---------------------------------------------------------------------
  // UNIQUE ID OPERATIONS
  // ---------------------------------------------------------------------
 

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

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

  @SuppressWarnings("unchecked")
  @Override
  public ConfigItem<?> get(UniqueId uniqueId) {
    ArgumentChecker.notNull(uniqueId, "uniqueId");
   
    byte[] uniqueIdKey = getUniqueIdKey(uniqueId);
    byte[] dataAsBytes = null;
    String className = null;
   
    Jedis jedis = getJedisPool().getResource();
    try {
      dataAsBytes = jedis.hget(uniqueIdKey, DATA_NAME_AS_BYTES);
      className = new String(jedis.hget(uniqueIdKey, CLASS_NAME_AS_BYTES), Charsets.UTF_8);
      getJedisPool().returnResource(jedis);
    } catch (Exception e) {
      s_logger.warn("Unable to lookup by unique id - " + uniqueId, e);
      getJedisPool().returnBrokenResource(jedis);
      throw new OpenGammaRuntimeException("Unable to lookup by unique id - " + uniqueId, e);
    }
   
    if (dataAsBytes == null) {
      return null;
    }
   
    Class<?> clazz;
    try {
      clazz = Class.forName(className);
    } catch (ClassNotFoundException ex) {
      s_logger.warn("Found config item of type {} which we can't load.", className);
      return null;
    }
   
    Object config = convertBytesToConfigurationObject(clazz, dataAsBytes);
   
    @SuppressWarnings("rawtypes")
    ConfigItem configItem = new ConfigItem();
    configItem.setType(clazz);
    configItem.setValue(config);
    configItem.setUniqueId(uniqueId);
   
    return configItem;
  }

  @Override
  public ConfigItem<?> get(ObjectId objectId, VersionCorrection versionCorrection) {
    return get(UniqueId.of(objectId, null));
  }

  @SuppressWarnings("unchecked")
  @Override
  public <R> R getConfig(Class<R> clazz, UniqueId uniqueId) {
    ConfigItem<?> configItem = get(uniqueId);
    if (configItem == null) {
      return null;
    }
    return (R) configItem.getValue();
  }

  @SuppressWarnings("unchecked")
  @Override
  public <R> R getConfig(Class<R> clazz, ObjectId objectId, VersionCorrection versionCorrection) {
    ConfigItem<?> configItem = get(UniqueId.of(objectId, null));
    if (configItem == null) {
      return null;
    }
    return (R) configItem.getValue();
  }

  @Override
  public ChangeManager changeManager() {
    return DummyChangeManager.INSTANCE;
  }

}
TOP

Related Classes of com.opengamma.core.config.impl.NonVersionedRedisConfigSource

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.