diff --git a/src/main/java/com/launchdarkly/client/Components.java b/src/main/java/com/launchdarkly/client/Components.java
index e95785915..fb48bc1dd 100644
--- a/src/main/java/com/launchdarkly/client/Components.java
+++ b/src/main/java/com/launchdarkly/client/Components.java
@@ -41,22 +41,23 @@ public static FeatureStoreFactory inMemoryFeatureStore() {
}
/**
- * Returns a factory with builder methods for creating a Redis-backed implementation of {@link FeatureStore},
- * using {@link RedisFeatureStoreBuilder#DEFAULT_URI}.
+ * Deprecated name for {@link com.launchdarkly.client.integrations.Redis#dataStore()}.
* @return a factory/builder object
- * @see LDConfig.Builder#dataStore(FeatureStoreFactory)
+ * @deprecated Use {@link com.launchdarkly.client.integrations.Redis#dataStore()}.
*/
+ @Deprecated
public static RedisFeatureStoreBuilder redisFeatureStore() {
return new RedisFeatureStoreBuilder();
}
/**
- * Returns a factory with builder methods for creating a Redis-backed implementation of {@link FeatureStore},
- * specifying the Redis URI.
+ * Deprecated name for {@link com.launchdarkly.client.integrations.Redis#dataStore()}.
* @param redisUri the URI of the Redis host
* @return a factory/builder object
- * @see LDConfig.Builder#dataStore(FeatureStoreFactory)
+ * @deprecated Use {@link com.launchdarkly.client.integrations.Redis#dataStore()} and
+ * {@link com.launchdarkly.client.integrations.RedisDataStoreBuilder#uri(URI)}.
*/
+ @Deprecated
public static RedisFeatureStoreBuilder redisFeatureStore(URI redisUri) {
return new RedisFeatureStoreBuilder(redisUri);
}
diff --git a/src/main/java/com/launchdarkly/client/RedisFeatureStore.java b/src/main/java/com/launchdarkly/client/RedisFeatureStore.java
index 55091fa40..9713704a7 100644
--- a/src/main/java/com/launchdarkly/client/RedisFeatureStore.java
+++ b/src/main/java/com/launchdarkly/client/RedisFeatureStore.java
@@ -1,73 +1,58 @@
package com.launchdarkly.client;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheStats;
import com.launchdarkly.client.utils.CachingStoreWrapper;
-import com.launchdarkly.client.utils.FeatureStoreCore;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import static com.launchdarkly.client.utils.FeatureStoreHelpers.marshalJson;
-import static com.launchdarkly.client.utils.FeatureStoreHelpers.unmarshalJson;
-
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.Transaction;
-import redis.clients.util.JedisURIHelper;
-
/**
- * An implementation of {@link FeatureStore} backed by Redis. Also
- * supports an optional in-memory cache configuration that can be used to improve performance.
+ * Deprecated implementation class for the Redis-based persistent data store.
+ *
+ * Instead of referencing this class directly, use {@link com.launchdarkly.client.integrations.Redis#dataStore()} to obtain a builder object.
+ *
+ * @deprecated Use {@link com.launchdarkly.client.integrations.Redis#dataStore()}
*/
+@Deprecated
public class RedisFeatureStore implements FeatureStore {
- private static final Logger logger = LoggerFactory.getLogger(RedisFeatureStore.class);
-
- // Note that we could avoid the indirection of delegating everything to CachingStoreWrapper if we
- // simply returned the wrapper itself as the FeatureStore; however, for historical reasons we can't,
- // because we have already exposed the RedisFeatureStore type.
- private final CachingStoreWrapper wrapper;
- private final Core core;
+ // The actual implementation is now in the com.launchdarkly.integrations package. This class remains
+ // visible for backward compatibility, but simply delegates to an instance of the underlying store.
+
+ private final FeatureStore wrappedStore;
@Override
public void init(Map, Map> allData) {
- wrapper.init(allData);
+ wrappedStore.init(allData);
}
@Override
public T get(VersionedDataKind kind, String key) {
- return wrapper.get(kind, key);
+ return wrappedStore.get(kind, key);
}
@Override
public Map all(VersionedDataKind kind) {
- return wrapper.all(kind);
+ return wrappedStore.all(kind);
}
@Override
public void upsert(VersionedDataKind kind, T item) {
- wrapper.upsert(kind, item);
+ wrappedStore.upsert(kind, item);
}
@Override
public void delete(VersionedDataKind kind, String key, int version) {
- wrapper.delete(kind, key, version);
+ wrappedStore.delete(kind, key, version);
}
@Override
public boolean initialized() {
- return wrapper.initialized();
+ return wrappedStore.initialized();
}
@Override
public void close() throws IOException {
- wrapper.close();
+ wrappedStore.close();
}
/**
@@ -76,7 +61,7 @@ public void close() throws IOException {
* @return the cache statistics object.
*/
public CacheStats getCacheStats() {
- return wrapper.getCacheStats();
+ return ((CachingStoreWrapper)wrappedStore).getCacheStats();
}
/**
@@ -87,192 +72,15 @@ public CacheStats getCacheStats() {
* @param builder the configured builder to construct the store with.
*/
protected RedisFeatureStore(RedisFeatureStoreBuilder builder) {
- // There is no builder for JedisPool, just a large number of constructor overloads. Unfortunately,
- // the overloads that accept a URI do not accept the other parameters we need to set, so we need
- // to decompose the URI.
- String host = builder.uri.getHost();
- int port = builder.uri.getPort();
- String password = builder.password == null ? JedisURIHelper.getPassword(builder.uri) : builder.password;
- int database = builder.database == null ? JedisURIHelper.getDBIndex(builder.uri): builder.database.intValue();
- boolean tls = builder.tls || builder.uri.getScheme().equals("rediss");
-
- String extra = tls ? " with TLS" : "";
- if (password != null) {
- extra = extra + (extra.isEmpty() ? " with" : " and") + " password";
- }
- logger.info(String.format("Connecting to Redis feature store at %s:%d/%d%s", host, port, database, extra));
-
- JedisPoolConfig poolConfig = (builder.poolConfig != null) ? builder.poolConfig : new JedisPoolConfig();
- JedisPool pool = new JedisPool(poolConfig,
- host,
- port,
- builder.connectTimeout,
- builder.socketTimeout,
- password,
- database,
- null, // clientName
- tls,
- null, // sslSocketFactory
- null, // sslParameters
- null // hostnameVerifier
- );
-
- String prefix = (builder.prefix == null || builder.prefix.isEmpty()) ?
- RedisFeatureStoreBuilder.DEFAULT_PREFIX :
- builder.prefix;
-
- this.core = new Core(pool, prefix);
- this.wrapper = CachingStoreWrapper.builder(this.core).caching(builder.caching)
- .build();
+ wrappedStore = builder.wrappedBuilder.createFeatureStore();
}
/**
* Creates a new store instance that connects to Redis with a default connection (localhost port 6379) and no in-memory cache.
* @deprecated Please use {@link Components#redisFeatureStore()} instead.
*/
+ @Deprecated
public RedisFeatureStore() {
this(new RedisFeatureStoreBuilder().caching(FeatureStoreCacheConfig.disabled()));
}
-
- static class Core implements FeatureStoreCore {
- private final JedisPool pool;
- private final String prefix;
- private UpdateListener updateListener;
-
- Core(JedisPool pool, String prefix) {
- this.pool = pool;
- this.prefix = prefix;
- }
-
- @Override
- public VersionedData getInternal(VersionedDataKind> kind, String key) {
- try (Jedis jedis = pool.getResource()) {
- VersionedData item = getRedis(kind, key, jedis);
- if (item != null) {
- logger.debug("[get] Key: {} with version: {} found in \"{}\".", key, item.getVersion(), kind.getNamespace());
- }
- return item;
- }
- }
-
- @Override
- public Map getAllInternal(VersionedDataKind> kind) {
- try (Jedis jedis = pool.getResource()) {
- Map allJson = jedis.hgetAll(itemsKey(kind));
- Map result = new HashMap<>();
-
- for (Map.Entry entry : allJson.entrySet()) {
- VersionedData item = unmarshalJson(kind, entry.getValue());
- result.put(entry.getKey(), item);
- }
- return result;
- }
- }
-
- @Override
- public void initInternal(Map, Map> allData) {
- try (Jedis jedis = pool.getResource()) {
- Transaction t = jedis.multi();
-
- for (Map.Entry, Map> entry: allData.entrySet()) {
- String baseKey = itemsKey(entry.getKey());
- t.del(baseKey);
- for (VersionedData item: entry.getValue().values()) {
- t.hset(baseKey, item.getKey(), marshalJson(item));
- }
- }
-
- t.set(initedKey(), "");
- t.exec();
- }
- }
-
- @Override
- public VersionedData upsertInternal(VersionedDataKind> kind, VersionedData newItem) {
- while (true) {
- Jedis jedis = null;
- try {
- jedis = pool.getResource();
- String baseKey = itemsKey(kind);
- jedis.watch(baseKey);
-
- if (updateListener != null) {
- updateListener.aboutToUpdate(baseKey, newItem.getKey());
- }
-
- VersionedData oldItem = getRedis(kind, newItem.getKey(), jedis);
-
- if (oldItem != null && oldItem.getVersion() >= newItem.getVersion()) {
- logger.debug("Attempted to {} key: {} version: {}" +
- " with a version that is the same or older: {} in \"{}\"",
- newItem.isDeleted() ? "delete" : "update",
- newItem.getKey(), oldItem.getVersion(), newItem.getVersion(), kind.getNamespace());
- return oldItem;
- }
-
- Transaction tx = jedis.multi();
- tx.hset(baseKey, newItem.getKey(), marshalJson(newItem));
- List