Skip to content

Commit

Permalink
feat(java): Configuration overrides (#189)
Browse files Browse the repository at this point in the history
* refactor(java): Thread Configuration through request builders

* refactor(java): Thread Configuration through requests

* feat(java): Introduce ConfigurationOverride class

* test(java): Add tests on ConfigurationOverride

* refactor(java): Consistent code in Configuration.override(...)
  • Loading branch information
booniepepper authored Aug 24, 2023
1 parent 7abf4c9 commit bf4a7c6
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 27 deletions.
4 changes: 4 additions & 0 deletions config/clients/java/config.overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
"destinationFilename": "src/main/java/dev/openfga/sdk/api/client/Configuration.java",
"templateType": "SupportingFiles"
},
"config-ConfigurationOverride.java.mustache" : {
"destinationFilename": "src/main/java/dev/openfga/sdk/api/client/ConfigurationOverride.java",
"templateType": "SupportingFiles"
},
"config-ConfigurationTest.java.mustache" : {
"destinationFilename": "src/test/java/dev/openfga/sdk/api/client/ConfigurationTest.java",
"templateType": "SupportingFiles"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import dev.openfga.sdk.errors.FgaInvalidParameterException;
import java.time.Duration;

public interface BaseConfiguration {
void assertValid() throws FgaInvalidParameterException;
String getApiUrl();
String getUserAgent();
Expand Down
43 changes: 36 additions & 7 deletions config/clients/java/template/config-Configuration.java.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import java.net.http.HttpClient;
import java.net.http.HttpConnectTimeoutException;
import java.net.http.HttpRequest;
import java.time.Duration;
import java.util.regex.Pattern;

/**
* Configurations for an ApiClient.
* Configurations for an api client.
*/
public class Configuration implements BaseConfiguration {
public static final String VERSION = "{{packageVersion}}";
Expand All @@ -29,6 +28,13 @@ public class Configuration implements BaseConfiguration {
private Duration readTimeout;
private Duration connectTimeout;
public Configuration() {
this.apiUrl = DEFAULT_API_URL;
this.userAgent = DEFAULT_USER_AGENT;
this.readTimeout = DEFAULT_READ_TIMEOUT;
this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
}

public Configuration(String apiUrl) {
this.apiUrl = apiUrl;
this.userAgent = DEFAULT_USER_AGENT;
Expand All @@ -39,7 +45,6 @@ public class Configuration implements BaseConfiguration {
/**
* Assert that the configuration is valid.
*/
@Override
public void assertValid() throws FgaInvalidParameterException {
// If apiUrl is null/empty/whitespace it will resolve to
// DEFAULT_API_URL when getApiUrl is called.
Expand All @@ -63,13 +68,37 @@ public class Configuration implements BaseConfiguration {
}
}

/**
* Construct a new {@link Configuration} with any non-null values of a {@link ConfigurationOverride} and remaining values from this {@link Configuration}.
*
* @param configurationOverride The values to override
* @return A new {@link Configuration} with values of this Configuration mixed with non-null values of configurationOverride
*/
public Configuration override(ConfigurationOverride configurationOverride) {
Configuration result = new Configuration();
String overrideApiUrl = configurationOverride.getApiUrl();
result.apiUrl(overrideApiUrl != null ? overrideApiUrl : apiUrl);
String overrideUserAgent = configurationOverride.getUserAgent();
result.userAgent(overrideUserAgent != null ? overrideUserAgent : userAgent);
Duration overrideReadTimeout = configurationOverride.getReadTimeout();
result.readTimeout(overrideReadTimeout != null ? overrideReadTimeout : readTimeout);
Duration overrideConnectTimeout = configurationOverride.getConnectTimeout();
result.connectTimeout(overrideConnectTimeout != null ? overrideConnectTimeout : connectTimeout);
return result;
}

/**
* Set the API URL for the http client.
*
* @param apiUrl The URL.
* @return This object.
*/
public BaseConfiguration apiUrl(String apiUrl) {
public Configuration apiUrl(String apiUrl) {
this.apiUrl = apiUrl;
return this;
}
Expand All @@ -94,7 +123,7 @@ public class Configuration implements BaseConfiguration {
* @param userAgent The user agent.
* @return This object.
*/
public BaseConfiguration userAgent(String userAgent) {
public Configuration userAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}
Expand All @@ -120,7 +149,7 @@ public class Configuration implements BaseConfiguration {
* effectively infinite value.
* @return This object.
*/
public BaseConfiguration readTimeout(Duration readTimeout) {
public Configuration readTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return this;
}
Expand Down Expand Up @@ -152,7 +181,7 @@ public class Configuration implements BaseConfiguration {
* @param connectTimeout connection timeout in milliseconds
* @return This object.
*/
public BaseConfiguration connectTimeout(Duration connectTimeout) {
public Configuration connectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{{>licenseInfo}}
package {{invokerPackage}};

import java.net.http.HttpClient;
import java.net.http.HttpConnectTimeoutException;
import java.net.http.HttpRequest;
import java.time.Duration;

/**
* Configuration overrides for an api client. Values are initialized to null, and any values unset are intended to fall
* through to the values of a {@link Configuration}.
* <p>
* More details on intended usage of this class can be found in the documentation of the {@link Configuration#override(ConfigurationOverride)} method.
*/
public class ConfigurationOverride implements BaseConfiguration {
private String apiUrl;
private String userAgent;
private Duration readTimeout;
private Duration connectTimeout;
public ConfigurationOverride() {
this.apiUrl = null;
this.userAgent = null;
this.readTimeout = null;
this.connectTimeout = null;
}

/**
* Set the API URL for the http client.
*
* @param apiUrl The URL.
* @return This object.
*/
public ConfigurationOverride apiUrl(String apiUrl) {
this.apiUrl = apiUrl;
return this;
}

/**
* Get the API URL that was set.
*
* @return The url.
*/
@Override
public String getApiUrl() {
return apiUrl;
}

/**
* Set the user agent.
*
* @param userAgent The user agent.
* @return This object.
*/
public ConfigurationOverride userAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}

/**
* Get the user agent.
*
* @return The user agent.
*/
@Override
public String getUserAgent() {
return userAgent;
}

/**
* Set the read timeout for the http client.
*
* <p>This is the value used by default for each request, though it can be
* overridden on a per-request basis with a request interceptor.</p>
*
* @param readTimeout The read timeout used by default by the http client.
* Setting this value to null resets the timeout to an
* effectively infinite value.
* @return This object.
*/
public ConfigurationOverride readTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return this;
}

/**
* Get the read timeout that was set.
*
* @return The read timeout, or null if no timeout was set. Null represents
* an infinite wait time.
*/
@Override
public Duration getReadTimeout() {
return readTimeout;
}

/**
* Sets the connect timeout (in milliseconds) for the http client.
*
* <p> In the case where a new connection needs to be established, if
* the connection cannot be established within the given {@code
* duration}, then {@link HttpClient#send(HttpRequest, BodyHandler)
* HttpClient::send} throws an {@link HttpConnectTimeoutException}, or
* {@link HttpClient#sendAsync(HttpRequest, BodyHandler)
* HttpClient::sendAsync} completes exceptionally with an
* {@code HttpConnectTimeoutException}. If a new connection does not
* need to be established, for example if a connection can be reused
* from a previous request, then this timeout duration has no effect.
*
* @param connectTimeout connection timeout in milliseconds
* @return This object.
*/
public ConfigurationOverride connectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}

/**
* Get connection timeout (in milliseconds).
*
* @return Timeout in milliseconds
*/
@Override
public Duration getConnectTimeout() {
return connectTimeout;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import static org.junit.jupiter.api.Assertions.*;

import dev.openfga.sdk.errors.*;
import org.junit.jupiter.api.Test;
import java.time.Duration;

class ConfigurationTest {
private static final String DEFAULT_API_URL = "http://localhost:8080";
private static final String DEFAULT_USER_AGENT = "{{{userAgent}}}";
private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofSeconds(10);
private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(10);
@Test
void apiUrl_nullDefaults() throws FgaInvalidParameterException {
// Given
Expand Down Expand Up @@ -47,41 +53,132 @@ class ConfigurationTest {

@Test
void apiUrl_stringNoProtocolFails() {
// Given
String apiUrl = "localhost:8080";
// When
FgaInvalidParameterException e = assertThrows(FgaInvalidParameterException.class, () -> {
var config = new Configuration(apiUrl);
config.assertValid();
});

// Then
assertEquals("Required parameter apiUrl was invalid when calling Configuration.", e.getMessage());
}

@Test
void apiUrl_stringInvalidProtocolFails() {
// Given
String apiUrl = "zzz://localhost:8080";
// When
FgaInvalidParameterException e = assertThrows(FgaInvalidParameterException.class, () -> {
var config = new Configuration(apiUrl);
config.assertValid();
});

// Then
assertEquals("Required parameter apiUrl was invalid when calling Configuration.", e.getMessage());
}

@Test
void apiUrl_stringNoHostFails() {
// Given
String apiUrl = "http://";
// When
FgaInvalidParameterException e = assertThrows(FgaInvalidParameterException.class, () -> {
var config = new Configuration(apiUrl);
config.assertValid();
});

// Then
assertEquals("Required parameter apiUrl was invalid when calling Configuration.", e.getMessage());
}

@Test
void apiUrl_stringBadPortFails() {
String apiUrl = "http://localshost:abcd";
// Given
String apiUrl = "http://localhost:abcd";
// When
FgaInvalidParameterException e = assertThrows(FgaInvalidParameterException.class, () -> {
var config = new Configuration(apiUrl);
config.assertValid();
});

// Then
assertEquals("Required parameter apiUrl was invalid when calling Configuration.", e.getMessage());
}

@Test
void defaults() {
// Given
Configuration config = new Configuration();
// NOTE: Failures in this test indicate that default values in Configuration have changed. Changing
// the defaults of Configuration can be a suprising and breaking change for consumers.
// Then
assertEquals(DEFAULT_API_URL, config.getApiUrl());
assertEquals(DEFAULT_USER_AGENT, config.getUserAgent());
assertEquals(DEFAULT_READ_TIMEOUT, config.getReadTimeout());
assertEquals(DEFAULT_CONNECT_TIMEOUT, config.getConnectTimeout());
}

@Test
void override_apiUrl() {
// Given
Configuration original = new Configuration();
ConfigurationOverride configOverride = new ConfigurationOverride().apiUrl("https://override.url");
// When
Configuration result = original.override(configOverride);
// Then
assertEquals("https://override.url", result.getApiUrl());
assertEquals(DEFAULT_API_URL, original.getApiUrl(), "The Configuration's default apiUrl should be unmodified.");
}

@Test
void override_userAgent() {
// Given
Configuration original = new Configuration();
ConfigurationOverride configOverride = new ConfigurationOverride().userAgent("override-agent");
// When
Configuration result = original.override(configOverride);
// Then
assertEquals("override-agent", result.getUserAgent());
assertEquals(DEFAULT_USER_AGENT, original.getUserAgent(), "The Configuration's default userAgent should be unmodified.");
}

@Test
void override_readTimeout() {
// Given
Configuration original = new Configuration();
ConfigurationOverride configOverride = new ConfigurationOverride().readTimeout(Duration.ofDays(7));
// When
Configuration result = original.override(configOverride);
// Then
assertEquals(Duration.ofDays(7), result.getReadTimeout());
assertEquals(DEFAULT_READ_TIMEOUT, original.getReadTimeout(), "The Configuration's default readTimeout should be unmodified.");
}

@Test
void override_connectTimeout() {
// Given
Configuration original = new Configuration();
ConfigurationOverride configOverride = new ConfigurationOverride().connectTimeout(Duration.ofDays(7));
// When
Configuration result = original.override(configOverride);
// Then
assertEquals(Duration.ofDays(7), result.getConnectTimeout());
assertEquals(DEFAULT_CONNECT_TIMEOUT, original.getConnectTimeout(), "The Configuration's default connectTimeout should be unmodified.");
}
}
Loading

0 comments on commit bf4a7c6

Please sign in to comment.