All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.launchdarkly.client.Components Maven / Gradle / Ivy

package com.launchdarkly.client;

import com.launchdarkly.client.DiagnosticEvent.ConfigProperty;
import com.launchdarkly.client.integrations.EventProcessorBuilder;
import com.launchdarkly.client.integrations.HttpConfigurationBuilder;
import com.launchdarkly.client.integrations.PersistentDataStoreBuilder;
import com.launchdarkly.client.integrations.PollingDataSourceBuilder;
import com.launchdarkly.client.integrations.StreamingDataSourceBuilder;
import com.launchdarkly.client.interfaces.DiagnosticDescription;
import com.launchdarkly.client.interfaces.HttpAuthentication;
import com.launchdarkly.client.interfaces.HttpConfiguration;
import com.launchdarkly.client.interfaces.PersistentDataStoreFactory;
import com.launchdarkly.client.utils.CachingStoreWrapper;
import com.launchdarkly.client.utils.FeatureStoreCore;
import com.launchdarkly.client.value.LDValue;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.util.concurrent.Future;

import static com.google.common.util.concurrent.Futures.immediateFuture;

import okhttp3.Credentials;

/**
 * Provides configurable factories for the standard implementations of LaunchDarkly component interfaces.
 * 

* Some of the configuration options in {@link LDConfig.Builder} affect the entire SDK, but others are * specific to one area of functionality, such as how the SDK receives feature flag updates or processes * analytics events. For the latter, the standard way to specify a configuration is to call one of the * static methods in {@link Components} (such as {@link #streamingDataSource()}), apply any desired * configuration change to the object that that method returns (such as {@link StreamingDataSourceBuilder#initialReconnectDelayMillis(long)}, * and then use the corresponding method in {@link LDConfig.Builder} (such as {@link LDConfig.Builder#dataSource(UpdateProcessorFactory)}) * to use that configured component in the SDK. * * @since 4.0.0 */ @SuppressWarnings("deprecation") public abstract class Components { private static final FeatureStoreFactory inMemoryFeatureStoreFactory = new InMemoryFeatureStoreFactory(); private static final EventProcessorFactory defaultEventProcessorFactory = new DefaultEventProcessorFactory(); private static final EventProcessorFactory nullEventProcessorFactory = new NullEventProcessorFactory(); private static final UpdateProcessorFactory defaultUpdateProcessorFactory = new DefaultUpdateProcessorFactory(); private static final NullUpdateProcessorFactory nullUpdateProcessorFactory = new NullUpdateProcessorFactory(); /** * Returns a configuration object for using the default in-memory implementation of a data store. *

* Since it is the default, you do not normally need to call this method, unless you need to create * a data store instance for testing purposes. *

* 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.12.0 */ public static FeatureStoreFactory inMemoryDataStore() { return inMemoryFeatureStoreFactory; } /** * Returns a configuration builder for some implementation of a persistent data store. *

* 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 any persistent data store (such as caching). For example: * *


   *     LDConfig config = new LDConfig.Builder()
   *         .dataStore(
   *             Components.persistentDataStore(
   *                 Redis.dataStore().url("redis://my-redis-host")
   *             ).cacheSeconds(15)
   *         )
   *         .build();
   * 
* * 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.12.0 */ public static PersistentDataStoreBuilder persistentDataStore(PersistentDataStoreFactory storeFactory) { return new PersistentDataStoreBuilderImpl(storeFactory); } /** * Deprecated name for {@link #inMemoryDataStore()}. * @return a factory object * @deprecated Use {@link #inMemoryDataStore()}. */ @Deprecated public static FeatureStoreFactory inMemoryFeatureStore() { return inMemoryFeatureStoreFactory; } /** * 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(); } /** * 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); } /** * Returns a configuration builder for analytics event delivery. *

* The default configuration has events enabled with default settings. If you want to * customize this behavior, call this method to obtain a builder, change its properties * with the {@link EventProcessorBuilder} properties, and pass it to {@link LDConfig.Builder#events(EventProcessorFactory)}: *


   *     LDConfig config = new LDConfig.Builder()
   *         .events(Components.sendEvents().capacity(5000).flushIntervalSeconds(2))
   *         .build();
   * 
* To completely disable sending analytics events, use {@link #noEvents()} instead. * * @return a builder for setting streaming connection properties * @see #noEvents() * @see LDConfig.Builder#events * @since 4.12.0 */ public static EventProcessorBuilder sendEvents() { return new EventProcessorBuilderImpl(); } /** * Deprecated method for using the default analytics events implementation. *

* If you pass the return value of this method to {@link LDConfig.Builder#events(EventProcessorFactory)}, * the behavior is as follows: *

    *
  • If you have set {@link LDConfig.Builder#offline(boolean)} to {@code true}, or * {@link LDConfig.Builder#sendEvents(boolean)} to {@code false}, the SDK will not send events to * LaunchDarkly. *
  • Otherwise, it will send events, using the properties set by the deprecated events configuration * methods such as {@link LDConfig.Builder#capacity(int)}. *
* * @return a factory object * @deprecated Use {@link #sendEvents()} or {@link #noEvents}. */ @Deprecated public static EventProcessorFactory defaultEventProcessor() { return defaultEventProcessorFactory; } /** * Returns a configuration object that disables analytics events. *

* Passing this to {@link LDConfig.Builder#events(EventProcessorFactory)} causes the SDK * to discard all analytics events and not send them to LaunchDarkly, regardless of any other configuration. *


   *     LDConfig config = new LDConfig.Builder()
   *         .events(Components.noEvents())
   *         .build();
   * 
* * @return a factory object * @see #sendEvents() * @see LDConfig.Builder#events(EventProcessorFactory) * @since 4.12.0 */ public static EventProcessorFactory noEvents() { return nullEventProcessorFactory; } /** * Deprecated name for {@link #noEvents()}. * @return a factory object * @see LDConfig.Builder#events(EventProcessorFactory) * @deprecated Use {@link #noEvents()}. */ @Deprecated public static EventProcessorFactory nullEventProcessor() { return nullEventProcessorFactory; } /** * Returns a configurable factory for using streaming mode to get feature flag data. *

* By default, the SDK uses a streaming connection to receive feature flag data from LaunchDarkly. To use the * default behavior, you do not need to call this method. However, if you want to customize the behavior of * the connection, call this method to obtain a builder, change its properties with the * {@link StreamingDataSourceBuilder} methods, and pass it to {@link LDConfig.Builder#dataSource(UpdateProcessorFactory)}: *

 
   *     LDConfig config = new LDConfig.Builder()
   *         .dataSource(Components.streamingDataSource().initialReconnectDelayMillis(500))
   *         .build();
   * 
*

* These properties will override any equivalent deprecated properties that were set with {@code LDConfig.Builder}, * such as {@link LDConfig.Builder#reconnectTimeMs(long)}. *

* (Note that the interface is still named {@link UpdateProcessorFactory}, but in a future version it * will be renamed to {@code DataSourceFactory}.) * * @return a builder for setting streaming connection properties * @see LDConfig.Builder#dataSource(UpdateProcessorFactory) * @since 4.12.0 */ public static StreamingDataSourceBuilder streamingDataSource() { return new StreamingDataSourceBuilderImpl(); } /** * Returns a configurable factory for using polling mode to get feature flag data. *

* This is not the default behavior; by default, the SDK uses a streaming connection to receive feature flag * data from LaunchDarkly. In polling mode, the SDK instead makes a new HTTP request to LaunchDarkly at regular * intervals. HTTP caching allows it to avoid redundantly downloading data if there have been no changes, but * polling is still less efficient than streaming and should only be used on the advice of LaunchDarkly support. *

* To use polling mode, call this method to obtain a builder, change its properties with the * {@link PollingDataSourceBuilder} methods, and pass it to {@link LDConfig.Builder#dataSource(UpdateProcessorFactory)}: *


   *     LDConfig config = new LDConfig.Builder()
   *         .dataSource(Components.pollingDataSource().pollIntervalMillis(45000))
   *         .build();
   * 
*

* These properties will override any equivalent deprecated properties that were set with {@code LDConfig.Builder}, * such as {@link LDConfig.Builder#pollingIntervalMillis(long)}. However, setting {@link LDConfig.Builder#offline(boolean)} * to {@code true} will supersede this setting and completely disable network requests. *

* (Note that the interface is still named {@link UpdateProcessorFactory}, but in a future version it * will be renamed to {@code DataSourceFactory}.) * * @return a builder for setting polling properties * @see LDConfig.Builder#dataSource(UpdateProcessorFactory) * @since 4.12.0 */ public static PollingDataSourceBuilder pollingDataSource() { return new PollingDataSourceBuilderImpl(); } /** * Deprecated method for using the default data source implementation. *

* If you pass the return value of this method to {@link LDConfig.Builder#dataSource(UpdateProcessorFactory)}, * the behavior is as follows: *

    *
  • If you have set {@link LDConfig.Builder#offline(boolean)} or {@link LDConfig.Builder#useLdd(boolean)} * to {@code true}, the SDK will not connect to LaunchDarkly for feature flag data. *
  • If you have set {@link LDConfig.Builder#stream(boolean)} to {@code false}, it will use polling mode-- * equivalent to using {@link #pollingDataSource()} with the options set by {@link LDConfig.Builder#baseURI(URI)} * and {@link LDConfig.Builder#pollingIntervalMillis(long)}. *
  • Otherwise, it will use streaming mode-- equivalent to using {@link #streamingDataSource()} with * the options set by {@link LDConfig.Builder#streamURI(URI)} and {@link LDConfig.Builder#reconnectTimeMs(long)}. *
* * @return a factory object * @deprecated Use {@link #streamingDataSource()}, {@link #pollingDataSource()}, or {@link #externalUpdatesOnly()}. */ @Deprecated public static UpdateProcessorFactory defaultUpdateProcessor() { return defaultUpdateProcessorFactory; } /** * Returns a configuration object that disables a direct connection with LaunchDarkly for feature flag updates. *

* Passing this to {@link LDConfig.Builder#dataSource(UpdateProcessorFactory)} causes the SDK * not to retrieve feature flag data from LaunchDarkly, regardless of any other configuration. * This is normally done if you are using the Relay Proxy * in "daemon mode", where an external process-- the Relay Proxy-- connects to LaunchDarkly and populates * a persistent data store with the feature flag data. The data store could also be populated by * another process that is running the LaunchDarkly SDK. If there is no external process updating * the data store, then the SDK will not have any feature flag data and will return application * default values only. *


   *     LDConfig config = new LDConfig.Builder()
   *         .dataSource(Components.externalUpdatesOnly())
   *         .dataStore(Components.persistentDataStore(Redis.dataStore())) // assuming the Relay Proxy is using Redis
   *         .build();
   * 
*

* (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.12.0 * @see LDConfig.Builder#dataSource(UpdateProcessorFactory) */ public static UpdateProcessorFactory externalUpdatesOnly() { return nullUpdateProcessorFactory; } /** * Deprecated name for {@link #externalUpdatesOnly()}. * @return a factory object * @deprecated Use {@link #externalUpdatesOnly()}. */ @Deprecated public static UpdateProcessorFactory nullUpdateProcessor() { return nullUpdateProcessorFactory; } /** * Returns a configurable factory for the SDK's networking configuration. *

* Passing this to {@link LDConfig.Builder#http(com.launchdarkly.client.interfaces.HttpConfigurationFactory)} * applies this configuration to all HTTP/HTTPS requests made by the SDK. *


   *     LDConfig config = new LDConfig.Builder()
   *         .http(
   *              Components.httpConfiguration()
   *                  .connectTimeoutMillis(3000)
   *                  .proxyHostAndPort("my-proxy", 8080)
   *         )
   *         .build();
   * 
*

* These properties will override any equivalent deprecated properties that were set with {@code LDConfig.Builder}, * such as {@link LDConfig.Builder#connectTimeout(int)}. However, setting {@link LDConfig.Builder#offline(boolean)} * to {@code true} will supersede these settings and completely disable network requests. * * @return a factory object * @since 4.13.0 * @see LDConfig.Builder#http(com.launchdarkly.client.interfaces.HttpConfigurationFactory) */ public static HttpConfigurationBuilder httpConfiguration() { return new HttpConfigurationBuilderImpl(); } /** * Configures HTTP basic authentication, for use with a proxy server. *


   *     LDConfig config = new LDConfig.Builder()
   *         .http(
   *              Components.httpConfiguration()
   *                  .proxyHostAndPort("my-proxy", 8080)
   *                  .proxyAuthentication(Components.httpBasicAuthentication("username", "password"))
   *         )
   *         .build();
   * 
* * @param username the username * @param password the password * @return the basic authentication strategy * @since 4.13.0 * @see HttpConfigurationBuilder#proxyAuth(HttpAuthentication) */ public static HttpAuthentication httpBasicAuthentication(String username, String password) { return new HttpBasicAuthentication(username, password); } private static final class InMemoryFeatureStoreFactory implements FeatureStoreFactory, DiagnosticDescription { @Override public FeatureStore createFeatureStore() { return new InMemoryFeatureStore(); } @Override public LDValue describeConfiguration(LDConfig config) { return LDValue.of("memory"); } } // This can be removed once the deprecated event config options have been removed. private static final class DefaultEventProcessorFactory implements EventProcessorFactoryWithDiagnostics, DiagnosticDescription { @Override public EventProcessor createEventProcessor(String sdkKey, LDConfig config) { return createEventProcessor(sdkKey, config, null); } public EventProcessor createEventProcessor(String sdkKey, LDConfig config, DiagnosticAccumulator diagnosticAccumulator) { if (config.offline || !config.deprecatedSendEvents) { return new NullEventProcessor(); } return new DefaultEventProcessor(sdkKey, config, new EventsConfiguration( config.deprecatedAllAttributesPrivate, config.deprecatedCapacity, config.deprecatedEventsURI == null ? LDConfig.DEFAULT_EVENTS_URI : config.deprecatedEventsURI, config.deprecatedFlushInterval, config.deprecatedInlineUsersInEvents, config.deprecatedPrivateAttrNames, config.deprecatedSamplingInterval, config.deprecatedUserKeysCapacity, config.deprecatedUserKeysFlushInterval, EventProcessorBuilder.DEFAULT_DIAGNOSTIC_RECORDING_INTERVAL_SECONDS ), config.httpConfig, diagnosticAccumulator ); } @Override public LDValue describeConfiguration(LDConfig config) { return LDValue.buildObject() .put(ConfigProperty.ALL_ATTRIBUTES_PRIVATE.name, config.deprecatedAllAttributesPrivate) .put(ConfigProperty.CUSTOM_EVENTS_URI.name, config.deprecatedEventsURI != null && !config.deprecatedEventsURI.equals(LDConfig.DEFAULT_EVENTS_URI)) .put(ConfigProperty.DIAGNOSTIC_RECORDING_INTERVAL_MILLIS.name, EventProcessorBuilder.DEFAULT_DIAGNOSTIC_RECORDING_INTERVAL_SECONDS * 1000) // not configurable via deprecated API .put(ConfigProperty.EVENTS_CAPACITY.name, config.deprecatedCapacity) .put(ConfigProperty.EVENTS_FLUSH_INTERVAL_MILLIS.name, config.deprecatedFlushInterval * 1000) .put(ConfigProperty.INLINE_USERS_IN_EVENTS.name, config.deprecatedInlineUsersInEvents) .put(ConfigProperty.SAMPLING_INTERVAL.name, config.deprecatedSamplingInterval) .put(ConfigProperty.USER_KEYS_CAPACITY.name, config.deprecatedUserKeysCapacity) .put(ConfigProperty.USER_KEYS_FLUSH_INTERVAL_MILLIS.name, config.deprecatedUserKeysFlushInterval * 1000) .build(); } } private static final class NullEventProcessorFactory implements EventProcessorFactory { public EventProcessor createEventProcessor(String sdkKey, LDConfig config) { return new NullEventProcessor(); } } static final class NullEventProcessor implements EventProcessor { @Override public void sendEvent(Event e) { } @Override public void flush() { } @Override public void close() { } } // This can be removed once the deprecated polling/streaming config options have been removed. private static final class DefaultUpdateProcessorFactory implements UpdateProcessorFactoryWithDiagnostics, DiagnosticDescription { @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) { return createUpdateProcessor(sdkKey, config, featureStore, null); } @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore, DiagnosticAccumulator diagnosticAccumulator) { if (config.offline) { return Components.externalUpdatesOnly().createUpdateProcessor(sdkKey, config, featureStore); } // We don't need to check config.offline or config.useLdd here; the former is checked automatically // by StreamingDataSourceBuilder and PollingDataSourceBuilder, and setting the latter is translated // into using externalUpdatesOnly() by LDConfig.Builder. if (config.deprecatedStream) { StreamingDataSourceBuilderImpl builder = (StreamingDataSourceBuilderImpl)streamingDataSource() .baseURI(config.deprecatedStreamURI) .pollingBaseURI(config.deprecatedBaseURI) .initialReconnectDelayMillis(config.deprecatedReconnectTimeMs); return builder.createUpdateProcessor(sdkKey, config, featureStore, diagnosticAccumulator); } else { return pollingDataSource() .baseURI(config.deprecatedBaseURI) .pollIntervalMillis(config.deprecatedPollingIntervalMillis) .createUpdateProcessor(sdkKey, config, featureStore); } } @Override public LDValue describeConfiguration(LDConfig config) { if (config.offline) { return nullUpdateProcessorFactory.describeConfiguration(config); } if (config.deprecatedStream) { return LDValue.buildObject() .put(ConfigProperty.STREAMING_DISABLED.name, false) .put(ConfigProperty.CUSTOM_BASE_URI.name, config.deprecatedBaseURI != null && !config.deprecatedBaseURI.equals(LDConfig.DEFAULT_BASE_URI)) .put(ConfigProperty.CUSTOM_STREAM_URI.name, config.deprecatedStreamURI != null && !config.deprecatedStreamURI.equals(LDConfig.DEFAULT_STREAM_URI)) .put(ConfigProperty.RECONNECT_TIME_MILLIS.name, config.deprecatedReconnectTimeMs) .put(ConfigProperty.USING_RELAY_DAEMON.name, false) .build(); } else { return LDValue.buildObject() .put(ConfigProperty.STREAMING_DISABLED.name, true) .put(ConfigProperty.CUSTOM_BASE_URI.name, config.deprecatedBaseURI != null && !config.deprecatedBaseURI.equals(LDConfig.DEFAULT_BASE_URI)) .put(ConfigProperty.CUSTOM_STREAM_URI.name, false) .put(ConfigProperty.POLLING_INTERVAL_MILLIS.name, config.deprecatedPollingIntervalMillis) .put(ConfigProperty.USING_RELAY_DAEMON.name, false) .build(); } } } private static final class NullUpdateProcessorFactory implements UpdateProcessorFactory, DiagnosticDescription { @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) { if (config.offline) { // If they have explicitly called offline(true) to disable everything, we'll log this slightly // more specific message. LDClient.logger.info("Starting LaunchDarkly client in offline mode"); } else { LDClient.logger.info("LaunchDarkly client will not connect to Launchdarkly for feature flag data"); } return new NullUpdateProcessor(); } @Override public LDValue describeConfiguration(LDConfig config) { // We can assume that if they don't have a data source, and they *do* have a persistent data store, then // they're using Relay in daemon mode. return LDValue.buildObject() .put(ConfigProperty.CUSTOM_BASE_URI.name, false) .put(ConfigProperty.CUSTOM_STREAM_URI.name, false) .put(ConfigProperty.STREAMING_DISABLED.name, false) .put(ConfigProperty.USING_RELAY_DAEMON.name, config.dataStoreFactory != null && config.dataStoreFactory != Components.inMemoryDataStore()) .build(); } } // Package-private for visibility in tests static final class NullUpdateProcessor implements UpdateProcessor { @Override public Future start() { return immediateFuture(null); } @Override public boolean initialized() { return true; } @Override public void close() throws IOException {} } private static final class StreamingDataSourceBuilderImpl extends StreamingDataSourceBuilder implements UpdateProcessorFactoryWithDiagnostics, DiagnosticDescription { @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) { return createUpdateProcessor(sdkKey, config, featureStore, null); } @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore, DiagnosticAccumulator diagnosticAccumulator) { // Note, we log startup messages under the LDClient class to keep logs more readable if (config.offline) { return Components.externalUpdatesOnly().createUpdateProcessor(sdkKey, config, featureStore); } LDClient.logger.info("Enabling streaming API"); URI streamUri = baseURI == null ? LDConfig.DEFAULT_STREAM_URI : baseURI; URI pollUri; if (pollingBaseURI != null) { pollUri = pollingBaseURI; } else { // If they have set a custom base URI, and they did *not* set a custom polling URI, then we can // assume they're using Relay in which case both of those values are the same. pollUri = baseURI == null ? LDConfig.DEFAULT_BASE_URI : baseURI; } DefaultFeatureRequestor requestor = new DefaultFeatureRequestor( sdkKey, config.httpConfig, pollUri, false ); return new StreamProcessor( sdkKey, config.httpConfig, requestor, featureStore, null, diagnosticAccumulator, streamUri, initialReconnectDelayMillis ); } @Override public LDValue describeConfiguration(LDConfig config) { if (config.offline) { return nullUpdateProcessorFactory.describeConfiguration(config); } return LDValue.buildObject() .put(ConfigProperty.STREAMING_DISABLED.name, false) .put(ConfigProperty.CUSTOM_BASE_URI.name, (pollingBaseURI != null && !pollingBaseURI.equals(LDConfig.DEFAULT_BASE_URI)) || (pollingBaseURI == null && baseURI != null && !baseURI.equals(LDConfig.DEFAULT_STREAM_URI))) .put(ConfigProperty.CUSTOM_STREAM_URI.name, baseURI != null && !baseURI.equals(LDConfig.DEFAULT_STREAM_URI)) .put(ConfigProperty.RECONNECT_TIME_MILLIS.name, initialReconnectDelayMillis) .put(ConfigProperty.USING_RELAY_DAEMON.name, false) .build(); } } private static final class PollingDataSourceBuilderImpl extends PollingDataSourceBuilder implements DiagnosticDescription { @Override public UpdateProcessor createUpdateProcessor(String sdkKey, LDConfig config, FeatureStore featureStore) { // Note, we log startup messages under the LDClient class to keep logs more readable if (config.offline) { return Components.externalUpdatesOnly().createUpdateProcessor(sdkKey, config, featureStore); } LDClient.logger.info("Disabling streaming API"); LDClient.logger.warn("You should only disable the streaming API if instructed to do so by LaunchDarkly support"); DefaultFeatureRequestor requestor = new DefaultFeatureRequestor( sdkKey, config.httpConfig, baseURI == null ? LDConfig.DEFAULT_BASE_URI : baseURI, true ); return new PollingProcessor(requestor, featureStore, pollIntervalMillis); } @Override public LDValue describeConfiguration(LDConfig config) { if (config.offline) { return nullUpdateProcessorFactory.describeConfiguration(config); } return LDValue.buildObject() .put(ConfigProperty.STREAMING_DISABLED.name, true) .put(ConfigProperty.CUSTOM_BASE_URI.name, baseURI != null && !baseURI.equals(LDConfig.DEFAULT_BASE_URI)) .put(ConfigProperty.CUSTOM_STREAM_URI.name, false) .put(ConfigProperty.POLLING_INTERVAL_MILLIS.name, pollIntervalMillis) .put(ConfigProperty.USING_RELAY_DAEMON.name, false) .build(); } } private static final class EventProcessorBuilderImpl extends EventProcessorBuilder implements EventProcessorFactoryWithDiagnostics, DiagnosticDescription { @Override public EventProcessor createEventProcessor(String sdkKey, LDConfig config) { return createEventProcessor(sdkKey, config, null); } @Override public EventProcessor createEventProcessor(String sdkKey, LDConfig config, DiagnosticAccumulator diagnosticAccumulator) { if (config.offline) { return new NullEventProcessor(); } return new DefaultEventProcessor(sdkKey, config, new EventsConfiguration( allAttributesPrivate, capacity, baseURI == null ? LDConfig.DEFAULT_EVENTS_URI : baseURI, flushIntervalSeconds, inlineUsersInEvents, privateAttrNames, 0, // deprecated samplingInterval isn't supported in new builder userKeysCapacity, userKeysFlushIntervalSeconds, diagnosticRecordingIntervalSeconds ), config.httpConfig, diagnosticAccumulator ); } @Override public LDValue describeConfiguration(LDConfig config) { return LDValue.buildObject() .put(ConfigProperty.ALL_ATTRIBUTES_PRIVATE.name, allAttributesPrivate) .put(ConfigProperty.CUSTOM_EVENTS_URI.name, baseURI != null && !baseURI.equals(LDConfig.DEFAULT_EVENTS_URI)) .put(ConfigProperty.DIAGNOSTIC_RECORDING_INTERVAL_MILLIS.name, diagnosticRecordingIntervalSeconds * 1000) .put(ConfigProperty.EVENTS_CAPACITY.name, capacity) .put(ConfigProperty.EVENTS_FLUSH_INTERVAL_MILLIS.name, flushIntervalSeconds * 1000) .put(ConfigProperty.INLINE_USERS_IN_EVENTS.name, inlineUsersInEvents) .put(ConfigProperty.SAMPLING_INTERVAL.name, 0) .put(ConfigProperty.USER_KEYS_CAPACITY.name, userKeysCapacity) .put(ConfigProperty.USER_KEYS_FLUSH_INTERVAL_MILLIS.name, userKeysFlushIntervalSeconds * 1000) .build(); } } private static final class HttpConfigurationBuilderImpl extends HttpConfigurationBuilder { @Override public HttpConfiguration createHttpConfiguration() { return new HttpConfigurationImpl( connectTimeoutMillis, proxyHost == null ? null : new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)), proxyAuth, socketTimeoutMillis, sslSocketFactory, trustManager, wrapperName == null ? null : (wrapperVersion == null ? wrapperName : (wrapperName + "/" + wrapperVersion)) ); } } private static final class HttpBasicAuthentication implements HttpAuthentication { private final String username; private final String password; HttpBasicAuthentication(String username, String password) { this.username = username; this.password = password; } @Override public String provideAuthorization(Iterable challenges) { return Credentials.basic(username, password); } } private static final class PersistentDataStoreBuilderImpl extends PersistentDataStoreBuilder implements DiagnosticDescription { public PersistentDataStoreBuilderImpl(PersistentDataStoreFactory persistentDataStoreFactory) { super(persistentDataStoreFactory); } @Override public FeatureStore createFeatureStore() { FeatureStoreCore core = persistentDataStoreFactory.createPersistentDataStore(); return CachingStoreWrapper.builder(core) .caching(caching) .cacheMonitor(cacheMonitor) .build(); } @Override public LDValue describeConfiguration(LDConfig config) { if (persistentDataStoreFactory instanceof DiagnosticDescription) { return ((DiagnosticDescription)persistentDataStoreFactory).describeConfiguration(config); } return LDValue.of("?"); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy