diff --git a/client/pom.xml b/client/pom.xml index efffe9272..88f7fdbd2 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -172,6 +172,16 @@ targeting-engine ${project.version} + + io.split.client + parsing-commons + ${project.version} + + + io.split.client + segment-commons + ${project.version} + io.split.client pluggable-storage diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 9ad38ef1b..e71a78ecb 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -57,8 +57,10 @@ import io.split.engine.experiments.SplitParser; import io.split.engine.experiments.SplitSynchronizationTask; import io.split.engine.experiments.RuleBasedSegmentParser; +import io.split.engine.segments.ExecutorFactory; import io.split.engine.segments.SegmentChangeFetcher; import io.split.engine.segments.SegmentSynchronizationTaskImp; +import io.split.engine.segments.TelemetryListener; import io.split.integrations.IntegrationsConfig; import io.split.service.SplitHttpClientImpl; import io.split.service.SplitHttpClient; @@ -85,6 +87,7 @@ import io.split.storages.pluggable.adapters.UserCustomRuleBasedSegmentAdapterConsumer; import io.split.storages.pluggable.domain.UserStorageWrapper; import io.split.storages.pluggable.synchronizer.TelemetryConsumerSubmitter; +import io.split.telemetry.domain.enums.LastSynchronizationRecordsEnum; import io.split.telemetry.storage.InMemoryTelemetryStorage; import io.split.telemetry.storage.NoopTelemetryStorage; import io.split.telemetry.storage.TelemetryStorage; @@ -129,6 +132,7 @@ import java.util.List; import java.util.ArrayList; +import io.split.client.utils.SplitExecutorFactory; import static io.split.client.utils.SplitExecutorFactory.buildExecutorService; public class SplitFactoryImpl implements SplitFactory { @@ -427,12 +431,17 @@ protected SplitFactoryImpl(SplitClientConfig config) { segmentChangeFetcher = new LocalhostSegmentChangeFetcher(config.segmentDirectory()); } + TelemetryListener segmentTelemetryListener = + t -> _telemetryStorageProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, t); + ExecutorFactory segmentExecutorFactory = + (tf, name, n) -> SplitExecutorFactory.buildScheduledExecutorService(tf, name, n); _segmentSynchronizationTaskImp = new SegmentSynchronizationTaskImp(segmentChangeFetcher, config.segmentsRefreshRate(), config.numThreadsForSegmentFetch(), segmentCache, - _telemetryStorageProducer, + segmentTelemetryListener, _splitCache, + segmentExecutorFactory, config.getThreadFactory(), ruleBasedSegmentCache); @@ -696,12 +705,17 @@ private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config, SegmentChangeFetcher segmentChangeFetcher = HttpSegmentChangeFetcher.create(_splitHttpClient, _rootTarget, _telemetryStorageProducer); + TelemetryListener segTelemetryListener = + t -> _telemetryStorageProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, t); + ExecutorFactory segExecutorFactory = + (tf, name, n) -> SplitExecutorFactory.buildScheduledExecutorService(tf, name, n); return new SegmentSynchronizationTaskImp(segmentChangeFetcher, config.segmentsRefreshRate(), config.numThreadsForSegmentFetch(), segmentCacheProducer, - _telemetryStorageProducer, + segTelemetryListener, splitCacheConsumer, + segExecutorFactory, config.getThreadFactory(), ruleBasedSegmentCache); } diff --git a/client/src/main/java/io/split/storages/SplitCacheCommons.java b/client/src/main/java/io/split/storages/SplitCacheCommons.java index 539e3144e..43c2b300d 100644 --- a/client/src/main/java/io/split/storages/SplitCacheCommons.java +++ b/client/src/main/java/io/split/storages/SplitCacheCommons.java @@ -1,8 +1,5 @@ package io.split.storages; -import java.util.Set; - -public interface SplitCacheCommons { +public interface SplitCacheCommons extends SegmentsProvider { long getChangeNumber(); - Set getSegments(); } diff --git a/client/src/test/java/io/split/engine/common/LocalhostSynchronizerTest.java b/client/src/test/java/io/split/engine/common/LocalhostSynchronizerTest.java index 04163aedd..a46d3176e 100644 --- a/client/src/test/java/io/split/engine/common/LocalhostSynchronizerTest.java +++ b/client/src/test/java/io/split/engine/common/LocalhostSynchronizerTest.java @@ -7,8 +7,10 @@ import io.split.client.utils.FileInputStreamProvider; import io.split.client.utils.InputStreamProvider; import io.split.engine.experiments.*; +import io.split.engine.segments.ExecutorFactory; import io.split.engine.segments.SegmentChangeFetcher; import io.split.engine.segments.SegmentSynchronizationTaskImp; +import io.split.engine.segments.TelemetryListener; import io.split.storages.*; import io.split.storages.memory.InMemoryCacheImp; import io.split.storages.memory.RuleBasedSegmentCacheInMemoryImp; @@ -24,6 +26,8 @@ public class LocalhostSynchronizerTest { private static final TelemetryStorage TELEMETRY_STORAGE_NOOP = Mockito.mock(NoopTelemetryStorage.class); + private static final TelemetryListener TELEMETRY_LISTENER = t -> {}; + private static final ExecutorFactory EXECUTOR_FACTORY = (tf, name, n) -> java.util.concurrent.Executors.newScheduledThreadPool(n); private static final FlagSetsFilter FLAG_SETS_FILTER = new FlagSetsFilterImpl(new HashSet<>()); @Test @@ -45,7 +49,7 @@ public void testSyncAll(){ SegmentCacheProducer segmentCacheProducer = new SegmentCacheInMemoryImpl(); SegmentSynchronizationTaskImp segmentSynchronizationTaskImp = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1000, 1, segmentCacheProducer, - TELEMETRY_STORAGE_NOOP, splitCacheProducer, null, ruleBasedSegmentCache); + TELEMETRY_LISTENER, splitCacheProducer, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); SplitTasks splitTasks = SplitTasks.build(splitSynchronizationTask, segmentSynchronizationTaskImp, null, null, null, null); LocalhostSynchronizer localhostSynchronizer = new LocalhostSynchronizer(splitTasks, splitFetcher, false); @@ -72,7 +76,7 @@ public void testPeriodicFetching() throws InterruptedException { SegmentCacheProducer segmentCacheProducer = new SegmentCacheInMemoryImpl(); SegmentSynchronizationTaskImp segmentSynchronizationTaskImp = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1000, 1, segmentCacheProducer, - TELEMETRY_STORAGE_NOOP, splitCacheProducer, null, ruleBasedSegmentCache); + TELEMETRY_LISTENER, splitCacheProducer, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); SplitTasks splitTasks = SplitTasks.build(splitSynchronizationTask, segmentSynchronizationTaskImp, null, null, null, null); LocalhostSynchronizer localhostSynchronizer = new LocalhostSynchronizer(splitTasks, splitFetcher, true); diff --git a/client/src/test/java/io/split/engine/common/SynchronizerTest.java b/client/src/test/java/io/split/engine/common/SynchronizerTest.java index 0ce439c7f..a0150d52e 100644 --- a/client/src/test/java/io/split/engine/common/SynchronizerTest.java +++ b/client/src/test/java/io/split/engine/common/SynchronizerTest.java @@ -5,8 +5,10 @@ import io.split.client.impressions.UniqueKeysTracker; import io.split.client.interceptors.FlagSetsFilter; import io.split.client.interceptors.FlagSetsFilterImpl; +import io.split.engine.segments.ExecutorFactory; import io.split.engine.segments.SegmentChangeFetcher; import io.split.engine.segments.SegmentSynchronizationTaskImp; +import io.split.engine.segments.TelemetryListener; import io.split.storages.*; import io.split.storages.memory.InMemoryCacheImp; import io.split.engine.experiments.FetchResult; @@ -81,9 +83,11 @@ public void syncAll() throws InterruptedException { @Test public void testSyncAllSegments() throws InterruptedException, NoSuchFieldException, IllegalAccessException { + ExecutorFactory executorFactory = (tf, name, n) -> java.util.concurrent.Executors.newScheduledThreadPool(n); + TelemetryListener telemetryListener = t -> {}; SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(Mockito.mock(SegmentChangeFetcher.class), - 20L, 1, _segmentCacheProducer, Mockito.mock(TelemetryRuntimeProducer.class), - Mockito.mock(SplitCacheConsumer.class), null, Mockito.mock(RuleBasedSegmentCache.class)); + 20L, 1, _segmentCacheProducer, telemetryListener, + Mockito.mock(SplitCacheConsumer.class), executorFactory, null, Mockito.mock(RuleBasedSegmentCache.class)); Field synchronizerSegmentFetcher = SynchronizerImp.class.getDeclaredField("_segmentSynchronizationTaskImp"); synchronizerSegmentFetcher.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); diff --git a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java index d388d7b6d..e58b4a40f 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java @@ -12,9 +12,11 @@ import io.split.engine.common.FetchOptions; import io.split.rules.matchers.AllKeysMatcher; import io.split.rules.matchers.CombiningMatcher; +import io.split.engine.segments.ExecutorFactory; import io.split.engine.segments.SegmentChangeFetcher; import io.split.engine.segments.SegmentSynchronizationTask; import io.split.engine.segments.SegmentSynchronizationTaskImp; +import io.split.engine.segments.TelemetryListener; import io.split.grammar.Treatments; import io.split.telemetry.storage.InMemoryTelemetryStorage; import io.split.telemetry.storage.TelemetryRuntimeProducer; @@ -52,6 +54,8 @@ public class SplitFetcherTest { private static final Logger _log = LoggerFactory.getLogger(SplitFetcherTest.class); private static final TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); + private static final TelemetryListener TELEMETRY_LISTENER = t -> {}; + private static final ExecutorFactory EXECUTOR_FACTORY = (tf, name, n) -> java.util.concurrent.Executors.newScheduledThreadPool(n); private static final FlagSetsFilter FLAG_SETS_FILTER = new FlagSetsFilterImpl(new HashSet<>()); @Test @@ -159,7 +163,7 @@ public void whenParserFailsWeRemoveTheExperiment() throws InterruptedException { RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); SegmentChangeFetcher segmentChangeFetcher = mock(SegmentChangeFetcher.class); - SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1,10, segmentCache, TELEMETRY_STORAGE, cache, null, ruleBasedSegmentCache); + SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1, 10, segmentCache, TELEMETRY_LISTENER, cache, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); segmentSynchronizationTask.start(); SplitFetcherImp fetcher = new SplitFetcherImp(splitChangeFetcher, new SplitParser(), cache, TELEMETRY_STORAGE, FLAG_SETS_FILTER, ruleBasedSegmentParser, ruleBasedSegmentCache); @@ -184,7 +188,7 @@ public void ifThereIsAProblemTalkingToSplitChangeCountDownLatchIsNotDecremented( RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); SegmentChangeFetcher segmentChangeFetcher = mock(SegmentChangeFetcher.class); - SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1,10, segmentCache, TELEMETRY_STORAGE, cache, null, ruleBasedSegmentCache); + SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1, 10, segmentCache, TELEMETRY_LISTENER, cache, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); segmentSynchronizationTask.start(); SplitFetcherImp fetcher = new SplitFetcherImp(splitChangeFetcher, new SplitParser(), cache, TELEMETRY_STORAGE, FLAG_SETS_FILTER, ruleBasedSegmentParser, ruleBasedSegmentCache); @@ -286,7 +290,7 @@ public void worksWithUserDefinedSegments() throws Exception { SegmentChangeFetcher segmentChangeFetcher = mock(SegmentChangeFetcher.class); SegmentChange segmentChange = getSegmentChange(0L, 0L, segmentName); when(segmentChangeFetcher.fetch(anyString(), anyLong(), any())).thenReturn(segmentChange); - SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1,10, segmentCache, Mockito.mock(TelemetryStorage.class), cache, null, ruleBasedSegmentCache); + SegmentSynchronizationTask segmentSynchronizationTask = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1, 10, segmentCache, TELEMETRY_LISTENER, cache, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); segmentSynchronizationTask.start(); SplitFetcherImp fetcher = new SplitFetcherImp(experimentChangeFetcher, new SplitParser(), cache, TELEMETRY_STORAGE, FLAG_SETS_FILTER, ruleBasedSegmentParser, ruleBasedSegmentCache); diff --git a/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java b/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java index f6f7f04f4..c5099e429 100644 --- a/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java +++ b/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java @@ -1,7 +1,5 @@ package io.split.engine.segments; -import com.google.common.collect.Maps; -import io.split.Spec; import io.split.client.LocalhostSegmentChangeFetcher; import io.split.client.JsonLocalhostSplitChangeFetcher; import io.split.client.interceptors.FlagSetsFilter; @@ -11,12 +9,10 @@ import io.split.engine.common.FetchOptions; import io.split.engine.experiments.*; import io.split.storages.*; +import io.split.telemetry.storage.TelemetryRuntimeProducer; import io.split.storages.memory.InMemoryCacheImp; import io.split.storages.memory.RuleBasedSegmentCacheInMemoryImp; import io.split.storages.memory.SegmentCacheInMemoryImpl; -import io.split.telemetry.storage.InMemoryTelemetryStorage; -import io.split.telemetry.storage.NoopTelemetryStorage; -import io.split.telemetry.storage.TelemetryStorage; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; @@ -32,6 +28,7 @@ import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -47,8 +44,9 @@ */ public class SegmentSynchronizationTaskImpTest { private static final Logger _log = LoggerFactory.getLogger(SegmentSynchronizationTaskImpTest.class); - private static final TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); - private static final TelemetryStorage TELEMETRY_STORAGE_NOOP = Mockito.mock(NoopTelemetryStorage.class); + private static final TelemetryListener TELEMETRY_STORAGE = t -> {}; + private static final TelemetryListener TELEMETRY_STORAGE_NOOP = t -> {}; + private static final ExecutorFactory EXECUTOR_FACTORY = (tf, name, n) -> java.util.concurrent.Executors.newScheduledThreadPool(n); private AtomicReference fetcher1 = null; private AtomicReference fetcher2 = null; @@ -65,7 +63,7 @@ public void works() { SegmentChangeFetcher segmentChangeFetcher = Mockito.mock(SegmentChangeFetcher.class); final SegmentSynchronizationTaskImp fetchers = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1L, 1, segmentCacheProducer, - TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), null, Mockito.mock(RuleBasedSegmentCache.class)); + TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), EXECUTOR_FACTORY, null, Mockito.mock(RuleBasedSegmentCache.class)); // create two tasks that will separately call segment and make sure @@ -104,13 +102,13 @@ public void run() { @Test public void testFetchAllAsynchronousAndGetFalse() throws NoSuchFieldException, IllegalAccessException { SegmentCacheProducer segmentCacheProducer = Mockito.mock(SegmentCacheProducer.class); - ConcurrentMap _segmentFetchers = Maps.newConcurrentMap(); + ConcurrentMap _segmentFetchers = new ConcurrentHashMap<>(); SegmentChangeFetcher segmentChangeFetcher = Mockito.mock(SegmentChangeFetcher.class); SegmentFetcherImp segmentFetcher = Mockito.mock(SegmentFetcherImp.class); _segmentFetchers.put("SF", segmentFetcher); final SegmentSynchronizationTaskImp fetchers = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1L, 1, - segmentCacheProducer, TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), null, Mockito.mock(RuleBasedSegmentCache.class)); + segmentCacheProducer, TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), EXECUTOR_FACTORY, null, Mockito.mock(RuleBasedSegmentCache.class)); Mockito.when(segmentFetcher.runWhitCacheHeader()).thenReturn(false); Mockito.when(segmentFetcher.fetch(Mockito.anyObject())).thenReturn(false); @@ -130,11 +128,11 @@ public void testFetchAllAsynchronousAndGetFalse() throws NoSuchFieldException, I public void testFetchAllAsynchronousAndGetTrue() throws NoSuchFieldException, IllegalAccessException { SegmentCacheProducer segmentCacheProducer = Mockito.mock(SegmentCacheProducer.class); - ConcurrentMap _segmentFetchers = Maps.newConcurrentMap(); + ConcurrentMap _segmentFetchers = new ConcurrentHashMap<>(); SegmentChangeFetcher segmentChangeFetcher = Mockito.mock(SegmentChangeFetcher.class); SegmentFetcherImp segmentFetcher = Mockito.mock(SegmentFetcherImp.class); final SegmentSynchronizationTaskImp fetchers = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1L, 1, segmentCacheProducer, - TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), null, Mockito.mock(RuleBasedSegmentCache.class)); + TELEMETRY_STORAGE, Mockito.mock(SplitCacheConsumer.class), EXECUTOR_FACTORY, null, Mockito.mock(RuleBasedSegmentCache.class)); // Before executing, we'll update the map of segmentFecthers via reflection. Field segmentFetchersForced = SegmentSynchronizationTaskImp.class.getDeclaredField("_segmentFetchers"); @@ -162,7 +160,7 @@ public void testLocalhostSegmentChangeFetcher() throws InterruptedException, Fil RuleBasedSegmentCache ruleBasedSegmentCache = new RuleBasedSegmentCacheInMemoryImp(); RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); - SplitFetcher splitFetcher = new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, TELEMETRY_STORAGE_NOOP, flagSetsFilter, + SplitFetcher splitFetcher = new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, Mockito.mock(TelemetryRuntimeProducer.class), flagSetsFilter, ruleBasedSegmentParser, ruleBasedSegmentCache); SplitSynchronizationTask splitSynchronizationTask = new SplitSynchronizationTask(splitFetcher, splitCacheProducer, 1000, null); @@ -175,7 +173,7 @@ public void testLocalhostSegmentChangeFetcher() throws InterruptedException, Fil SegmentCacheProducer segmentCacheProducer = new SegmentCacheInMemoryImpl(); SegmentSynchronizationTaskImp segmentSynchronizationTaskImp = new SegmentSynchronizationTaskImp(segmentChangeFetcher, 1000, 1, segmentCacheProducer, - TELEMETRY_STORAGE_NOOP, splitCacheProducer, null, ruleBasedSegmentCache); + TELEMETRY_STORAGE_NOOP, splitCacheProducer, EXECUTOR_FACTORY, null, ruleBasedSegmentCache); segmentSynchronizationTaskImp.start(); diff --git a/parsing-commons/pom.xml b/parsing-commons/pom.xml new file mode 100644 index 000000000..f16bbb366 --- /dev/null +++ b/parsing-commons/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + io.split.client + java-client-parent + 4.18.3 + + + 4.18.3 + parsing-commons + jar + Parsing Commons + DTOs and parsing utilities shared between Split SDK modules + + + + io.split.client + targeting-engine + ${project.version} + + + junit + junit + 4.13.1 + test + + + org.mockito + mockito-core + 5.14.2 + test + + + diff --git a/client/src/main/java/io/split/client/dtos/BetweenMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/BetweenMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/BetweenMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/BetweenMatcherData.java diff --git a/client/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java diff --git a/client/src/main/java/io/split/client/dtos/Condition.java b/parsing-commons/src/main/java/io/split/client/dtos/Condition.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/Condition.java rename to parsing-commons/src/main/java/io/split/client/dtos/Condition.java diff --git a/client/src/main/java/io/split/client/dtos/ConditionType.java b/parsing-commons/src/main/java/io/split/client/dtos/ConditionType.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/ConditionType.java rename to parsing-commons/src/main/java/io/split/client/dtos/ConditionType.java diff --git a/client/src/main/java/io/split/client/dtos/DataType.java b/parsing-commons/src/main/java/io/split/client/dtos/DataType.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/DataType.java rename to parsing-commons/src/main/java/io/split/client/dtos/DataType.java diff --git a/client/src/main/java/io/split/client/dtos/DependencyMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/DependencyMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/DependencyMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/DependencyMatcherData.java diff --git a/client/src/main/java/io/split/client/dtos/Excluded.java b/parsing-commons/src/main/java/io/split/client/dtos/Excluded.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/Excluded.java rename to parsing-commons/src/main/java/io/split/client/dtos/Excluded.java diff --git a/client/src/main/java/io/split/client/dtos/ExcludedSegments.java b/parsing-commons/src/main/java/io/split/client/dtos/ExcludedSegments.java similarity index 80% rename from client/src/main/java/io/split/client/dtos/ExcludedSegments.java rename to parsing-commons/src/main/java/io/split/client/dtos/ExcludedSegments.java index 9e65fa60f..690ca677d 100644 --- a/client/src/main/java/io/split/client/dtos/ExcludedSegments.java +++ b/parsing-commons/src/main/java/io/split/client/dtos/ExcludedSegments.java @@ -1,8 +1,8 @@ package io.split.client.dtos; public class ExcludedSegments { - static final String STANDARD_TYPE = "standard"; - static final String RULE_BASED_TYPE = "rule-based"; + public static final String STANDARD_TYPE = "standard"; + public static final String RULE_BASED_TYPE = "rule-based"; public ExcludedSegments() {} public ExcludedSegments(String type, String name) { diff --git a/client/src/main/java/io/split/client/dtos/KeySelector.java b/parsing-commons/src/main/java/io/split/client/dtos/KeySelector.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/KeySelector.java rename to parsing-commons/src/main/java/io/split/client/dtos/KeySelector.java diff --git a/client/src/main/java/io/split/client/dtos/Matcher.java b/parsing-commons/src/main/java/io/split/client/dtos/Matcher.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/Matcher.java rename to parsing-commons/src/main/java/io/split/client/dtos/Matcher.java diff --git a/client/src/main/java/io/split/client/dtos/MatcherCombiner.java b/parsing-commons/src/main/java/io/split/client/dtos/MatcherCombiner.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/MatcherCombiner.java rename to parsing-commons/src/main/java/io/split/client/dtos/MatcherCombiner.java diff --git a/client/src/main/java/io/split/client/dtos/MatcherGroup.java b/parsing-commons/src/main/java/io/split/client/dtos/MatcherGroup.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/MatcherGroup.java rename to parsing-commons/src/main/java/io/split/client/dtos/MatcherGroup.java diff --git a/client/src/main/java/io/split/client/dtos/MatcherType.java b/parsing-commons/src/main/java/io/split/client/dtos/MatcherType.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/MatcherType.java rename to parsing-commons/src/main/java/io/split/client/dtos/MatcherType.java diff --git a/client/src/main/java/io/split/client/dtos/Partition.java b/parsing-commons/src/main/java/io/split/client/dtos/Partition.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/Partition.java rename to parsing-commons/src/main/java/io/split/client/dtos/Partition.java diff --git a/client/src/main/java/io/split/client/dtos/Status.java b/parsing-commons/src/main/java/io/split/client/dtos/Status.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/Status.java rename to parsing-commons/src/main/java/io/split/client/dtos/Status.java diff --git a/client/src/main/java/io/split/client/dtos/UnaryNumericMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/UnaryNumericMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/UnaryNumericMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/UnaryNumericMatcherData.java diff --git a/client/src/main/java/io/split/client/dtos/UserDefinedSegmentMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/UserDefinedSegmentMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/UserDefinedSegmentMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/UserDefinedSegmentMatcherData.java diff --git a/client/src/main/java/io/split/client/dtos/WhitelistMatcherData.java b/parsing-commons/src/main/java/io/split/client/dtos/WhitelistMatcherData.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/WhitelistMatcherData.java rename to parsing-commons/src/main/java/io/split/client/dtos/WhitelistMatcherData.java diff --git a/client/src/main/java/io/split/engine/evaluator/Labels.java b/parsing-commons/src/main/java/io/split/engine/evaluator/Labels.java similarity index 100% rename from client/src/main/java/io/split/engine/evaluator/Labels.java rename to parsing-commons/src/main/java/io/split/engine/evaluator/Labels.java diff --git a/client/src/main/java/io/split/engine/experiments/ParsedCondition.java b/parsing-commons/src/main/java/io/split/engine/experiments/ParsedCondition.java similarity index 100% rename from client/src/main/java/io/split/engine/experiments/ParsedCondition.java rename to parsing-commons/src/main/java/io/split/engine/experiments/ParsedCondition.java diff --git a/client/src/main/java/io/split/engine/experiments/ParserUtils.java b/parsing-commons/src/main/java/io/split/engine/experiments/ParserUtils.java similarity index 80% rename from client/src/main/java/io/split/engine/experiments/ParserUtils.java rename to parsing-commons/src/main/java/io/split/engine/experiments/ParserUtils.java index 9ada61159..685f3e115 100644 --- a/client/src/main/java/io/split/engine/experiments/ParserUtils.java +++ b/parsing-commons/src/main/java/io/split/engine/experiments/ParserUtils.java @@ -36,8 +36,7 @@ import java.util.ArrayList; import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; public final class ParserUtils { @@ -86,7 +85,7 @@ public static CombiningMatcher toMatcher(MatcherGroup matcherGroup) { } - private static io.split.rules.model.DataType toRulesDataType(io.split.client.dtos.DataType dt) { + private static io.split.rules.model.DataType toRulesDataType(DataType dt) { return io.split.rules.model.DataType.valueOf(dt.name()); } @@ -101,99 +100,99 @@ public static AttributeMatcher toMatcher(Matcher matcher) { delegate = new AllKeysMatcher(); break; case IN_SEGMENT: - checkNotNull(matcher.userDefinedSegmentMatcherData); + Objects.requireNonNull(matcher.userDefinedSegmentMatcherData); String segmentName = matcher.userDefinedSegmentMatcherData.segmentName; delegate = new UserDefinedSegmentMatcher(segmentName); break; case WHITELIST: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new WhitelistMatcher(matcher.whitelistMatcherData.whitelist); break; case EQUAL_TO: - checkNotNull(matcher.unaryNumericMatcherData); + Objects.requireNonNull(matcher.unaryNumericMatcherData); delegate = new EqualToMatcher(matcher.unaryNumericMatcherData.value, toRulesDataType(matcher.unaryNumericMatcherData.dataType)); break; case GREATER_THAN_OR_EQUAL_TO: - checkNotNull(matcher.unaryNumericMatcherData); + Objects.requireNonNull(matcher.unaryNumericMatcherData); delegate = new GreaterThanOrEqualToMatcher( matcher.unaryNumericMatcherData.value, toRulesDataType(matcher.unaryNumericMatcherData.dataType)); break; case LESS_THAN_OR_EQUAL_TO: - checkNotNull(matcher.unaryNumericMatcherData); + Objects.requireNonNull(matcher.unaryNumericMatcherData); delegate = new LessThanOrEqualToMatcher( matcher.unaryNumericMatcherData.value, toRulesDataType(matcher.unaryNumericMatcherData.dataType)); break; case BETWEEN: - checkNotNull(matcher.betweenMatcherData); + Objects.requireNonNull(matcher.betweenMatcherData); delegate = new BetweenMatcher(matcher.betweenMatcherData.start, matcher.betweenMatcherData.end, toRulesDataType(matcher.betweenMatcherData.dataType)); break; case EQUAL_TO_SET: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new EqualToSetMatcher(matcher.whitelistMatcherData.whitelist); break; case PART_OF_SET: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new PartOfSetMatcher(matcher.whitelistMatcherData.whitelist); break; case CONTAINS_ALL_OF_SET: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new ContainsAllOfSetMatcher(matcher.whitelistMatcherData.whitelist); break; case CONTAINS_ANY_OF_SET: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new ContainsAnyOfSetMatcher(matcher.whitelistMatcherData.whitelist); break; case STARTS_WITH: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new StartsWithAnyOfMatcher(matcher.whitelistMatcherData.whitelist); break; case ENDS_WITH: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new EndsWithAnyOfMatcher(matcher.whitelistMatcherData.whitelist); break; case CONTAINS_STRING: - checkNotNull(matcher.whitelistMatcherData); + Objects.requireNonNull(matcher.whitelistMatcherData); delegate = new ContainsAnyOfMatcher(matcher.whitelistMatcherData.whitelist); break; case MATCHES_STRING: - checkNotNull(matcher.stringMatcherData); + Objects.requireNonNull(matcher.stringMatcherData); delegate = new RegularExpressionMatcher(matcher.stringMatcherData); break; case IN_SPLIT_TREATMENT: - checkNotNull(matcher.dependencyMatcherData, + Objects.requireNonNull(matcher.dependencyMatcherData, "MatcherType is " + matcher.matcherType + ". matcher.dependencyMatcherData() MUST NOT BE null"); delegate = new DependencyMatcher(matcher.dependencyMatcherData.split, matcher.dependencyMatcherData.treatments); break; case EQUAL_TO_BOOLEAN: - checkNotNull(matcher.booleanMatcherData, + Objects.requireNonNull(matcher.booleanMatcherData, "MatcherType is " + matcher.matcherType + ". matcher.booleanMatcherData() MUST NOT BE null"); delegate = new BooleanMatcher(matcher.booleanMatcherData); break; case EQUAL_TO_SEMVER: - checkNotNull(matcher.stringMatcherData, "stringMatcherData is required for EQUAL_TO_SEMVER matcher type"); + Objects.requireNonNull(matcher.stringMatcherData, "stringMatcherData is required for EQUAL_TO_SEMVER matcher type"); delegate = new EqualToSemverMatcher(matcher.stringMatcherData); break; case GREATER_THAN_OR_EQUAL_TO_SEMVER: - checkNotNull(matcher.stringMatcherData, "stringMatcherData is required for GREATER_THAN_OR_EQUAL_TO_SEMVER matcher type"); + Objects.requireNonNull(matcher.stringMatcherData, "stringMatcherData is required for GREATER_THAN_OR_EQUAL_TO_SEMVER matcher type"); delegate = new GreaterThanOrEqualToSemverMatcher(matcher.stringMatcherData); break; case LESS_THAN_OR_EQUAL_TO_SEMVER: - checkNotNull(matcher.stringMatcherData, "stringMatcherData is required for LESS_THAN_OR_EQUAL_SEMVER matcher type"); + Objects.requireNonNull(matcher.stringMatcherData, "stringMatcherData is required for LESS_THAN_OR_EQUAL_SEMVER matcher type"); delegate = new LessThanOrEqualToSemverMatcher(matcher.stringMatcherData); break; case IN_LIST_SEMVER: - checkNotNull(matcher.whitelistMatcherData, "whitelistMatcherData is required for IN_LIST_SEMVER matcher type"); + Objects.requireNonNull(matcher.whitelistMatcherData, "whitelistMatcherData is required for IN_LIST_SEMVER matcher type"); delegate = new InListSemverMatcher(matcher.whitelistMatcherData.whitelist); break; case BETWEEN_SEMVER: - checkNotNull(matcher.betweenStringMatcherData, "betweenStringMatcherData is required for BETWEEN_SEMVER matcher type"); + Objects.requireNonNull(matcher.betweenStringMatcherData, "betweenStringMatcherData is required for BETWEEN_SEMVER matcher type"); delegate = new BetweenSemverMatcher(matcher.betweenStringMatcherData.start, matcher.betweenStringMatcherData.end); break; case IN_RULE_BASED_SEGMENT: - checkNotNull(matcher.userDefinedSegmentMatcherData); + Objects.requireNonNull(matcher.userDefinedSegmentMatcherData); String ruleBasedSegmentName = matcher.userDefinedSegmentMatcherData.segmentName; delegate = new RuleBasedSegmentMatcher(ruleBasedSegmentName); break; @@ -201,7 +200,7 @@ public static AttributeMatcher toMatcher(Matcher matcher) { throw new IllegalArgumentException("Unknown matcher type: " + matcher.matcherType); } - checkNotNull(delegate, "We were not able to create a matcher for: " + matcher.matcherType); + Objects.requireNonNull(delegate, "We were not able to create a matcher for: " + matcher.matcherType); String attribute = null; if (matcher.keySelector != null && matcher.keySelector.attribute != null) { @@ -213,4 +212,4 @@ public static AttributeMatcher toMatcher(Matcher matcher) { return new AttributeMatcher(attribute, delegate, negate); } -} \ No newline at end of file +} diff --git a/pom.xml b/pom.xml index 8df4d7ef9..e9e75f72f 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,8 @@ targeting-engine + parsing-commons + segment-commons pluggable-storage redis-wrapper testing diff --git a/segment-commons/pom.xml b/segment-commons/pom.xml new file mode 100644 index 000000000..eb0c2ccc1 --- /dev/null +++ b/segment-commons/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + io.split.client + java-client-parent + 4.18.3 + + + 4.18.3 + segment-commons + jar + Segment Commons + + + + io.split.client + parsing-commons + ${project.version} + + + org.slf4j + slf4j-api + 1.7.36 + + + + + junit + junit + 4.13.1 + test + + + org.mockito + mockito-core + 5.14.2 + test + + + diff --git a/client/src/main/java/io/split/client/dtos/RuleBasedSegment.java b/segment-commons/src/main/java/io/split/client/dtos/RuleBasedSegment.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/RuleBasedSegment.java rename to segment-commons/src/main/java/io/split/client/dtos/RuleBasedSegment.java diff --git a/client/src/main/java/io/split/client/dtos/SegmentChange.java b/segment-commons/src/main/java/io/split/client/dtos/SegmentChange.java similarity index 100% rename from client/src/main/java/io/split/client/dtos/SegmentChange.java rename to segment-commons/src/main/java/io/split/client/dtos/SegmentChange.java diff --git a/client/src/main/java/io/split/engine/common/FetchOptions.java b/segment-commons/src/main/java/io/split/engine/common/FetchOptions.java similarity index 95% rename from client/src/main/java/io/split/engine/common/FetchOptions.java rename to segment-commons/src/main/java/io/split/engine/common/FetchOptions.java index ff7a3d49d..11c8a5771 100644 --- a/client/src/main/java/io/split/engine/common/FetchOptions.java +++ b/segment-commons/src/main/java/io/split/engine/common/FetchOptions.java @@ -87,8 +87,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return com.google.common.base.Objects.hashCode(_cacheControlHeaders, - _targetCN, _flagSetsFilter); + return java.util.Objects.hash(_cacheControlHeaders, _targetCN, _flagSetsFilter); } private final boolean _cacheControlHeaders; diff --git a/client/src/main/java/io/split/engine/experiments/ParsedRuleBasedSegment.java b/segment-commons/src/main/java/io/split/engine/experiments/ParsedRuleBasedSegment.java similarity index 100% rename from client/src/main/java/io/split/engine/experiments/ParsedRuleBasedSegment.java rename to segment-commons/src/main/java/io/split/engine/experiments/ParsedRuleBasedSegment.java diff --git a/client/src/main/java/io/split/engine/experiments/RuleBasedSegmentParser.java b/segment-commons/src/main/java/io/split/engine/experiments/RuleBasedSegmentParser.java similarity index 100% rename from client/src/main/java/io/split/engine/experiments/RuleBasedSegmentParser.java rename to segment-commons/src/main/java/io/split/engine/experiments/RuleBasedSegmentParser.java diff --git a/client/src/main/java/io/split/engine/experiments/SyncTask.java b/segment-commons/src/main/java/io/split/engine/experiments/SyncTask.java similarity index 100% rename from client/src/main/java/io/split/engine/experiments/SyncTask.java rename to segment-commons/src/main/java/io/split/engine/experiments/SyncTask.java diff --git a/segment-commons/src/main/java/io/split/engine/segments/ExecutorFactory.java b/segment-commons/src/main/java/io/split/engine/segments/ExecutorFactory.java new file mode 100644 index 000000000..233ade6a6 --- /dev/null +++ b/segment-commons/src/main/java/io/split/engine/segments/ExecutorFactory.java @@ -0,0 +1,8 @@ +package io.split.engine.segments; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; + +public interface ExecutorFactory { + ScheduledExecutorService build(ThreadFactory threadFactory, String nameFormat, int numThreads); +} diff --git a/client/src/main/java/io/split/engine/segments/SegmentChangeFetcher.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentChangeFetcher.java similarity index 100% rename from client/src/main/java/io/split/engine/segments/SegmentChangeFetcher.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentChangeFetcher.java diff --git a/client/src/main/java/io/split/engine/segments/SegmentFetcher.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentFetcher.java similarity index 100% rename from client/src/main/java/io/split/engine/segments/SegmentFetcher.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentFetcher.java diff --git a/client/src/main/java/io/split/engine/segments/SegmentFetcherImp.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentFetcherImp.java similarity index 85% rename from client/src/main/java/io/split/engine/segments/SegmentFetcherImp.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentFetcherImp.java index 526ca02d1..a72df364c 100644 --- a/client/src/main/java/io/split/engine/segments/SegmentFetcherImp.java +++ b/segment-commons/src/main/java/io/split/engine/segments/SegmentFetcherImp.java @@ -2,16 +2,13 @@ import io.split.client.dtos.SegmentChange; import io.split.storages.SegmentCacheProducer; -import io.split.telemetry.domain.enums.LastSynchronizationRecordsEnum; -import io.split.telemetry.storage.TelemetryRuntimeProducer; import io.split.engine.common.FetchOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; public class SegmentFetcherImp implements SegmentFetcher { private static final Logger _log = LoggerFactory.getLogger(SegmentFetcherImp.class); @@ -19,16 +16,16 @@ public class SegmentFetcherImp implements SegmentFetcher { private final String _segmentName; private final SegmentChangeFetcher _segmentChangeFetcher; private final SegmentCacheProducer _segmentCacheProducer; - private final TelemetryRuntimeProducer _telemetryRuntimeProducer; + private final TelemetryListener _telemetryListener; private final Object _lock = new Object(); public SegmentFetcherImp(String segmentName, SegmentChangeFetcher segmentChangeFetcher, SegmentCacheProducer segmentCacheProducer, - TelemetryRuntimeProducer telemetryRuntimeProducer) { - _segmentName = checkNotNull(segmentName); - _segmentChangeFetcher = checkNotNull(segmentChangeFetcher); - _segmentCacheProducer = checkNotNull(segmentCacheProducer); - _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); + TelemetryListener telemetryListener) { + _segmentName = Objects.requireNonNull(segmentName); + _segmentChangeFetcher = Objects.requireNonNull(segmentChangeFetcher); + _segmentCacheProducer = Objects.requireNonNull(segmentCacheProducer); + _telemetryListener = Objects.requireNonNull(telemetryListener); _segmentCacheProducer.updateSegment(segmentName, new ArrayList<>(), new ArrayList<>(), -1L); } @@ -97,7 +94,7 @@ private void runWithoutExceptionHandling(FetchOptions options) { _log.info(_segmentName + " removed keys: " + summarize(change.removed)); } - _telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, System.currentTimeMillis()); + _telemetryListener.recordSuccessfulSync(System.currentTimeMillis()); } } diff --git a/client/src/main/java/io/split/engine/segments/SegmentImp.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentImp.java similarity index 100% rename from client/src/main/java/io/split/engine/segments/SegmentImp.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentImp.java diff --git a/client/src/main/java/io/split/engine/segments/SegmentSynchronizationTask.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentSynchronizationTask.java similarity index 100% rename from client/src/main/java/io/split/engine/segments/SegmentSynchronizationTask.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentSynchronizationTask.java diff --git a/client/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java b/segment-commons/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java similarity index 83% rename from client/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java rename to segment-commons/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java index 857493087..feedaf79f 100644 --- a/client/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java +++ b/segment-commons/src/main/java/io/split/engine/segments/SegmentSynchronizationTaskImp.java @@ -1,12 +1,9 @@ package io.split.engine.segments; -import com.google.common.collect.Maps; -import io.split.client.utils.SplitExecutorFactory; import io.split.engine.common.FetchOptions; +import io.split.storages.SegmentsProvider; import io.split.storages.RuleBasedSegmentCacheConsumer; import io.split.storages.SegmentCacheProducer; -import io.split.storages.SplitCacheConsumer; -import io.split.telemetry.storage.TelemetryRuntimeProducer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +11,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -26,9 +25,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - public class SegmentSynchronizationTaskImp implements SegmentSynchronizationTask, Closeable { private static final Logger _log = LoggerFactory.getLogger(SegmentSynchronizationTaskImp.class); @@ -36,30 +32,33 @@ public class SegmentSynchronizationTaskImp implements SegmentSynchronizationTask private final AtomicLong _refreshEveryNSeconds; private final AtomicBoolean _running; private final Object _lock = new Object(); - private final ConcurrentMap _segmentFetchers = Maps.newConcurrentMap(); + private final ConcurrentMap _segmentFetchers = new ConcurrentHashMap<>(); private final SegmentCacheProducer _segmentCacheProducer; private final ScheduledExecutorService _scheduledExecutorService; - private final TelemetryRuntimeProducer _telemetryRuntimeProducer; - private final SplitCacheConsumer _splitCacheConsumer; + private final TelemetryListener _telemetryListener; + private final SegmentsProvider _segmentsProvider; private final RuleBasedSegmentCacheConsumer _ruleBasedSegmentCacheConsumer; private ScheduledFuture _scheduledFuture; public SegmentSynchronizationTaskImp(SegmentChangeFetcher segmentChangeFetcher, long refreshEveryNSeconds, int numThreads, - SegmentCacheProducer segmentCacheProducer, TelemetryRuntimeProducer telemetryRuntimeProducer, - SplitCacheConsumer splitCacheConsumer, ThreadFactory threadFactory, + SegmentCacheProducer segmentCacheProducer, TelemetryListener telemetryListener, + SegmentsProvider segmentsProvider, ExecutorFactory executorFactory, + ThreadFactory threadFactory, RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer) { - _segmentChangeFetcher = checkNotNull(segmentChangeFetcher); + _segmentChangeFetcher = Objects.requireNonNull(segmentChangeFetcher); - checkArgument(refreshEveryNSeconds >= 0L); + if (refreshEveryNSeconds < 0L) { + throw new IllegalArgumentException("refreshEveryNSeconds must be non-negative"); + } _refreshEveryNSeconds = new AtomicLong(refreshEveryNSeconds); - _scheduledExecutorService = SplitExecutorFactory.buildScheduledExecutorService(threadFactory, "split-segmentFetcher-" + "%d", numThreads); + _scheduledExecutorService = executorFactory.build(threadFactory, "split-segmentFetcher-%d", numThreads); _running = new AtomicBoolean(false); - _segmentCacheProducer = checkNotNull(segmentCacheProducer); - _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); - _splitCacheConsumer = checkNotNull(splitCacheConsumer); - _ruleBasedSegmentCacheConsumer = checkNotNull(ruleBasedSegmentCacheConsumer); + _segmentCacheProducer = Objects.requireNonNull(segmentCacheProducer); + _telemetryListener = Objects.requireNonNull(telemetryListener); + _segmentsProvider = Objects.requireNonNull(segmentsProvider); + _ruleBasedSegmentCacheConsumer = Objects.requireNonNull(ruleBasedSegmentCacheConsumer); } public void initializeSegment(String segmentName) { @@ -77,7 +76,7 @@ public void initializeSegment(String segmentName) { return; } - SegmentFetcher newSegment = new SegmentFetcherImp(segmentName, _segmentChangeFetcher, _segmentCacheProducer, _telemetryRuntimeProducer); + SegmentFetcher newSegment = new SegmentFetcherImp(segmentName, _segmentChangeFetcher, _segmentCacheProducer, _telemetryListener); if (_running.get()) { _scheduledExecutorService.submit(() -> newSegment.fetch(new FetchOptions.Builder().build())); @@ -195,14 +194,14 @@ private void initialize(String segmentName) { return; } - segment = new SegmentFetcherImp(segmentName, _segmentChangeFetcher, _segmentCacheProducer, _telemetryRuntimeProducer); + segment = new SegmentFetcherImp(segmentName, _segmentChangeFetcher, _segmentCacheProducer, _telemetryListener); _segmentFetchers.putIfAbsent(segmentName, segment); } } private Set getSegmentNames() { - Set names = new HashSet<>(_splitCacheConsumer.getSegments()); + Set names = new HashSet<>(_segmentsProvider.getSegments()); names.addAll(_ruleBasedSegmentCacheConsumer.getSegments()); return names; diff --git a/segment-commons/src/main/java/io/split/engine/segments/TelemetryListener.java b/segment-commons/src/main/java/io/split/engine/segments/TelemetryListener.java new file mode 100644 index 000000000..78b8da527 --- /dev/null +++ b/segment-commons/src/main/java/io/split/engine/segments/TelemetryListener.java @@ -0,0 +1,5 @@ +package io.split.engine.segments; + +public interface TelemetryListener { + void recordSuccessfulSync(long time); +} diff --git a/client/src/main/java/io/split/storages/RuleBasedSegmentCache.java b/segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCache.java similarity index 100% rename from client/src/main/java/io/split/storages/RuleBasedSegmentCache.java rename to segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCache.java diff --git a/client/src/main/java/io/split/storages/RuleBasedSegmentCacheConsumer.java b/segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCacheConsumer.java similarity index 100% rename from client/src/main/java/io/split/storages/RuleBasedSegmentCacheConsumer.java rename to segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCacheConsumer.java diff --git a/client/src/main/java/io/split/storages/RuleBasedSegmentCacheProducer.java b/segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCacheProducer.java similarity index 100% rename from client/src/main/java/io/split/storages/RuleBasedSegmentCacheProducer.java rename to segment-commons/src/main/java/io/split/storages/RuleBasedSegmentCacheProducer.java diff --git a/client/src/main/java/io/split/storages/SegmentCache.java b/segment-commons/src/main/java/io/split/storages/SegmentCache.java similarity index 100% rename from client/src/main/java/io/split/storages/SegmentCache.java rename to segment-commons/src/main/java/io/split/storages/SegmentCache.java diff --git a/client/src/main/java/io/split/storages/SegmentCacheCommons.java b/segment-commons/src/main/java/io/split/storages/SegmentCacheCommons.java similarity index 100% rename from client/src/main/java/io/split/storages/SegmentCacheCommons.java rename to segment-commons/src/main/java/io/split/storages/SegmentCacheCommons.java diff --git a/client/src/main/java/io/split/storages/SegmentCacheConsumer.java b/segment-commons/src/main/java/io/split/storages/SegmentCacheConsumer.java similarity index 100% rename from client/src/main/java/io/split/storages/SegmentCacheConsumer.java rename to segment-commons/src/main/java/io/split/storages/SegmentCacheConsumer.java diff --git a/client/src/main/java/io/split/storages/SegmentCacheProducer.java b/segment-commons/src/main/java/io/split/storages/SegmentCacheProducer.java similarity index 100% rename from client/src/main/java/io/split/storages/SegmentCacheProducer.java rename to segment-commons/src/main/java/io/split/storages/SegmentCacheProducer.java diff --git a/segment-commons/src/main/java/io/split/storages/SegmentsProvider.java b/segment-commons/src/main/java/io/split/storages/SegmentsProvider.java new file mode 100644 index 000000000..2115ac749 --- /dev/null +++ b/segment-commons/src/main/java/io/split/storages/SegmentsProvider.java @@ -0,0 +1,7 @@ +package io.split.storages; + +import java.util.Set; + +public interface SegmentsProvider { + Set getSegments(); +} diff --git a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java b/segment-commons/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java similarity index 97% rename from client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java rename to segment-commons/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java index 660811ca8..e32eededb 100644 --- a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java +++ b/segment-commons/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java @@ -1,6 +1,5 @@ package io.split.storages.memory; -import com.google.common.collect.Maps; import io.split.engine.experiments.ParsedRuleBasedSegment; import io.split.storages.RuleBasedSegmentCache; @@ -11,6 +10,7 @@ import java.util.List; import java.util.Set; import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; @@ -29,7 +29,7 @@ public RuleBasedSegmentCacheInMemoryImp() { } public RuleBasedSegmentCacheInMemoryImp(long startingChangeNumber) { - _concurrentMap = Maps.newConcurrentMap(); + _concurrentMap = new ConcurrentHashMap<>(); _changeNumber = new AtomicLong(startingChangeNumber); } diff --git a/client/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java b/segment-commons/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java similarity index 93% rename from client/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java rename to segment-commons/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java index 72a375e99..d6c1636f8 100644 --- a/client/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java +++ b/segment-commons/src/main/java/io/split/storages/memory/SegmentCacheInMemoryImpl.java @@ -1,13 +1,12 @@ package io.split.storages.memory; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Maps; import io.split.engine.segments.SegmentImp; import io.split.storages.SegmentCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** @@ -17,7 +16,7 @@ public class SegmentCacheInMemoryImpl implements SegmentCache { private static final Logger _log = LoggerFactory.getLogger(SegmentCacheInMemoryImpl.class); private static final long DEFAULT_CHANGE_NUMBER = -1l; - private final ConcurrentMap _segments = Maps.newConcurrentMap(); + private final ConcurrentMap _segments = new ConcurrentHashMap<>(); @Override public void updateSegment(String segmentName, List toAdd, List toRemove, long changeNumber) { @@ -53,7 +52,6 @@ public long getChangeNumber(String segmentName) { return segmentImp.getChangeNumber(); } - @VisibleForTesting void clear() { _segments.clear(); } diff --git a/client/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java b/segment-commons/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java similarity index 91% rename from client/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java rename to segment-commons/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java index 0872fb45b..5edb6ad0d 100644 --- a/client/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java +++ b/segment-commons/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java @@ -4,9 +4,7 @@ import io.split.storages.SegmentCacheProducer; import io.split.storages.memory.SegmentCacheInMemoryImpl; import io.split.client.dtos.SegmentChange; -import io.split.telemetry.storage.InMemoryTelemetryStorage; -import io.split.telemetry.storage.TelemetryRuntimeProducer; -import io.split.telemetry.storage.TelemetryStorage; + import io.split.engine.common.FetchOptions; import org.junit.Assert; import org.junit.Test; @@ -33,7 +31,7 @@ public class SegmentFetcherImpTest { private static final Logger _log = LoggerFactory.getLogger(SegmentFetcherImpTest.class); private static final String SEGMENT_NAME = "foo"; - private static final TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); + private static final TelemetryListener TELEMETRY_LISTENER = t -> {}; @Test public void worksWhenWeStartWithoutState() throws InterruptedException { @@ -53,7 +51,7 @@ public void worksWhenThereAreNoChanges() throws InterruptedException { SegmentChange segmentChange = getSegmentChange(-1L, 10L); Mockito.when(segmentChangeFetcher.fetch(Mockito.anyString(), Mockito.anyLong(), Mockito.any())).thenReturn(segmentChange); - SegmentFetcherImp fetcher = new SegmentFetcherImp(SEGMENT_NAME, segmentChangeFetcher, segmentCache, TELEMETRY_STORAGE); + SegmentFetcherImp fetcher = new SegmentFetcherImp(SEGMENT_NAME, segmentChangeFetcher, segmentCache, TELEMETRY_LISTENER); // execute the fetcher for a little bit. ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); @@ -88,7 +86,7 @@ private void works(long startingChangeNumber) throws InterruptedException { Mockito.when(segmentChangeFetcher.fetch(Mockito.eq(SEGMENT_NAME),Mockito.eq( -1L), Mockito.any())).thenReturn(segmentChange); Mockito.when(segmentChangeFetcher.fetch(Mockito.eq(SEGMENT_NAME),Mockito.eq( 0L), Mockito.any())).thenReturn(segmentChange); - SegmentFetcher fetcher = new SegmentFetcherImp(segmentName, segmentChangeFetcher, segmentCacheProducer, Mockito.mock(TelemetryRuntimeProducer.class)); + SegmentFetcher fetcher = new SegmentFetcherImp(segmentName, segmentChangeFetcher, segmentCacheProducer, t -> {}); // execute the fetcher for a little bit. ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); @@ -106,28 +104,28 @@ private void works(long startingChangeNumber) throws InterruptedException { // reset the interrupt. Thread.currentThread().interrupt(); } - Mockito.verify(segmentChangeFetcher, Mockito.times(2)).fetch(Mockito.anyString(), Mockito.anyLong(), Mockito.anyObject()); + Mockito.verify(segmentChangeFetcher, Mockito.times(2)).fetch(Mockito.anyString(), Mockito.anyLong(), Mockito.any()); } @Test(expected = NullPointerException.class) public void doesNotWorkIfSegmentChangeFetcherIsNull() { SegmentCacheProducer segmentCacheProducer = Mockito.mock(SegmentCacheProducer.class); - SegmentFetcher fetcher = new SegmentFetcherImp(SEGMENT_NAME, null, segmentCacheProducer, TELEMETRY_STORAGE); + SegmentFetcher fetcher = new SegmentFetcherImp(SEGMENT_NAME, null, segmentCacheProducer, TELEMETRY_LISTENER); } @Test(expected = NullPointerException.class) public void doesNotWorkIfSegmentNameIsNull() { SegmentCacheProducer segmentCacheProducer = Mockito.mock(SegmentCacheProducer.class); SegmentChangeFetcher segmentChangeFetcher = Mockito.mock(SegmentChangeFetcher.class); - SegmentFetcher fetcher = new SegmentFetcherImp(null, segmentChangeFetcher, segmentCacheProducer, TELEMETRY_STORAGE); + SegmentFetcher fetcher = new SegmentFetcherImp(null, segmentChangeFetcher, segmentCacheProducer, TELEMETRY_LISTENER); } @Test public void testBypassCdnClearedAfterFirstHit() { SegmentChangeFetcher mockFetcher = Mockito.mock(SegmentChangeFetcher.class); SegmentCache segmentCacheMock = new SegmentCacheInMemoryImpl(); - SegmentFetcher fetcher = new SegmentFetcherImp("someSegment", mockFetcher, segmentCacheMock, Mockito.mock(TelemetryRuntimeProducer.class)); + SegmentFetcher fetcher = new SegmentFetcherImp("someSegment", mockFetcher, segmentCacheMock, t -> {}); SegmentChange response1 = new SegmentChange();