DomainTemplateClient.java
package fr.tiogars.template.client;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
/**
* Provides HTTP access to the DomainTemplate API.
*
* @since 0.1.0
*/
public class DomainTemplateClient {
private static final String API_PATH = "/api/v1/domaintemplate";
private static final String APPLICATION_JSON = "application/json";
private static final String TEXT_CSV = "text/csv";
private static final TypeReference<List<DomainTemplate>> TEMPLATE_LIST = new TypeReference<>() {
};
private final URI baseUri;
private final HttpClient httpClient;
private final ObjectMapper objectMapper;
/**
* Creates a client backed by the default Java HTTP client.
*
* @param baseUri base URI of the server
*/
public DomainTemplateClient(URI baseUri) {
this(baseUri, HttpClient.newHttpClient(), new ObjectMapper().registerModule(new JavaTimeModule()));
}
DomainTemplateClient(URI baseUri, HttpClient httpClient, ObjectMapper objectMapper) {
this.baseUri = baseUri;
this.httpClient = httpClient;
this.objectMapper = objectMapper;
}
/**
* Creates a DomainTemplate.
*
* @param request template data to create
* @return template created by the server
* @throws IOException if request serialization or response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public DomainTemplate create(CreateDomainTemplateRequest request) throws IOException, InterruptedException {
return sendJson(jsonRequest(uri(""), "POST", request), DomainTemplate.class, 201);
}
/**
* Lists all DomainTemplates.
*
* @return templates returned by the server
* @throws IOException if response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public List<DomainTemplate> findAll() throws IOException, InterruptedException {
return sendJson(getRequest(uri(""), APPLICATION_JSON), TEMPLATE_LIST, 200);
}
/**
* Finds a DomainTemplate by identifier.
*
* @param id persistent template identifier
* @return matching template
* @throws IOException if response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public DomainTemplate findById(long id) throws IOException, InterruptedException {
return sendJson(getRequest(uri("/" + id), APPLICATION_JSON), DomainTemplate.class, 200);
}
/**
* Updates a DomainTemplate.
*
* @param id persistent template identifier
* @param request replacement label and description
* @return template updated by the server
* @throws IOException if request serialization or response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public DomainTemplate update(long id, UpdateDomainTemplateRequest request) throws IOException, InterruptedException {
return sendJson(jsonRequest(uri("/" + id), "PUT", request), DomainTemplate.class, 200);
}
/**
* Deletes a DomainTemplate.
*
* @param id persistent template identifier
* @throws IOException if the request fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public void delete(long id) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder(uri("/" + id)).DELETE().build();
send(request, 204);
}
/**
* Seeds DomainTemplates from structured requests.
*
* @param requests templates to seed
* @return templates stored by the server
* @throws IOException if request serialization or response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public List<DomainTemplate> seed(List<CreateDomainTemplateRequest> requests) throws IOException, InterruptedException {
return sendJson(jsonRequest(uri("/seed"), "POST", requests), TEMPLATE_LIST, 201);
}
/**
* Imports DomainTemplates from JSON-compatible requests.
*
* @param requests templates to import
* @return templates imported by the server
* @throws IOException if request serialization or response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public List<DomainTemplate> importJson(List<CreateDomainTemplateRequest> requests)
throws IOException, InterruptedException {
return sendJson(jsonRequest(uri("/import.json"), "POST", requests), TEMPLATE_LIST, 201);
}
/**
* Imports DomainTemplates from a CSV document.
*
* @param csv CSV document to import
* @return templates imported by the server
* @throws IOException if the request or response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public List<DomainTemplate> importCsv(String csv) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder(uri("/import.csv"))
.header("Content-Type", TEXT_CSV)
.header("Accept", APPLICATION_JSON)
.POST(HttpRequest.BodyPublishers.ofString(csv))
.build();
return sendJson(request, TEMPLATE_LIST, 201);
}
/**
* Exports all DomainTemplates as JSON-compatible objects.
*
* @return templates exported by the server
* @throws IOException if response deserialization fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public List<DomainTemplate> exportJson() throws IOException, InterruptedException {
return sendJson(getRequest(uri("/export.json"), APPLICATION_JSON), TEMPLATE_LIST, 200);
}
/**
* Exports all DomainTemplates as CSV.
*
* @return CSV document returned by the server
* @throws IOException if the request fails
* @throws InterruptedException if the thread is interrupted while awaiting the response
* @throws DomainTemplateException if the server returns an unexpected HTTP status
*/
public String exportCsv() throws IOException, InterruptedException {
return send(getRequest(uri("/export.csv"), TEXT_CSV), 200).body();
}
private HttpRequest jsonRequest(URI uri, String method, Object body) throws IOException {
return HttpRequest.newBuilder(uri)
.header("Content-Type", APPLICATION_JSON)
.header("Accept", APPLICATION_JSON)
.method(method, HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(body)))
.build();
}
private HttpRequest getRequest(URI uri, String accept) {
return HttpRequest.newBuilder(uri).header("Accept", accept).GET().build();
}
private <T> T sendJson(HttpRequest request, Class<T> responseType, int expectedStatus)
throws IOException, InterruptedException {
return objectMapper.readValue(send(request, expectedStatus).body(), responseType);
}
private <T> T sendJson(HttpRequest request, TypeReference<T> responseType, int expectedStatus)
throws IOException, InterruptedException {
return objectMapper.readValue(send(request, expectedStatus).body(), responseType);
}
private HttpResponse<String> send(HttpRequest request, int expectedStatus) throws IOException, InterruptedException {
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != expectedStatus) {
throw new DomainTemplateException(
"Expected HTTP " + expectedStatus + " but received " + response.statusCode());
}
return response;
}
private URI uri(String suffix) {
return baseUri.resolve(API_PATH + suffix);
}
}