public final class SphereClientTuningDocumentation extends Object
The BlockingSphereClient
can wait for responses with BlockingSphereClient.executeBlocking(SphereRequest)
. This method enforces a timeout for resilience
and throws directly SphereException
s. For creation refer to BlockingSphereClient
.
public class BlockingClientValueGetDemo {
public static void demo(final BlockingSphereClient client, final String expectedProjectKey) {
final SphereRequest<Project> sphereRequest = ProjectGet.of();
final Project project = client.executeBlocking(sphereRequest);//returns result directly, no CompletionStage
assertThat(project.getKey()).isEqualTo(expectedProjectKey);
}
}
See the test code.
Here follow some examples how to NOT use the SphereClient
:
This examples lacks a timeout, so in an unfortunate case the thread is blocked forever:
public class WrongBlockingWithJoin {
public static <T> T demo(final SphereClient client, final SphereRequest<T> sphereRequest) {
//WRONG please don't do this
final CompletionStage<T> completionStage = client.execute(sphereRequest);
return completionStage.toCompletableFuture().join();
}
}
See the test code.
The following examples are even worse because they lack a timeout and they need to deal with checked exceptions:
public class WrongBlockingWithGetAndSwallowing {
public static <T> T demo(final SphereClient client, final SphereRequest<T> sphereRequest) {
//WRONG!!! please don't do this !!!!! it swallows the exceptions
try {
final CompletionStage<T> completionStage = client.execute(sphereRequest);
return completionStage.toCompletableFuture().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
}
See the test code.
public class WrongBlockingWithGetAndSignature {
//NOT a good idea
public static <T> T demo(final SphereClient client, final SphereRequest<T> sphereRequest)
throws ExecutionException, InterruptedException { //UNCOOL and contagious
final CompletionStage<T> completionStage = client.execute(sphereRequest);
return completionStage.toCompletableFuture().get();
}
}
See the test code.
TimeoutSphereClientDecorator
.
RetrySphereClientDecorator
.
QueueSphereClientDecorator
.
The clients are interfaces which have a default implementation (add "Impl" to the interface name).
This enables you to use the decorator pattern to configure the cross concern behaviour of the client:
The following listing shows a pimped client which updates metrics on responses, retries commands and sets default values:
public class WrappedClientDemo implements SphereClient {
private final SphereClient client;
private final MetricComponent metricComponent;
public WrappedClientDemo(final SphereClient client, final MetricComponent metricComponent) {
this.client = client;
this.metricComponent = metricComponent;
}
@SuppressWarnings("unchecked")
@Override
public <T> CompletionStage<T> execute(SphereRequest<T> sphereRequest) {
final CompletionStage<T> result;
final CompletionStage<T> intermediateResult = filtered(client.execute(sphereRequest));
if (sphereRequest instanceof Query) {
final Function<Throwable, T> provideEmptyResultOnException = exception -> (T) PagedQueryResult.empty();
result = intermediateResult.exceptionally(provideEmptyResultOnException);
} else if (sphereRequest instanceof Command) {
final Function<Throwable, T> retry = exception -> (T) client.execute(sphereRequest);
result = intermediateResult.exceptionally(retry);
} else {
result = intermediateResult;
}
return result;
}
//this method will be called for every request
private <T> CompletionStage<T> filtered(final CompletionStage<T> future) {
future.whenComplete(Email::writeEmailToDevelopers);
future.whenComplete(metricComponent::incrementFailureRequests);
future.whenComplete(metricComponent::incrementSuccessfulRequests);
return future;
}
@Override
public void close() {
client.close();
}
@Override
public SphereApiConfig getConfig() {
return client.getConfig();
}
}
See the test code.
HttpClient
is an abstraction to perform http requests.
io.sphere.sdk.http.AsyncHttpClientAdapter#of(AsyncHttpClient)
wraps an AsyncHttpClient
as HttpClient
.
The following example creates a configured HTTP client and initializes a SphereClient
with it.
public class CustomClientConfigDemoIntegrationTest {
/**
* Creates a {@link HttpClient} that can be used by the {@link SphereClient}.
* @return new http client with custom settings
*/
public static HttpClient createCustomHttpClient() {
final AsyncHttpClientConfig httpClientConfig = new DefaultAsyncHttpClientConfig.Builder()
.setEnabledProtocols(new String[]{"TLSv1.2"})//required
//examples for configuration
.setMaxConnections(500)
.setConnectTimeout(10000)
// .setProxyServer(proxy)
.build();
final AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(httpClientConfig);
return AsyncHttpClientAdapter.of(asyncHttpClient);
}
/**
* Shows the initialization of a {@link SphereClient} with a custom {@link HttpClient} provider.
*/
private void demoCreateClient() {
final SphereClient sphereClient = SphereClientFactory.of(CustomClientConfigDemoIntegrationTest::createCustomHttpClient)
.createClient("your projectKey", "your clientId", "your clientSecret");
}
@Test
public void customClient() {
final HttpClient httpClient = createCustomHttpClient();
final CompletionStage<HttpResponse> completionStage =
httpClient.execute(HttpRequest.of(GET, "https://commercetools.com"));
final HttpResponse httpResponse = completionStage.toCompletableFuture().join();
assertThat(httpResponse.getStatusCode()).isLessThanOrEqualTo(302);
httpClient.close();
}
}
See the test code.
For configuration parameters refer to github.com/AsyncHttpClient/async-http-client.