Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #171 from launchdarkly/eb/ch59777-ch61549/new-pers…
Browse files Browse the repository at this point in the history
…istent-store-intf-4.x

partially implement new DataStore/DataSource APIs, + fix Redis cache stats logic
  • Loading branch information
eli-darkly authored Jan 22, 2020
2 parents 3d5381f + aa41dd2 commit 38f48d7
Show file tree
Hide file tree
Showing 54 changed files with 2,025 additions and 1,022 deletions.
106 changes: 98 additions & 8 deletions src/main/java/com/launchdarkly/client/Components.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.launchdarkly.client;

import com.launchdarkly.client.integrations.PersistentDataStoreBuilder;
import com.launchdarkly.client.interfaces.PersistentDataStoreFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -17,28 +20,79 @@ public abstract class Components {
private static final UpdateProcessorFactory nullUpdateProcessorFactory = new NullUpdateProcessorFactory();

/**
* Returns a factory for the default in-memory implementation of {@link FeatureStore}.
* Returns a factory for the default in-memory implementation of a data store.
* <p>
* Note that the interface is still named {@link FeatureStoreFactory}, but in a future version it
* will be renamed to {@code DataStoreFactory}.
*
* @return a factory object
* @see LDConfig.Builder#dataStore(FeatureStoreFactory)
* @since 4.11.0
*/
public static FeatureStoreFactory inMemoryDataStore() {
return inMemoryFeatureStoreFactory;
}

/**
* Returns a configurable factory for some implementation of a persistent data store.
* <p>
* This method is used in conjunction with another factory object provided by specific components
* such as the Redis integration. The latter provides builder methods for options that are specific
* to that integration, while the {@link PersistentDataStoreBuilder} provides options that are
* applicable to <i>any</i> persistent data store (such as caching). For example:
*
* <pre><code>
* LDConfig config = new LDConfig.Builder()
* .dataStore(
* Components.persistentDataStore(
* Redis.dataStore().url("redis://my-redis-host")
* ).cacheSeconds(15)
* )
* .build();
* </code></pre>
*
* See {@link PersistentDataStoreBuilder} for more on how this method is used.
*
* @param storeFactory the factory/builder for the specific kind of persistent data store
* @return a {@link PersistentDataStoreBuilder}
* @see LDConfig.Builder#dataStore(FeatureStoreFactory)
* @see com.launchdarkly.client.integrations.Redis
* @since 4.11.0
*/
public static PersistentDataStoreBuilder persistentDataStore(PersistentDataStoreFactory storeFactory) {
return new PersistentDataStoreBuilder(storeFactory);
}

/**
* Deprecated name for {@link #inMemoryDataStore()}.
* @return a factory object
* @deprecated Use {@link #inMemoryDataStore()}.
*/
@Deprecated
public static FeatureStoreFactory inMemoryFeatureStore() {
return inMemoryFeatureStoreFactory;
}

/**
* 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
* @deprecated Use {@link #persistentDataStore(PersistentDataStoreFactory)} with
* {@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
* @deprecated Use {@link #persistentDataStore(PersistentDataStoreFactory)} with
* {@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);
}
Expand All @@ -48,6 +102,7 @@ public static RedisFeatureStoreBuilder redisFeatureStore(URI redisUri) {
* forwards all analytics events to LaunchDarkly (unless the client is offline or you have
* set {@link LDConfig.Builder#sendEvents(boolean)} to {@code false}).
* @return a factory object
* @see LDConfig.Builder#eventProcessorFactory(EventProcessorFactory)
*/
public static EventProcessorFactory defaultEventProcessor() {
return defaultEventProcessorFactory;
Expand All @@ -57,26 +112,59 @@ public static EventProcessorFactory defaultEventProcessor() {
* Returns a factory for a null implementation of {@link EventProcessor}, which will discard
* all analytics events and not send them to LaunchDarkly, regardless of any other configuration.
* @return a factory object
* @see LDConfig.Builder#eventProcessorFactory(EventProcessorFactory)
*/
public static EventProcessorFactory nullEventProcessor() {
return nullEventProcessorFactory;
}

/**
* Returns a factory for the default implementation of {@link UpdateProcessor}, which receives
* feature flag data from LaunchDarkly using either streaming or polling as configured (or does
* nothing if the client is offline, or in LDD mode).
* Returns a factory for the default implementation of the component for receiving feature flag data
* from LaunchDarkly. Based on your configuration, this implementation uses either streaming or
* polling, or does nothing if the client is offline, or in LDD mode.
*
* Note that the interface is still named {@link UpdateProcessorFactory}, but in a future version it
* will be renamed to {@code DataSourceFactory}.
*
* @return a factory object
* @since 4.11.0
* @see LDConfig.Builder#dataSource(UpdateProcessorFactory)
*/
public static UpdateProcessorFactory defaultDataSource() {
return defaultUpdateProcessorFactory;
}

/**
* Deprecated name for {@link #defaultDataSource()}.
* @return a factory object
* @deprecated Use {@link #defaultDataSource()}.
*/
@Deprecated
public static UpdateProcessorFactory defaultUpdateProcessor() {
return defaultUpdateProcessorFactory;
}

/**
* Returns a factory for a null implementation of {@link UpdateProcessor}, which does not
* connect to LaunchDarkly, regardless of any other configuration.
*
* Note that the interface is still named {@link UpdateProcessorFactory}, but in a future version it
* will be renamed to {@code DataSourceFactory}.
*
* @return a factory object
* @since 4.11.0
* @see LDConfig.Builder#dataSource(UpdateProcessorFactory)
*/
public static UpdateProcessorFactory nullDataSource() {
return nullUpdateProcessorFactory;
}

/**
* Deprecated name for {@link #nullDataSource()}.
* @return a factory object
* @deprecated Use {@link #nullDataSource()}.
*/
@Deprecated
public static UpdateProcessorFactory nullUpdateProcessor() {
return nullUpdateProcessorFactory;
}
Expand Down Expand Up @@ -109,6 +197,7 @@ private static final class DefaultUpdateProcessorFactory implements UpdateProces
// Note, logger uses LDClient class name for backward compatibility
private static final Logger logger = LoggerFactory.getLogger(LDClient.class);

@SuppressWarnings("deprecation")
@Override
public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) {
if (config.offline) {
Expand All @@ -132,6 +221,7 @@ public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, Fea
}

private static final class NullUpdateProcessorFactory implements UpdateProcessorFactory {
@SuppressWarnings("deprecation")
@Override
public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) {
return new UpdateProcessor.NullUpdateProcessor();
Expand Down
9 changes: 0 additions & 9 deletions src/main/java/com/launchdarkly/client/EvaluationReason.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
package com.launchdarkly.client;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Objects;

import static com.google.common.base.Preconditions.checkNotNull;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.launchdarkly.client;

import com.google.common.cache.CacheBuilder;
import com.launchdarkly.client.integrations.PersistentDataStoreBuilder;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
Expand All @@ -25,7 +26,9 @@
*
* @see RedisFeatureStoreBuilder#caching(FeatureStoreCacheConfig)
* @since 4.6.0
* @deprecated This has been superseded by the {@link PersistentDataStoreBuilder} interface.
*/
@Deprecated
public final class FeatureStoreCacheConfig {
/**
* The default TTL, in seconds, used by {@link #DEFAULT}.
Expand Down Expand Up @@ -88,7 +91,40 @@ public enum StaleValuesPolicy {
* See: <a href="https://github.com/google/guava/wiki/CachesExplained#refresh">CacheBuilder</a> for
* more specific information on cache semantics.
*/
REFRESH_ASYNC
REFRESH_ASYNC;

/**
* Used internally for backward compatibility.
* @return the equivalent enum value
* @since 4.11.0
*/
public PersistentDataStoreBuilder.StaleValuesPolicy toNewEnum() {
switch (this) {
case REFRESH:
return PersistentDataStoreBuilder.StaleValuesPolicy.REFRESH;
case REFRESH_ASYNC:
return PersistentDataStoreBuilder.StaleValuesPolicy.REFRESH_ASYNC;
default:
return PersistentDataStoreBuilder.StaleValuesPolicy.EVICT;
}
}

/**
* Used internally for backward compatibility.
* @param policy the enum value in the new API
* @return the equivalent enum value
* @since 4.11.0
*/
public static StaleValuesPolicy fromNewEnum(PersistentDataStoreBuilder.StaleValuesPolicy policy) {
switch (policy) {
case REFRESH:
return StaleValuesPolicy.REFRESH;
case REFRESH_ASYNC:
return StaleValuesPolicy.REFRESH_ASYNC;
default:
return StaleValuesPolicy.EVICT;
}
}
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* A thread-safe, versioned store for {@link FeatureFlag} objects and related data based on a
* A thread-safe, versioned store for feature flags and related data based on a
* {@link HashMap}. This is the default implementation of {@link FeatureStore}.
*/
public class InMemoryFeatureStore implements FeatureStore {
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/launchdarkly/client/LDClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public LDClient(String sdkKey, LDConfig config) {
// of instances that we created ourselves from a factory.
this.shouldCloseFeatureStore = false;
} else {
FeatureStoreFactory factory = config.featureStoreFactory == null ?
Components.inMemoryFeatureStore() : config.featureStoreFactory;
FeatureStoreFactory factory = config.dataStoreFactory == null ?
Components.inMemoryDataStore() : config.dataStoreFactory;
store = factory.createFeatureStore();
this.shouldCloseFeatureStore = true;
}
Expand All @@ -83,8 +83,8 @@ public LDClient(String sdkKey, LDConfig config) {
Components.defaultEventProcessor() : config.eventProcessorFactory;
this.eventProcessor = epFactory.createEventProcessor(sdkKey, config);

UpdateProcessorFactory upFactory = config.updateProcessorFactory == null ?
Components.defaultUpdateProcessor() : config.updateProcessorFactory;
UpdateProcessorFactory upFactory = config.dataSourceFactory == null ?
Components.defaultDataSource() : config.dataSourceFactory;
this.updateProcessor = upFactory.createUpdateProcessor(sdkKey, config, featureStore);
Future<Void> startFuture = updateProcessor.start();
if (config.startWaitMillis > 0L) {
Expand Down
Loading

0 comments on commit 38f48d7

Please sign in to comment.