/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.livedata.server;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import com.opengamma.id.ExternalId;
/**
* An implemention of {@link LastKnownValueStoreProvider} which backs onto Redis.
* <p/>
* It has the following properties that should be set:
* <dl>
* <dt>server</dt>
* <dd>The hostname of the server that should be used. Defaults to localhost.</dd>
* <dt>port</dt>
* <dd>The redis port to connect to. Defaults to 6379.</dd>
* <dt>globalPrefix</dt>
* <dd>A string that will be prepended onto all keys to separate different uses on the same
* Redis cluster. Defaults to empty string, for unit testing should probably be set
* to user name.</dd>
* <dt>writeThrough</dt>
* <dd>Whether all writes should flow through to the underlying Redis store.
* Defaults to true.
* If there are multiple live data servers, only one of which is in charge
* of updating Redis, set this to false on all but the master updating
* version.</dd>
* </dl>
*
*/
public class RedisLastKnownValueStoreProvider implements LastKnownValueStoreProvider {
private static final Logger s_logger = LoggerFactory.getLogger(RedisLastKnownValueStoreProvider.class);
private String _server = "localhost";
private int _port = 6379;
private String _globalPrefix = "";
private boolean _writeThrough = true;
private volatile boolean _isInitialized;
private JedisPool _jedisPool;
/**
* Gets the server.
* @return the server
*/
public String getServer() {
return _server;
}
/**
* Sets the server.
* @param server the server
*/
public void setServer(String server) {
_server = server;
}
/**
* Gets the port.
* @return the port
*/
public int getPort() {
return _port;
}
/**
* Sets the port.
* @param port the port
*/
public void setPort(int port) {
_port = port;
}
/**
* Gets the globalPrefix.
* @return the globalPrefix
*/
public String getGlobalPrefix() {
return _globalPrefix;
}
/**
* Sets the globalPrefix.
* @param globalPrefix the globalPrefix
*/
public void setGlobalPrefix(String globalPrefix) {
_globalPrefix = globalPrefix;
}
/**
* Gets the writeThrough.
* @return the writeThrough
*/
public boolean isWriteThrough() {
return _writeThrough;
}
/**
* Sets the writeThrough.
* @param writeThrough the writeThrough
*/
public void setWriteThrough(boolean writeThrough) {
_writeThrough = writeThrough;
}
@Override
public LastKnownValueStore newInstance(ExternalId security, String normalizationRuleSetId) {
initIfNecessary();
String redisKey = generateRedisKey(security, normalizationRuleSetId);
s_logger.debug("Creating Redis LKV store on {}/{} with key name {}", new Object[] {security, normalizationRuleSetId, redisKey});
updateIdentifiers(security);
RedisLastKnownValueStore store = new RedisLastKnownValueStore(_jedisPool, redisKey, isWriteThrough());
return store;
}
/**
* @param security
* @param normalizationRuleSetId
* @return
*/
private String generateRedisKey(ExternalId security, String normalizationRuleSetId) {
StringBuilder sb = new StringBuilder();
if (getGlobalPrefix() != null) {
sb.append(getGlobalPrefix());
}
sb.append(security.getScheme().getName());
sb.append("-");
sb.append(security.getValue());
sb.append("[");
sb.append(normalizationRuleSetId);
sb.append("]");
return sb.toString();
}
private String generateAllSchemesKey() {
StringBuilder sb = new StringBuilder();
if (getGlobalPrefix() != null) {
sb.append(getGlobalPrefix());
}
sb.append("-<ALL_SCHEMES>");
return sb.toString();
}
private String generatePerSchemeKey(String scheme) {
StringBuilder sb = new StringBuilder();
if (getGlobalPrefix() != null) {
sb.append(getGlobalPrefix());
}
sb.append(scheme);
sb.append("-");
sb.append("<ALL_IDENTIFIERS>");
return sb.toString();
}
protected void initIfNecessary() {
if (_isInitialized) {
return;
}
synchronized (this) {
assert _jedisPool == null;
s_logger.info("Connecting to {}:{}. Write-through set to: {}", new Object[] {getServer(), getPort(), _writeThrough});
JedisPoolConfig poolConfig = new JedisPoolConfig();
//poolConfig.set...
JedisPool pool = new JedisPool(poolConfig, getServer(), getPort());
_jedisPool = pool;
_isInitialized = true;
}
}
protected void updateIdentifiers(ExternalId security) {
Jedis jedis = _jedisPool.getResource();
jedis.sadd(generateAllSchemesKey(), security.getScheme().getName());
jedis.sadd(generatePerSchemeKey(security.getScheme().getName()), security.getValue());
_jedisPool.returnResource(jedis);
}
@Override
public Set<String> getAllIdentifiers(String identifierScheme) {
initIfNecessary();
Jedis jedis = _jedisPool.getResource();
Set<String> allMembers = jedis.smembers(generatePerSchemeKey(identifierScheme));
_jedisPool.returnResource(jedis);
s_logger.info("Loaded {} identifiers from Jedis (full contents in Debug level log)", allMembers.size());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Loaded identifiers from Jedis: {}", allMembers);
}
return allMembers;
}
@Override
public boolean isAvailable(ExternalId security, String normalizationRuleSetId) {
initIfNecessary();
String redisKey = generateRedisKey(security, normalizationRuleSetId);
Jedis jedis = _jedisPool.getResource();
boolean isAvailable = jedis.exists(redisKey);
_jedisPool.returnResource(jedis);
return isAvailable;
}
}