diff --git a/client/src/main/java/io/split/client/ApiKeyCounter.java b/client/src/main/java/io/split/client/ApiKeyCounter.java new file mode 100644 index 000000000..8c39394dd --- /dev/null +++ b/client/src/main/java/io/split/client/ApiKeyCounter.java @@ -0,0 +1,66 @@ +package io.split.client; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ConcurrentHashMultiset; +import com.google.common.collect.Multiset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ApiKeyCounter { + + private static final Logger _log = LoggerFactory.getLogger(ApiKeyCounter.class); + private static final Multiset USED_API_KEYS = ConcurrentHashMultiset.create(); + + private ApiKeyCounter() {} + + public static ApiKeyCounter getApiKeyCounterInstance() { + return ApyKeyCounterHolder.INSTANCE; + } + + //Inner class to provide instance of class + private static class ApyKeyCounterHolder + { + private static final ApiKeyCounter INSTANCE = new ApiKeyCounter(); + } + + public void add(String apiKey) { + String message; + if (USED_API_KEYS.contains(apiKey)) { + message = String.format("factory instantiation: You already have %s with this API Key. " + + "We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing " + + "it throughout your application.", + USED_API_KEYS.count(apiKey) == 1 ? "1 factory" : String.format("%s factories", USED_API_KEYS.count(apiKey))); + _log.warn(message); + } else if (!USED_API_KEYS.isEmpty()) { + message = "factory instantiation: You already have an instance of the Split factory. " + + "Make sure you definitely want this additional instance. We recommend keeping only one instance of " + + "the factory at all times (Singleton pattern) and reusing it throughout your application.“"; + _log.warn(message); + } + USED_API_KEYS.add(apiKey); + } + + public void remove(String apiKey) { + USED_API_KEYS.remove(apiKey); + } + + /** + * Just for test + * @param apiKey + * @return + */ + @VisibleForTesting + boolean isApiKeyPresent(String apiKey) { + return USED_API_KEYS.contains(apiKey); + } + + /** + * Just for test + * @param apiKey + * @return + */ + @VisibleForTesting + int getCount(String apiKey) { + return USED_API_KEYS.count(apiKey); + } +} diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 12823fcde..c521e6bae 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -1,7 +1,5 @@ package io.split.client; -import com.google.common.collect.ConcurrentHashMultiset; -import com.google.common.collect.Multiset; import io.split.client.impressions.AsynchronousImpressionListener; import io.split.client.impressions.ImpressionListener; import io.split.client.impressions.ImpressionsManagerImpl; @@ -62,7 +60,6 @@ public class SplitFactoryImpl implements SplitFactory { private final static long SSE_CONNECT_TIMEOUT = 30000; private final static long SSE_SOCKET_TIMEOUT = 70000; - private static final Multiset USED_API_TOKENS = ConcurrentHashMultiset.create(); private static Random RANDOM = new Random(); private final SplitClient _client; @@ -70,23 +67,12 @@ public class SplitFactoryImpl implements SplitFactory { private final Runnable destroyer; private final String _apiToken; private boolean isTerminated = false; + private final ApiKeyCounter _apiKeyCounter; public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyntaxException { _apiToken = apiToken; - - if (USED_API_TOKENS.contains(apiToken)) { - String message = String.format("factory instantiation: You already have %s with this API Key. " + - "We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing " + - "it throughout your application.", - USED_API_TOKENS.count(apiToken) == 1 ? "1 factory" : String.format("%s factories", USED_API_TOKENS.count(apiToken))); - _log.warn(message); - } else if (!USED_API_TOKENS.isEmpty()) { - String message = "factory instantiation: You already have an instance of the Split factory. " + - "Make sure you definitely want this additional instance. We recommend keeping only one instance of " + - "the factory at all times (Singleton pattern) and reusing it throughout your application.“"; - _log.warn(message); - } - USED_API_TOKENS.add(apiToken); + _apiKeyCounter = ApiKeyCounter.getApiKeyCounterInstance(); + _apiKeyCounter.add(apiToken); if (config.blockUntilReady() == -1) { //BlockUntilReady not been set @@ -214,7 +200,7 @@ public void destroy() { synchronized (SplitFactoryImpl.class) { if (!isTerminated) { destroyer.run(); - USED_API_TOKENS.remove(_apiToken); + _apiKeyCounter.remove(_apiToken); isTerminated = true; } } diff --git a/client/src/test/java/io/split/client/ApiKeyCounterTest.java b/client/src/test/java/io/split/client/ApiKeyCounterTest.java new file mode 100644 index 000000000..c017127ce --- /dev/null +++ b/client/src/test/java/io/split/client/ApiKeyCounterTest.java @@ -0,0 +1,50 @@ +package io.split.client; + +import junit.framework.TestCase; +import org.junit.Test; + +public class ApiKeyCounterTest extends TestCase { + + private static final String FIRST_KEY = "KEYNUMBER1"; + private static final String SECOND_KEY = "KEYNUMBER2"; + + @Test + public void testAddingNewToken() { + ApiKeyCounter.getApiKeyCounterInstance().add(FIRST_KEY); + assertTrue(ApiKeyCounter.getApiKeyCounterInstance().isApiKeyPresent(FIRST_KEY)); + + ApiKeyCounter.getApiKeyCounterInstance().remove(FIRST_KEY); + } + + @Test + public void testAddingExistingToken() { + ApiKeyCounter.getApiKeyCounterInstance().add(FIRST_KEY); + ApiKeyCounter.getApiKeyCounterInstance().add(FIRST_KEY); + + assertTrue(ApiKeyCounter.getApiKeyCounterInstance().isApiKeyPresent(FIRST_KEY)); + assertEquals(2, ApiKeyCounter.getApiKeyCounterInstance().getCount(FIRST_KEY)); + ApiKeyCounter.getApiKeyCounterInstance().remove(FIRST_KEY); + ApiKeyCounter.getApiKeyCounterInstance().remove(FIRST_KEY); + } + + @Test + public void testRemovingToken() { + ApiKeyCounter.getApiKeyCounterInstance().add(FIRST_KEY); + ApiKeyCounter.getApiKeyCounterInstance().remove(FIRST_KEY); + + assertFalse(ApiKeyCounter.getApiKeyCounterInstance().isApiKeyPresent(FIRST_KEY)); + assertEquals(0, ApiKeyCounter.getApiKeyCounterInstance().getCount(FIRST_KEY)); + } + + @Test + public void testAddingNonExistingToken() { + ApiKeyCounter.getApiKeyCounterInstance().add(FIRST_KEY); + ApiKeyCounter.getApiKeyCounterInstance().add(SECOND_KEY); + + assertTrue(ApiKeyCounter.getApiKeyCounterInstance().isApiKeyPresent(FIRST_KEY)); + assertEquals(1, ApiKeyCounter.getApiKeyCounterInstance().getCount(FIRST_KEY)); + assertEquals(1, ApiKeyCounter.getApiKeyCounterInstance().getCount(SECOND_KEY)); + ApiKeyCounter.getApiKeyCounterInstance().remove(FIRST_KEY); + ApiKeyCounter.getApiKeyCounterInstance().remove(SECOND_KEY); + } +}