package org.togglz.redis;
import java.util.Map;
import org.togglz.core.Feature;
import org.togglz.core.repository.FeatureState;
import org.togglz.core.repository.StateRepository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* A state repository which stores the feature state in Redis.
* <p>
* The class provides a builder which can be used to configure the state repository instance
* (e.g. Redis hostname, Redis/Jedis configuration, serialization).
* </p>
*
* @author Cosmin Rentea
*/
public class RedisStateRepository implements StateRepository {
public static final String ENABLED_FIELD = "enabled";
public static final String STRATEGY_FIELD = "strategy";
public static final String PARAMETER_PREFIX = "parameter:";
public static final int PARAMETER_PREFIX_LENGTH = PARAMETER_PREFIX.length();
protected final JedisPool jedisPool;
protected final String keyPrefix;
private RedisStateRepository(final Builder builder) {
keyPrefix = builder.keyPrefix;
jedisPool = builder.jedisPool != null ? builder.jedisPool : new JedisPool();
}
@Override
public FeatureState getFeatureState(final Feature feature) {
try (final Jedis jedis = jedisPool.getResource()) {
final Map<String, String> redisMap = jedis.hgetAll(keyPrefix + feature.name());
if (redisMap == null || redisMap.size() == 0) {
return null;
}
final FeatureState featureState = new FeatureState(feature);
featureState.setEnabled(Boolean.valueOf(redisMap.get(ENABLED_FIELD)));
featureState.setStrategyId(redisMap.get(STRATEGY_FIELD));
for (final Map.Entry<String, String> entry : redisMap.entrySet()) {
final String key = entry.getKey();
if (key.startsWith(PARAMETER_PREFIX)) {
featureState.setParameter(key.substring(PARAMETER_PREFIX_LENGTH), entry.getValue());
}
}
return featureState;
}
}
@Override
public void setFeatureState(final FeatureState featureState) {
try (final Jedis jedis = jedisPool.getResource()) {
final String featureKey = keyPrefix + featureState.getFeature().name();
jedis.hset(featureKey, ENABLED_FIELD, Boolean.toString(featureState.isEnabled()));
final String strategyId = featureState.getStrategyId();
if (strategyId != null) {
jedis.hset(featureKey, STRATEGY_FIELD, strategyId);
}
final Map<String, String> parameterMap = featureState.getParameterMap();
if (parameterMap != null) {
for (final Map.Entry<String, String> entry : parameterMap.entrySet()) {
jedis.hset(featureKey, PARAMETER_PREFIX + entry.getKey(), entry.getValue());
}
}
}
}
/**
* Builder for a {@link RedisStateRepository}.
* <p>
* Can be used as follows:
* </p>
* <pre>
* StateRepository stateRepository =
* new RedisStateRepository.Builder().
* jedisPool(new JedisPool("hostname")).
* keyPrefix("toggles:").
* build();
* </pre>
*/
public static class Builder {
private JedisPool jedisPool = null;
private String keyPrefix = "togglz:";
/**
* Creates a new builder for a {@link RedisStateRepository}.
*/
public Builder() {
// intentionally empty
}
/**
* Sets the Jedis Pool.
*
* @param jedisPool the Jedis Pool {@link JedisPool}
*/
public Builder jedisPool(final JedisPool jedisPool) {
this.jedisPool = jedisPool;
return this;
}
/**
* Sets the Redis key prefix to be used when getting or setting the state of the features.
*
* @param keyPrefix the key prefix to be used in Redis
*/
public Builder keyPrefix(final String keyPrefix) {
this.keyPrefix = keyPrefix;
return this;
}
/**
* Creates a new {@link RedisStateRepository} using the current settings.
*/
public RedisStateRepository build() {
return new RedisStateRepository(this);
}
}
}