Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ 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.0-SNAPSHOT'
version = '3.0.1-SNAPSHOT'
ext.isReleaseVersion = !version.endsWith("SNAPSHOT")

import org.apache.tools.ant.filters.ReplaceTokens
Expand All @@ -25,10 +30,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
Expand Down Expand Up @@ -128,16 +134,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')
}
49 changes: 42 additions & 7 deletions src/main/java/com/eppo/sdk/EppoClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
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);

Expand Down Expand Up @@ -40,63 +46,92 @@ 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 {
Expand Down
4 changes: 3 additions & 1 deletion src/test/java/com/eppo/sdk/EppoClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@

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;
import cloud.eppo.logging.Assignment;
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;
Expand Down