Skip to content

Commit

Permalink
add java 11 request handler module (#18)
Browse files Browse the repository at this point in the history
* java11 module

* fix Java11RequestHandler

* add junit tests for java11 request handler

* add request logs

* fix upload content type

* add missing form data

* formatting

---------

Co-authored-by: aabssmc <aabssmc@users.noreply.github.com>
Co-authored-by: Haylee Schäfer <haylee@inventivetalent.org>
  • Loading branch information
3 people authored Sep 20, 2024
1 parent cd5a50a commit b53ea29
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 12 deletions.
23 changes: 23 additions & 0 deletions java11/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mineskin</groupId>
<artifactId>client-parent</artifactId>
<version>PARENT</version>
</parent>

<artifactId>java-client-java11</artifactId>
<version>${revision}</version>

<dependencies>
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>

</project>
168 changes: 168 additions & 0 deletions java11/src/main/java/org/mineskin/Java11RequestHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package org.mineskin;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.mineskin.exception.MineSkinRequestException;
import org.mineskin.exception.MineskinException;
import org.mineskin.request.RequestHandler;
import org.mineskin.response.MineSkinResponse;
import org.mineskin.response.ResponseConstructor;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors;

public class Java11RequestHandler extends RequestHandler {

private final Gson gson;
private final HttpClient httpClient;

public Java11RequestHandler(String userAgent, String apiKey, int timeout, Gson gson) {
super(userAgent, apiKey, timeout, gson);
this.gson = gson;

HttpClient.Builder clientBuilder = HttpClient.newBuilder()
.connectTimeout(java.time.Duration.ofMillis(timeout));

if (userAgent != null) {
clientBuilder.followRedirects(HttpClient.Redirect.NORMAL);
}
this.httpClient = clientBuilder.build();
}

private <T, R extends MineSkinResponse<T>> R wrapResponse(HttpResponse<String> response, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
String rawBody = response.body();
try {
JsonObject jsonBody = gson.fromJson(rawBody, JsonObject.class);
R wrapped = constructor.construct(
response.statusCode(),
lowercaseHeaders(response.headers().map()),
jsonBody,
gson, clazz
);
if (!wrapped.isSuccess()) {
throw new MineSkinRequestException(wrapped.getError().orElse("Request Failed"), wrapped);
}
return wrapped;
} catch (JsonParseException e) {
MineSkinClientImpl.LOGGER.log(Level.WARNING, "Failed to parse response body: " + rawBody, e);
throw new MineskinException("Failed to parse response", e);
}
}

private Map<String, String> lowercaseHeaders(Map<String, java.util.List<String>> headers) {
return headers.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().toLowerCase(),
entry -> String.join(", ", entry.getValue())
));
}

public <T, R extends MineSkinResponse<T>> R getJson(String url, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("GET " + url);

HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.header("User-Agent", this.userAgent);
HttpRequest request;
if (apiKey != null) {
request = requestBuilder
.header("Authorization", "Bearer " + apiKey)
.header("Accept", "application/json").build();
} else {
request = requestBuilder.build();
}
HttpResponse<String> response;
try {
response = this.httpClient.send(request, BodyHandlers.ofString());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return wrapResponse(response, clazz, constructor);
}

public <T, R extends MineSkinResponse<T>> R postJson(String url, JsonObject data, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("POST " + url);

HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(url))
.POST(BodyPublishers.ofString(gson.toJson(data)))
.header("Content-Type", "application/json")
.header("User-Agent", this.userAgent);
HttpRequest request;
if (apiKey != null) {
request = requestBuilder
.header("Authorization", "Bearer " + apiKey)
.header("Accept", "application/json").build();
} else {
request = requestBuilder.build();
}

HttpResponse<String> response;
try {
response = this.httpClient.send(request, BodyHandlers.ofString());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return wrapResponse(response, clazz, constructor);
}

public <T, R extends MineSkinResponse<T>> R postFormDataFile(String url, String key, String filename, InputStream in, Map<String, String> data, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("POST " + url);

String boundary = "mineskin-" + System.currentTimeMillis();
StringBuilder bodyBuilder = new StringBuilder();

// add form fields
for (Map.Entry<String, String> entry : data.entrySet()) {
bodyBuilder.append("--").append(boundary).append("\r\n")
.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"\r\n\r\n")
.append(entry.getValue()).append("\r\n");
}

// add file
byte[] fileContent = in.readAllBytes();
bodyBuilder.append("--").append(boundary).append("\r\n")
.append("Content-Disposition: form-data; name=\"").append(key)
.append("\"; filename=\"").append(filename).append("\"\r\n")
.append("Content-Type: image/png\r\n\r\n");
byte[] bodyStart = bodyBuilder.toString().getBytes();
byte[] boundaryEnd = ("\r\n--" + boundary + "--\r\n").getBytes();
byte[] bodyString = new byte[bodyStart.length + fileContent.length + boundaryEnd.length];
System.arraycopy(bodyStart, 0, bodyString, 0, bodyStart.length);
System.arraycopy(fileContent, 0, bodyString, bodyStart.length, fileContent.length);
System.arraycopy(boundaryEnd, 0, bodyString, bodyStart.length + fileContent.length, boundaryEnd.length);

HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofByteArray(bodyString))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.header("User-Agent", this.userAgent);
HttpRequest request;
if (apiKey != null) {
request = requestBuilder
.header("Authorization", "Bearer " + apiKey)
.header("Accept", "application/json").build();
} else {
request = requestBuilder.build();
}

