From fc31b227a677da031f5f55e28af4a456dab901e6 Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Fri, 16 Aug 2024 12:56:30 -0600 Subject: [PATCH 1/3] wip --- build.gradle | 19 +++--- src/main/java/com/eppo/sdk/EppoClient.java | 59 ++++++++++++++++--- .../java/com/eppo/sdk/EppoClientTest.java | 4 +- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index ea1e46a..e5048b5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'cloud.eppo' -version = '3.0.0-SNAPSHOT' +version = '3.0.1-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") import org.apache.tools.ant.filters.ReplaceTokens @@ -25,10 +25,11 @@ repositories { } dependencies { - implementation 'cloud.eppo:sdk-common-jvm:3.0.1-SNAPSHOT' + // Re-export classes and interfaces that will be used upstream + api 'cloud.eppo:sdk-common-jvm:3.0.2-SNAPSHOT' + implementation 'com.github.zafarkhaja:java-semver:0.10.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' - implementation 'org.apache.httpcomponents:httpclient:4.5.14' implementation 'org.ehcache:ehcache:3.10.8' implementation 'org.slf4j:slf4j-api:2.0.13' // Logback classic 1.3.x is compatible with java 8 @@ -128,16 +129,18 @@ publishing { } } -signing { - sign publishing.publications.mavenJava - if (System.env['CI']) { - useInMemoryPgpKeys(System.env.GPG_PRIVATE_KEY, System.env.GPG_PASSPHRASE) +if (!project.gradle.startParameter.taskNames.contains('publishToMavenLocal')) { + signing { + sign publishing.publications.mavenJava + if (System.env['CI']) { + useInMemoryPgpKeys(System.env.GPG_PRIVATE_KEY, System.env.GPG_PASSPHRASE) + } } } - javadoc { if (JavaVersion.current().isJava9Compatible()) { options.addBooleanOption('html5', true) } + options.addStringOption('Xdoclint:none', '-quiet') } diff --git a/src/main/java/com/eppo/sdk/EppoClient.java b/src/main/java/com/eppo/sdk/EppoClient.java index 78b0609..5994435 100644 --- a/src/main/java/com/eppo/sdk/EppoClient.java +++ b/src/main/java/com/eppo/sdk/EppoClient.java @@ -9,6 +9,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Class used to ingest and use the flag and bandit configurations retrieved from Eppo + * This class uses the Singleton pattern. First the singleton must be initialized + * via it's Builder's buildAndInit() method. + * Then call getInstance() to access the singleton and call methods to get + * assignments and bandit actions. + */ public class EppoClient extends BaseEppoClient { private static final Logger log = LoggerFactory.getLogger(EppoClient.class); @@ -40,63 +47,101 @@ private EppoClient( apiKey, host, sdkName, sdkVersion, assignmentLogger, banditLogger, isGracefulModel, false); } + /** + * Stops the client from polling Eppo for updated flag and bandit configurations + */ public static void stopPolling() { if (pollTimer != null) { pollTimer.cancel(); } } + /** + * Builder pattern to initialize the EppoClient singleton + */ public static class Builder { private String apiKey; - private String host = DEFAULT_HOST; private AssignmentLogger assignmentLogger; private BanditLogger banditLogger; private boolean isGracefulMode = DEFAULT_IS_GRACEFUL_MODE; private boolean forceReinitialize = DEFAULT_FORCE_REINITIALIZE; private long pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS; + private String host = DEFAULT_HOST; + /** + * Sets the API Key--created within the eppo application--to use. + * This is required. + */ public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; } - public Builder host(String host) { - this.host = host; - return this; - } - + /** + * Assignment logger to use to record when variations were assigned. + * This is needed if you want Eppo to analyze experiments controlled by flags. + */ public Builder assignmentLogger(AssignmentLogger assignmentLogger) { this.assignmentLogger = assignmentLogger; return this; } + /** + * Bandit logger to use to record when a bandit has assigned an action. + * This is needed if you are using contextual multi-armed bandits. + */ public Builder banditLogger(BanditLogger banditLogger) { this.banditLogger = banditLogger; return this; } + /** + * Sets the initial graceful mode of the client. When on (which is the default), + * flag evaluation errors will be caught, and the default value returned. When off, + * the errors will be rethrown. + */ public Builder isGracefulMode(boolean isGracefulMode) { this.isGracefulMode = isGracefulMode; return this; } + /** + * Sets whether the singleton client should be recreated if one already has been. + * fetch an updated configuration. If true, a new client will be instantiated and a new + * fetch for configurations will be performed. If false (which is the default), + * initialization will be ignored and the previously initialized client will be used. + */ public Builder forceReinitialize(boolean forceReinitialize) { this.forceReinitialize = forceReinitialize; return this; } + /** + * Sets how often the client should check for updated configurations, in milliseconds. + * The default is 30,000 (poll every 30 seconds). + */ public Builder pollingIntervalMs(long pollingIntervalMs) { this.pollingIntervalMs = pollingIntervalMs; return this; } + /** + * Overrides the host from where it fetches configurations. + * This typically should not be explicitly set so that the default of the + * Fastly CDN is used. + */ + public Builder host(String host) { + this.host = host; + return this; + } + public EppoClient buildAndInit() { AppDetails appDetails = AppDetails.getInstance(); String sdkName = appDetails.getName(); String sdkVersion = appDetails.getVersion(); if (instance != null) { - if (forceReinitialize) { // TODO: unit test this + if (forceReinitialize) { log.warn( "Eppo SDK is already initialized, reinitializing since forceReinitialize is true"); } else { diff --git a/src/test/java/com/eppo/sdk/EppoClientTest.java b/src/test/java/com/eppo/sdk/EppoClientTest.java index 7f7ef12..d71a14f 100644 --- a/src/test/java/com/eppo/sdk/EppoClientTest.java +++ b/src/test/java/com/eppo/sdk/EppoClientTest.java @@ -10,6 +10,9 @@ import cloud.eppo.BaseEppoClient; import cloud.eppo.EppoHttpClient; +import cloud.eppo.api.Attributes; +import cloud.eppo.api.BanditActions; +import cloud.eppo.api.BanditResult; import cloud.eppo.helpers.AssignmentTestCase; import cloud.eppo.helpers.BanditTestCase; import cloud.eppo.helpers.TestUtils; @@ -17,7 +20,6 @@ import cloud.eppo.logging.AssignmentLogger; import cloud.eppo.logging.BanditAssignment; import cloud.eppo.logging.BanditLogger; -import cloud.eppo.ufc.dto.*; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; From 98930c7523357cd30b057aaaaaab00acf122e397 Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Fri, 16 Aug 2024 13:34:32 -0600 Subject: [PATCH 2/3] target Java 8 --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index e5048b5..ae2597d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,11 @@ plugins { id "com.diffplug.spotless" version "6.13.0" } +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + group = 'cloud.eppo' version = '3.0.1-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From 95325cbb598665eb5bc0622559b386c1e6710488 Mon Sep 17 00:00:00 2001 From: Aaron Silverman Date: Fri, 16 Aug 2024 14:13:01 -0600 Subject: [PATCH 3/3] =?UTF-8?q?linter=20=F0=9F=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/eppo/sdk/EppoClient.java | 50 +++++++++------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/eppo/sdk/EppoClient.java b/src/main/java/com/eppo/sdk/EppoClient.java index 5994435..d3509a2 100644 --- a/src/main/java/com/eppo/sdk/EppoClient.java +++ b/src/main/java/com/eppo/sdk/EppoClient.java @@ -10,10 +10,9 @@ import org.slf4j.LoggerFactory; /** - * Class used to ingest and use the flag and bandit configurations retrieved from Eppo - * This class uses the Singleton pattern. First the singleton must be initialized - * via it's Builder's buildAndInit() method. - * Then call getInstance() to access the singleton and call methods to get + * Class used to ingest and use the flag and bandit configurations retrieved from Eppo This class + * uses the Singleton pattern. First the singleton must be initialized via it's Builder's + * buildAndInit() method. Then call getInstance() to access the singleton and call methods to get * assignments and bandit actions. */ public class EppoClient extends BaseEppoClient { @@ -47,18 +46,14 @@ private EppoClient( apiKey, host, sdkName, sdkVersion, assignmentLogger, banditLogger, isGracefulModel, false); } - /** - * Stops the client from polling Eppo for updated flag and bandit configurations - */ + /** Stops the client from polling Eppo for updated flag and bandit configurations */ public static void stopPolling() { if (pollTimer != null) { pollTimer.cancel(); } } - /** - * Builder pattern to initialize the EppoClient singleton - */ + /** Builder pattern to initialize the EppoClient singleton */ public static class Builder { private String apiKey; private AssignmentLogger assignmentLogger; @@ -68,18 +63,15 @@ public static class Builder { private long pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS; private String host = DEFAULT_HOST; - /** - * Sets the API Key--created within the eppo application--to use. - * This is required. - */ + /** Sets the API Key--created within the eppo application--to use. This is required. */ public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; } /** - * Assignment logger to use to record when variations were assigned. - * This is needed if you want Eppo to analyze experiments controlled by flags. + * Assignment logger to use to record when variations were assigned. This is needed if you want + * Eppo to analyze experiments controlled by flags. */ public Builder assignmentLogger(AssignmentLogger assignmentLogger) { this.assignmentLogger = assignmentLogger; @@ -87,8 +79,8 @@ public Builder assignmentLogger(AssignmentLogger assignmentLogger) { } /** - * Bandit logger to use to record when a bandit has assigned an action. - * This is needed if you are using contextual multi-armed bandits. + * Bandit logger to use to record when a bandit has assigned an action. This is needed if you + * are using contextual multi-armed bandits. */ public Builder banditLogger(BanditLogger banditLogger) { this.banditLogger = banditLogger; @@ -96,9 +88,8 @@ public Builder banditLogger(BanditLogger banditLogger) { } /** - * Sets the initial graceful mode of the client. When on (which is the default), - * flag evaluation errors will be caught, and the default value returned. When off, - * the errors will be rethrown. + * Sets the initial graceful mode of the client. When on (which is the default), flag evaluation + * errors will be caught, and the default value returned. When off, the errors will be rethrown. */ public Builder isGracefulMode(boolean isGracefulMode) { this.isGracefulMode = isGracefulMode; @@ -106,10 +97,10 @@ public Builder isGracefulMode(boolean isGracefulMode) { } /** - * Sets whether the singleton client should be recreated if one already has been. - * fetch an updated configuration. If true, a new client will be instantiated and a new - * fetch for configurations will be performed. If false (which is the default), - * initialization will be ignored and the previously initialized client will be used. + * Sets whether the singleton client should be recreated if one already has been. fetch an + * updated configuration. If true, a new client will be instantiated and a new fetch for + * configurations will be performed. If false (which is the default), initialization will be + * ignored and the previously initialized client will be used. */ public Builder forceReinitialize(boolean forceReinitialize) { this.forceReinitialize = forceReinitialize; @@ -117,8 +108,8 @@ public Builder forceReinitialize(boolean forceReinitialize) { } /** - * Sets how often the client should check for updated configurations, in milliseconds. - * The default is 30,000 (poll every 30 seconds). + * Sets how often the client should check for updated configurations, in milliseconds. The + * default is 30,000 (poll every 30 seconds). */ public Builder pollingIntervalMs(long pollingIntervalMs) { this.pollingIntervalMs = pollingIntervalMs; @@ -126,9 +117,8 @@ public Builder pollingIntervalMs(long pollingIntervalMs) { } /** - * Overrides the host from where it fetches configurations. - * This typically should not be explicitly set so that the default of the - * Fastly CDN is used. + * Overrides the host from where it fetches configurations. This typically should not be + * explicitly set so that the default of the Fastly CDN is used. */ public Builder host(String host) { this.host = host;