diff --git a/config/clients/java/CHANGELOG.md.mustache b/config/clients/java/CHANGELOG.md.mustache index f17aa1735..ec46f10dd 100644 --- a/config/clients/java/CHANGELOG.md.mustache +++ b/config/clients/java/CHANGELOG.md.mustache @@ -2,6 +2,14 @@ ## [Unreleased](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v{{packageVersion}}...HEAD) +## v0.8.3 + +### [0.8.3](https://github.com/openfga/java-sdk/compare/v0.8.2...v0.8.3) (2025-07-15) + +Fixed: +- client: fix connectTimeout config (#182) +- client: fix batchCheck error handling (#183) + ## v0.8.2 ### [0.8.2](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v0.8.1...v0.8.2) (2025-07-02) diff --git a/config/clients/java/config.overrides.json b/config/clients/java/config.overrides.json index fd85762d0..0c66510c5 100644 --- a/config/clients/java/config.overrides.json +++ b/config/clients/java/config.overrides.json @@ -3,7 +3,7 @@ "gitRepoId": "java-sdk", "artifactId": "openfga-sdk", "groupId": "dev.openfga", - "packageVersion": "0.8.2", + "packageVersion": "0.8.3", "apiPackage": "dev.openfga.sdk.api", "authPackage": "dev.openfga.sdk.api.auth", "clientPackage": "dev.openfga.sdk.api.client", diff --git a/config/clients/java/template/libraries/native/api.mustache b/config/clients/java/template/libraries/native/api.mustache index 07ca1e837..78f0abaa6 100644 --- a/config/clients/java/template/libraries/native/api.mustache +++ b/config/clients/java/template/libraries/native/api.mustache @@ -87,6 +87,11 @@ public class OpenFgaApi { if (defaultHeaders != null) { apiClient.addRequestInterceptor(httpRequest -> defaultHeaders.forEach(httpRequest::setHeader)); } + + Duration connectTimeout = configuration.getConnectTimeout(); + if (connectTimeout != null) { + apiClient.setHttpClientBuilder(apiClient.getHttpClientBuilder().connectTimeout(connectTimeout)); + } } {{#operation}} diff --git a/config/clients/java/template/src/main/api/auth/OAuth2Client.java.mustache b/config/clients/java/template/src/main/api/auth/OAuth2Client.java.mustache index a7ffc670d..2701c5300 100644 --- a/config/clients/java/template/src/main/api/auth/OAuth2Client.java.mustache +++ b/config/clients/java/template/src/main/api/auth/OAuth2Client.java.mustache @@ -40,6 +40,7 @@ public class OAuth2Client { this.authRequest.setScope(clientCredentials.getScopes()); this.config = new Configuration() .apiUrl(buildApiTokenIssuer(clientCredentials.getApiTokenIssuer())) + .connectTimeout(configuration.getConnectTimeout()) .maxRetries(configuration.getMaxRetries()) .minimumRetryDelay(configuration.getMinimumRetryDelay()) .telemetryConfiguration(configuration.getTelemetryConfiguration()); diff --git a/config/clients/java/template/src/main/api/client/OpenFgaClient.java.mustache b/config/clients/java/template/src/main/api/client/OpenFgaClient.java.mustache index 868cdec4e..630a0ed8e 100644 --- a/config/clients/java/template/src/main/api/client/OpenFgaClient.java.mustache +++ b/config/clients/java/template/src/main/api/client/OpenFgaClient.java.mustache @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -699,6 +700,7 @@ public class OpenFgaClient { var latch = new CountDownLatch(batchedChecks.size()); var responses = new ConcurrentLinkedQueue(); + var failure = new AtomicReference(); var override = new ConfigurationOverride().addHeaders(options); @@ -719,26 +721,36 @@ public class OpenFgaClient { return api.batchCheck(configuration.getStoreId(), body, override); }) - .handleAsync((batchCheckResponseApiResponse, throwable) -> { - Map response = - batchCheckResponseApiResponse.getData().getResult(); - - List batchResults = new ArrayList<>(); - response.forEach((key, result) -> { - boolean allowed = Boolean.TRUE.equals(result.getAllowed()); - ClientBatchCheckItem checkItem = correlationIdToCheck.get(key); - var singleResponse = - new ClientBatchCheckSingleResponse(allowed, checkItem, key, result.getError()); - batchResults.add(singleResponse); - }); - return batchResults; - }) - .thenAccept(responses::addAll) - .thenRun(latch::countDown); + .whenComplete((batchCheckResponseApiResponse, throwable) -> { + try { + if (throwable != null) { + failure.compareAndSet(null, throwable); + return; + } + + Map response = + batchCheckResponseApiResponse.getData().getResult(); + + List batchResults = new ArrayList<>(); + response.forEach((key, result) -> { + boolean allowed = Boolean.TRUE.equals(result.getAllowed()); + ClientBatchCheckItem checkItem = correlationIdToCheck.get(key); + var singleResponse = + new ClientBatchCheckSingleResponse(allowed, checkItem, key, result.getError()); + batchResults.add(singleResponse); + }); + responses.addAll(batchResults); + } finally { + latch.countDown(); + } + }); try { batchedChecks.forEach(batch -> executor.execute(() -> singleBatchCheckRequest.accept(batch))); latch.await(); + if (failure.get() != null) { + return CompletableFuture.failedFuture(failure.get()); + } return CompletableFuture.completedFuture(new ClientBatchCheckResponse(new ArrayList<>(responses))); } catch (Exception e) { return CompletableFuture.failedFuture(e); diff --git a/config/clients/java/template/src/test/api/client/OpenFgaClientTest.java.mustache b/config/clients/java/template/src/test/api/client/OpenFgaClientTest.java.mustache index 3a29deb1d..6960e7760 100644 --- a/config/clients/java/template/src/test/api/client/OpenFgaClientTest.java.mustache +++ b/config/clients/java/template/src/test/api/client/OpenFgaClientTest.java.mustache @@ -2057,9 +2057,33 @@ public class OpenFgaClientTest { assertTrue(response.getResult().isEmpty()); } - /** - * Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason - * about and debug a certain relationship. + @Test + public void batchCheck_rateLimited() { + // Given + String postUrl = String.format("https://api.fga.example/stores/%s/batch-check", DEFAULT_STORE_ID); + mockHttpClient.onPost(postUrl).doReturn(429, "{\"code\":\"rate_limited\",\"message\":\"Too Many Requests\"}"); + + ClientBatchCheckItem item = new ClientBatchCheckItem() + .user(DEFAULT_USER) + .relation(DEFAULT_RELATION) + ._object(DEFAULT_OBJECT) + .correlationId("cor-1"); + ClientBatchCheckRequest request = new ClientBatchCheckRequest().checks(List.of(item)); + + // When + ExecutionException execException = assertThrows( + ExecutionException.class, () -> fga.batchCheck(request).get()); + + // Then + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); + var exception = assertInstanceOf(FgaApiRateLimitExceededError.class, execException.getCause()); + assertEquals(429, exception.getStatusCode()); + assertEquals("{\"code\":\"rate_limited\",\"message\":\"Too Many Requests\"}", exception.getResponseData()); + } + + /** + * Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason + * about and debug a certain relationship. */ @Test public void expandTest() throws Exception {