HttpResponse<String> response;
try {
response = this.httpClient.send(request, BodyHandlers.ofString());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return wrapResponse(response, clazz, constructor);
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<module>core</module>
<module>apache</module>
<module>jsoup</module>
<module>java11</module>
<module>tests</module>
</modules>

Expand Down
6 changes: 6 additions & 0 deletions tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
<artifactId>java-client-apache</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client-java11</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
16 changes: 9 additions & 7 deletions tests/src/test/java/test/GenerateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mineskin.ApacheRequestHandler;
import org.mineskin.GenerateOptions;
import org.mineskin.ImageUtil;
import org.mineskin.JsoupRequestHandler;
import org.mineskin.MineSkinClient;
import org.mineskin.MineSkinClientImpl;
import org.mineskin.*;
import org.mineskin.data.GeneratedSkin;
import org.mineskin.data.Skin;
import org.mineskin.data.Visibility;
Expand Down Expand Up @@ -44,6 +39,12 @@ public class GenerateTest {
.apiKey(System.getenv("MINESKIN_API_KEY"))
.generateExecutor(EXECUTOR)
.build();
private static final MineSkinClient JAVA11 = MineSkinClient.builder()
.requestHandler(Java11RequestHandler::new)
.userAgent("MineSkinClient-Java11/Tests")
.apiKey(System.getenv("MINESKIN_API_KEY"))
.generateExecutor(EXECUTOR)
.build();

static {
MineSkinClientImpl.LOGGER.setLevel(Level.ALL);
Expand All @@ -60,7 +61,8 @@ public void before() throws InterruptedException {
private static Stream<Arguments> clients() {
return Stream.of(
Arguments.of(APACHE),
Arguments.of(JSOUP)
Arguments.of(JSOUP),
Arguments.of(JAVA11)
);
}

Expand Down
13 changes: 8 additions & 5 deletions tests/src/test/java/test/GetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mineskin.ApacheRequestHandler;
import org.mineskin.JsoupRequestHandler;
import org.mineskin.MineSkinClient;
import org.mineskin.MineSkinClientImpl;
import org.mineskin.*;
import org.mineskin.data.ExistingSkin;
import org.mineskin.exception.MineSkinRequestException;
import org.mineskin.response.GetSkinResponse;
Expand All @@ -30,6 +27,11 @@ public class GetTest {
.userAgent("MineSkinClient-Jsoup/Tests")
.apiKey(System.getenv("MINESKIN_API_KEY"))
.build();
private static final MineSkinClient JAVA11 = MineSkinClient.builder()
.requestHandler(Java11RequestHandler::new)
.userAgent("MineSkinClient-Java11/Tests")
.apiKey(System.getenv("MINESKIN_API_KEY"))
.build();
static {
MineSkinClientImpl.LOGGER.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
Expand All @@ -40,7 +42,8 @@ public class GetTest {
private static Stream<Arguments> clients() {
return Stream.of(
Arguments.of(APACHE),
Arguments.of(JSOUP)
Arguments.of(JSOUP),
Arguments.of(JAVA11)
);
}

Expand Down

0 comments on commit b53ea29

Please sign in to comment.