Skip to content

Commit

Permalink
Add Vert.x client.
Browse files Browse the repository at this point in the history
  • Loading branch information
Chavjoh committed Nov 25, 2023
1 parent 1601488 commit f793d91
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 0 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Expand Up @@ -107,6 +107,14 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>4.5.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
125 changes: 125 additions & 0 deletions src/main/java/com/chavaillaz/client/vertx/AbstractVertxHttpClient.java
@@ -0,0 +1,125 @@
package com.chavaillaz.client.vertx;

import java.io.InputStream;
import java.util.concurrent.CompletableFuture;

import com.chavaillaz.client.AbstractHttpClient;
import com.chavaillaz.client.Authentication;
import com.fasterxml.jackson.databind.JavaType;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import lombok.extern.slf4j.Slf4j;

/**
* Abstract class implementing common parts for Vert.x HTTP.
*
* @param <A> The authentication type
*/
@Slf4j
public class AbstractVertxHttpClient<A extends Authentication> extends AbstractHttpClient<A> implements AutoCloseable {

protected WebClient client;

/**
* Creates a new abstract client based on Vert.x HTTP client.
*
* @param vertx The Vert.x instance to create the web client
* @param options The web client options
* @param baseUrl The base URL of endpoints
* @param authentication The authentication information
*/
protected AbstractVertxHttpClient(Vertx vertx, WebClientOptions options, String baseUrl, A authentication) {
super(baseUrl, authentication);
this.client = WebClient.create(vertx, options);
}

/**
* Creates a new abstract client based on Vert.x HTTP client.
*
* @param httpClient The HTTP client to wrap in the Vert.x web client
* @param baseUrl The base URL of endpoints
* @param authentication The authentication information
*/
protected AbstractVertxHttpClient(HttpClient httpClient, String baseUrl, A authentication) {
super(baseUrl, authentication);
this.client = WebClient.wrap(httpClient);
}

/**
* Creates a request based on the given URL and replaces the parameters in it by the given ones.
*
* @param method The HTTP method for the HTTP request to build
* @param url The URL with possible parameters in it (using braces)
* @param parameters The parameters value to replace in the URL (in the right order)
* @return The request having the URL and authorization header set
*/
protected HttpRequest<Buffer> requestBuilder(HttpMethod method, String url, Object... parameters) {
return client.request(method, url(url, parameters).toString())
.putHeader(HEADER_AUTHORIZATION, getAuthentication().getAuthorizationHeader())
.putHeader(HEADER_CONTENT_TYPE, HEADER_CONTENT_JSON);
}

/**
* Sends a request and returns a domain object.
*
* @param request The request
* @param returnType The domain object type class
* @param <T> The domain object type
* @return A {@link CompletableFuture} with the deserialized domain object
*/
protected <T> CompletableFuture<T> sendAsync(HttpRequest<Buffer> request, Class<T> returnType) {
return sendAsync(request, objectMapper.constructType(returnType));
}

/**
* Sends a request and returns a domain object.
*
* @param request The request
* @param returnType The domain object type class
* @param <T> The domain object type
* @return A {@link CompletableFuture} with the deserialized domain object
*/
protected <T> CompletableFuture<T> sendAsync(HttpRequest<Buffer> request, JavaType returnType) {
CompletableFuture<HttpResponse<Buffer>> completableFuture = new CompletableFuture<>();
request.send()
.onSuccess(response -> handleResponse(response, completableFuture))
.onFailure(completableFuture::completeExceptionally);
return completableFuture.thenApply(HttpResponse::bodyAsString)
.thenApply(body -> deserialize(body, returnType));
}

/**
* Sends a request and returns an input stream.
*
* @param request The request
* @return A {@link CompletableFuture} with the input stream
*/
protected CompletableFuture<InputStream> sendAsync(HttpRequest<Buffer> request) {
CompletableFuture<HttpResponse<Buffer>> completableFuture = new CompletableFuture<>();
request.send()
.onSuccess(response -> handleResponse(response, completableFuture))
.onFailure(completableFuture::completeExceptionally);
return completableFuture.thenApply(HttpResponse::body)
.thenApply(VertxInputStream::new);
}

protected void handleResponse(HttpResponse<Buffer> response, CompletableFuture<HttpResponse<Buffer>> completableFuture) {
if (response.statusCode() >= 400) {
completableFuture.completeExceptionally(responseException(response.statusCode(), response.bodyAsString()));
} else {
completableFuture.complete(response);
}
}

@Override
public void close() throws Exception {
client.close();
}

}
34 changes: 34 additions & 0 deletions src/main/java/com/chavaillaz/client/vertx/VertxInputStream.java
@@ -0,0 +1,34 @@
package com.chavaillaz.client.vertx;

import java.io.IOException;
import java.io.InputStream;

import io.vertx.core.buffer.Buffer;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class VertxInputStream extends InputStream {

private final Buffer buffer;
private int position = 0;

@Override
public int read() throws IOException {
if (position == buffer.length()) {
return -1;
}
return buffer.getByte(position++) & 0xFF;
}

@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
int size = Math.min(buffer.length, this.buffer.length() - position);
if (size == 0) {
return -1;
}
this.buffer.getBytes(position, position + size, buffer, offset);
position += size;
return size;
}

}
33 changes: 33 additions & 0 deletions src/main/java/com/chavaillaz/client/vertx/VertxUtils.java
@@ -0,0 +1,33 @@
package com.chavaillaz.client.vertx;

import java.util.Optional;

import com.chavaillaz.client.utility.ProxyConfiguration;
import io.vertx.core.net.ProxyOptions;
import io.vertx.ext.web.client.WebClientOptions;
import lombok.experimental.UtilityClass;

/**
* Utilities for Vert.x Client.
*/
@UtilityClass
public class VertxUtils {

/**
* Creates new options for Vert.x web client with default configuration (30 seconds timeout).
*
* @param proxy The proxy configuration
* @return The corresponding options
*/
public static WebClientOptions newWebClientOptions(ProxyConfiguration proxy) {
return new WebClientOptions()
.setProxyOptions(Optional.ofNullable(proxy)
.map(config -> new ProxyOptions()
.setHost(config.getHost())
.setPort(config.getPort()))
.orElse(null))
.setConnectTimeout(30_000)
.setIdleTimeout(30_000);
}

}

0 comments on commit f793d91

Please sign in to comment.