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
2 changes: 1 addition & 1 deletion .codegen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "engineHash": "482939a", "specHash": "77eac4b", "version": "5.4.0" }
{ "engineHash": "bc04b80", "specHash": "77eac4b", "version": "5.4.0" }
13 changes: 13 additions & 0 deletions docs/sdkgen/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ divided across resource managers.
- [Custom headers](#custom-headers)
- [Custom Base URLs](#custom-base-urls)
- [Interceptors](#interceptors)
- [Use Timeouts for API calls](#use-timeouts-for-api-calls)
- [Use Proxy for API calls](#use-proxy-for-api-calls)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Expand Down Expand Up @@ -178,6 +179,18 @@ List<Interceptor> interceptors = new ArrayList<>() {
BoxClient clientWithInterceptor = client.withInterceptors(interceptors);
```

# Use Timeouts for API calls

In order to configure timeout for API calls, calling the `client.withTimeouts(config)` method creates a new client with timeout settings, leaving the original client unmodified.

```java
TimeoutConfig timeoutConfig = new TimeoutConfig.Builder()
.connectionTimeoutMs(10000L)
.readTimeoutMs(30000L)
.build();
BoxClient newClient = client.withTimeouts(timeoutConfig);
```

# Use Proxy for API calls

In order to use a proxy for API calls, calling the `client.withProxy(proxyConfig)` method creates a new client, leaving the original client unmodified, with the username and password being optional. We only support adding proxy for BoxNetworkClient. If you are using your own implementation of NetworkClient, you would need to configure proxy on your own.
Expand Down
32 changes: 32 additions & 0 deletions docs/sdkgen/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [Network Exception Handling](#network-exception-handling)
- [Customizing Retry Parameters](#customizing-retry-parameters)
- [Custom Retry Strategy](#custom-retry-strategy)
- [Timeouts](#timeouts)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -173,3 +174,34 @@ BoxClient client = new BoxClient.Builder(auth)
.networkSession(session)
.build();
```

## Timeouts

You can configure network timeouts with `TimeoutConfig` on `NetworkSession`.
Java SDK supports separate values for connection and read timeouts, both in milliseconds.

```java
BoxDeveloperTokenAuth auth = new BoxDeveloperTokenAuth("DEVELOPER_TOKEN");
TimeoutConfig timeoutConfig = new TimeoutConfig.Builder()
.connectionTimeoutMs(10000L)
.readTimeoutMs(30000L)
.build();

NetworkSession session = new NetworkSession()
.withTimeoutConfig(timeoutConfig);

BoxClient client = new BoxClient.Builder(auth)
.networkSession(session)
.build();
```

How timeout handling works:

- `connectionTimeoutMs` controls how long the client waits to establish a connection.
- `readTimeoutMs` controls how long the client waits for data while reading the response.
- Each timeout is optional. If a value is not provided, the client keeps its existing timeout for that setting.
- To disable both timeouts, set `connectionTimeoutMs(0L)` and `readTimeoutMs(0L)`.
- You can also disable only one timeout by setting just one of them to `0L` and leaving the other configured.
- Timeout failures are handled as request exceptions, then retry behavior is controlled by the configured retry strategy
- If retries are exhausted after timeout failures, the SDK throws `BoxSDKError` with the underlying timeout exception as the cause.
- Timeout applies to a single HTTP request attempt to the Box API (not the total time across all retries).
17 changes: 17 additions & 0 deletions src/intTest/java/com/box/sdkgen/client/ClientITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.box.sdkgen.networking.fetchoptions.MultipartItem;
import com.box.sdkgen.networking.fetchoptions.ResponseFormat;
import com.box.sdkgen.networking.fetchresponse.FetchResponse;
import com.box.sdkgen.networking.timeoutconfig.TimeoutConfig;
import com.box.sdkgen.schemas.filefull.FileFull;
import com.box.sdkgen.schemas.files.Files;
import com.box.sdkgen.schemas.folderfull.FolderFull;
Expand Down Expand Up @@ -199,6 +200,22 @@ public void testWithCustomBaseUrls() {
assertThrows(RuntimeException.class, () -> customBaseClient.getUsers().getUserMe());
}

@Test
public void testWithTimeoutWhenTimeoutOccurs() {
long readTimeoutMs = 1;
BoxClient clientWithTimeout =
client.withTimeouts(new TimeoutConfig.Builder().readTimeoutMs(readTimeoutMs).build());
assertThrows(RuntimeException.class, () -> clientWithTimeout.getUsers().getUserMe());
}

@Test
public void testWithTimeoutWhenTimeoutDoesNotOccur() {
long readTimeoutMs = 10000;
BoxClient clientWithTimeout =
client.withTimeouts(new TimeoutConfig.Builder().readTimeoutMs(readTimeoutMs).build());
clientWithTimeout.getUsers().getUserMe();
}

@Test
public void testWithInterceptors() {
UserFull user = client.getUsers().getUserMe();
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/box/sdkgen/client/BoxClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import com.box.sdkgen.networking.interceptors.Interceptor;
import com.box.sdkgen.networking.network.NetworkSession;
import com.box.sdkgen.networking.proxyconfig.ProxyConfig;
import com.box.sdkgen.networking.timeoutconfig.TimeoutConfig;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -1046,6 +1047,17 @@ public BoxClient withProxy(ProxyConfig config) {
.build();
}

/**
* Create a new client with custom timeouts that will be used for every API call
*
* @param config Timeout configuration.
*/
public BoxClient withTimeouts(TimeoutConfig config) {
return new BoxClient.Builder(this.auth)
.networkSession(this.networkSession.withTimeoutConfig(config))
.build();
}

/**
* Create a new client with a custom set of interceptors that will be used for every API call
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.box.sdkgen.networking.network.NetworkSession;
import com.box.sdkgen.networking.networkclient.NetworkClient;
import com.box.sdkgen.networking.proxyconfig.ProxyConfig;
import com.box.sdkgen.networking.timeoutconfig.TimeoutConfig;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.net.InetSocketAddress;
Expand Down Expand Up @@ -97,6 +98,31 @@ public BoxNetworkClient withProxy(ProxyConfig config) {
return new BoxNetworkClient(clientBuilder.build());
}

public BoxNetworkClient withTimeoutConfig(TimeoutConfig config) {
if (config == null) {
throw new IllegalArgumentException("TimeoutConfig cannot be null");
}

OkHttpClient.Builder clientBuilder = httpClient.newBuilder();

Long connectionTimeoutMs = config.getConnectionTimeoutMs();
if (connectionTimeoutMs != null) {
if (connectionTimeoutMs < 0) {
throw new IllegalArgumentException("connectionTimeoutMs cannot be negative");
}
clientBuilder.connectTimeout(connectionTimeoutMs.longValue(), TimeUnit.MILLISECONDS);
}

Long readTimeoutMs = config.getReadTimeoutMs();
if (readTimeoutMs != null) {
if (readTimeoutMs < 0) {
throw new IllegalArgumentException("readTimeoutMs cannot be negative");
}
clientBuilder.readTimeout(readTimeoutMs.longValue(), TimeUnit.MILLISECONDS);
}
return new BoxNetworkClient(clientBuilder.build());
}

public FetchResponse fetch(FetchOptions options) {
NetworkSession networkSession =
options.getNetworkSession() == null ? new NetworkSession() : options.getNetworkSession();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.box.sdkgen.networking.proxyconfig.ProxyConfig;
import com.box.sdkgen.networking.retries.BoxRetryStrategy;
import com.box.sdkgen.networking.retries.RetryStrategy;
import com.box.sdkgen.networking.timeoutconfig.TimeoutConfig;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -31,6 +32,8 @@ public class NetworkSession {

protected ProxyConfig proxyConfig;

protected TimeoutConfig timeoutConfig;

public NetworkSession() {
networkClient = new BoxNetworkClient();
retryStrategy = new BoxRetryStrategy();
Expand All @@ -45,6 +48,7 @@ protected NetworkSession(Builder builder) {
this.retryStrategy = builder.retryStrategy;
this.dataSanitizer = builder.dataSanitizer;
this.proxyConfig = builder.proxyConfig;
this.timeoutConfig = builder.timeoutConfig;
}

public NetworkSession withAdditionalHeaders() {
Expand All @@ -63,6 +67,7 @@ public NetworkSession withAdditionalHeaders(Map<String, String> additionalHeader
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -75,6 +80,7 @@ public NetworkSession withCustomBaseUrls(BaseUrls baseUrls) {
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -90,6 +96,7 @@ public NetworkSession withInterceptors(List<Interceptor> interceptors) {
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -102,6 +109,7 @@ public NetworkSession withNetworkClient(NetworkClient networkClient) {
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -114,6 +122,7 @@ public NetworkSession withRetryStrategy(RetryStrategy retryStrategy) {
.retryStrategy(retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -126,6 +135,7 @@ public NetworkSession withDataSanitizer(DataSanitizer dataSanitizer) {
.retryStrategy(this.retryStrategy)
.dataSanitizer(dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(this.timeoutConfig)
.build();
}

Expand All @@ -145,6 +155,30 @@ public NetworkSession withProxy(ProxyConfig config) {
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(config)
.timeoutConfig(this.timeoutConfig)
.build();
}

public NetworkSession withTimeoutConfig(TimeoutConfig timeoutConfig) {
if (timeoutConfig == null) {
throw new IllegalArgumentException("TimeoutConfig cannot be null");
}

if (!(this.networkClient instanceof BoxNetworkClient)) {
throw new BoxSDKError("Timeouts are only supported for BoxNetworkClient");
}

BoxNetworkClient newClient =
((BoxNetworkClient) this.networkClient).withTimeoutConfig(timeoutConfig);
return new Builder()
.additionalHeaders(this.additionalHeaders)
.baseUrls(this.baseUrls)
.interceptors(this.interceptors)
.networkClient(newClient)
.retryStrategy(this.retryStrategy)
.dataSanitizer(this.dataSanitizer)
.proxyConfig(this.proxyConfig)
.timeoutConfig(timeoutConfig)
.build();
}

Expand Down Expand Up @@ -176,6 +210,10 @@ public ProxyConfig getProxyConfig() {
return proxyConfig;
}

public TimeoutConfig getTimeoutConfig() {
return timeoutConfig;
}

public static class Builder {

protected Map<String, String> additionalHeaders = new HashMap<>();
Expand All @@ -192,6 +230,8 @@ public static class Builder {

protected ProxyConfig proxyConfig;

protected TimeoutConfig timeoutConfig;

public Builder() {
networkClient = new BoxNetworkClient();
retryStrategy = new BoxRetryStrategy();
Expand Down Expand Up @@ -233,6 +273,11 @@ public Builder proxyConfig(ProxyConfig proxyConfig) {
return this;
}

public Builder timeoutConfig(TimeoutConfig timeoutConfig) {
this.timeoutConfig = timeoutConfig;
return this;
}

public NetworkSession build() {
return new NetworkSession(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.box.sdkgen.networking.timeoutconfig;

public class TimeoutConfig {

public Long connectionTimeoutMs;

public Long readTimeoutMs;

public TimeoutConfig() {}

protected TimeoutConfig(Builder builder) {
this.connectionTimeoutMs = builder.connectionTimeoutMs;
this.readTimeoutMs = builder.readTimeoutMs;
}

public Long getConnectionTimeoutMs() {
return connectionTimeoutMs;
}

public Long getReadTimeoutMs() {
return readTimeoutMs;
}

public static class Builder {

protected Long connectionTimeoutMs;

protected Long readTimeoutMs;

public Builder connectionTimeoutMs(Long connectionTimeoutMs) {
this.connectionTimeoutMs = connectionTimeoutMs;
return this;
}

public Builder readTimeoutMs(Long readTimeoutMs) {
this.readTimeoutMs = readTimeoutMs;
return this;
}

public TimeoutConfig build() {
return new TimeoutConfig(this);
}
}
}
Loading