diff --git a/config/clients/java/config.overrides.json b/config/clients/java/config.overrides.json index 90fe69ef..4eb8e6da 100644 --- a/config/clients/java/config.overrides.json +++ b/config/clients/java/config.overrides.json @@ -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" diff --git a/config/clients/java/template/config-BaseConfiguration.java.mustache b/config/clients/java/template/config-BaseConfiguration.java.mustache index e2bd48ac..273abed3 100644 --- a/config/clients/java/template/config-BaseConfiguration.java.mustache +++ b/config/clients/java/template/config-BaseConfiguration.java.mustache @@ -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(); diff --git a/config/clients/java/template/config-Configuration.java.mustache b/config/clients/java/template/config-Configuration.java.mustache index 2f7be777..b9d640cb 100644 --- a/config/clients/java/template/config-Configuration.java.mustache +++ b/config/clients/java/template/config-Configuration.java.mustache @@ -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}}"; @@ -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; @@ -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. @@ -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; } @@ -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; } @@ -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; } @@ -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; } diff --git a/config/clients/java/template/config-ConfigurationOverride.java.mustache b/config/clients/java/template/config-ConfigurationOverride.java.mustache new file mode 100644 index 00000000..60f568a3 --- /dev/null +++ b/config/clients/java/template/config-ConfigurationOverride.java.mustache @@ -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}. + *
+ * 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. + * + *
This is the value used by default for each request, though it can be + * overridden on a per-request basis with a request interceptor.
+ * + * @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. + * + * 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;
+ }
+}
diff --git a/config/clients/java/template/config-ConfigurationTest.java.mustache b/config/clients/java/template/config-ConfigurationTest.java.mustache
index 77b75b45..efd7f036 100644
--- a/config/clients/java/template/config-ConfigurationTest.java.mustache
+++ b/config/clients/java/template/config-ConfigurationTest.java.mustache
@@ -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
@@ -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.");
+ }
}
diff --git a/config/clients/java/template/libraries/native/api.mustache b/config/clients/java/template/libraries/native/api.mustache
index 7c64fef9..5d343ec6 100644
--- a/config/clients/java/template/libraries/native/api.mustache
+++ b/config/clients/java/template/libraries/native/api.mustache
@@ -5,7 +5,9 @@ import {{invokerPackage}}.ApiClient;
import {{invokerPackage}}.ApiException;
import {{invokerPackage}}.ApiResponse;
import {{invokerPackage}}.Configuration;
+import {{invokerPackage}}.ConfigurationOverride;
import {{invokerPackage}}.Pair;
+import dev.openfga.sdk.errors.FgaInvalidParameterException;
{{#imports}}
import {{import}};
@@ -53,9 +55,7 @@ import java.util.concurrent.CompletableFuture;
public class {{classname}} {
private final HttpClient memberVarHttpClient;
private final ObjectMapper memberVarObjectMapper;
- private final Configuration memberVarConfiguration;
- private final String memberVarBaseUri;
- private final Duration memberVarReadTimeout;
+ private final Configuration configuration;
private final Consumer