Skip to content

Google http client apache v3 async #2109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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
115 changes: 115 additions & 0 deletions google-http-client-apache-v3/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<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>com.google.http-client</groupId>
<artifactId>google-http-client-parent</artifactId>
<version>1.44.3-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>google-http-client-apache-v3</artifactId>
<version>1.44.3-SNAPSHOT</version><!-- {x-version-update:google-http-client-apache-v3:current} -->
<name>Apache HTTP transport v3 for the Google HTTP Client Library for Java.</name>

<build>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<links>
<link>https://download.oracle.com/javase/7/docs/api/</link>
</links>
<doctitle>${project.name} ${project.version}</doctitle>
<windowtitle>${project.artifactId} ${project.version}</windowtitle>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-test-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
<manifestEntries>
<Automatic-Module-Name>com.google.api.client.http.apache.v3</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>5.1.9</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>9.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-h2</artifactId>
<version>5.2.4</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.google.api.client.http.apache.v3;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.util.Timeout;

import com.google.api.client.http.LowLevelHttpRequest;
import com.google.api.client.http.LowLevelHttpResponse;

@SuppressWarnings("deprecation")
final class ApacheHttp2Request extends LowLevelHttpRequest {
private final CloseableHttpAsyncClient httpAsyncClient;
private final SimpleRequestBuilder requestBuilder;
private SimpleHttpRequest request;
private final RequestConfig.Builder requestConfig;

ApacheHttp2Request(CloseableHttpAsyncClient httpAsyncClient, SimpleRequestBuilder requestBuilder) {
this.httpAsyncClient = httpAsyncClient;
this.requestBuilder = requestBuilder;

this.requestConfig = RequestConfig.custom()
.setRedirectsEnabled(false);
}

@Override
public void addHeader(String name, String value) {
requestBuilder.addHeader(name, value);
}

@Override
public void setTimeout(int connectionTimeout, int readTimeout) throws IOException {
requestConfig
.setConnectTimeout(Timeout.ofMilliseconds(connectionTimeout))
.setResponseTimeout(Timeout.ofMilliseconds(readTimeout));
// .setConnectionRequestTimeout(connectionTimeout)
// .setResponseTimeout();
}

@Override
public LowLevelHttpResponse execute() throws IOException {
// Convert StreamingContent to bytes to set request body
ByteArrayOutputStream baos = new ByteArrayOutputStream();
getStreamingContent().writeTo(baos);
byte[] bytes = baos.toByteArray();
requestBuilder.setBody(bytes, ContentType.parse(getContentType()));

// Set request configs
requestBuilder.setRequestConfig(requestConfig.build());

// Build and execute request
request = requestBuilder.build();
final CompletableFuture<SimpleHttpResponse> responseFuture = new CompletableFuture<>();
try {
httpAsyncClient.execute(
SimpleRequestProducer.create(request),
SimpleResponseConsumer.create(),
new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(final SimpleHttpResponse response) {
responseFuture.complete(response);
}

@Override
public void failed(final Exception exception) {
responseFuture.completeExceptionally(exception);
}

@Override
public void cancelled() {
responseFuture.cancel(false);
}
});
final SimpleHttpResponse response = responseFuture.get();
return new ApacheHttp2Response(request, response);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
throw new IOException("Error making request", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.google.api.client.http.apache.v3;

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

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.core5.http.Header;

import com.google.api.client.http.LowLevelHttpResponse;

public class ApacheHttp2Response extends LowLevelHttpResponse {

private final SimpleHttpResponse response;
private final Header[] allHeaders;

ApacheHttp2Response(SimpleHttpRequest request, SimpleHttpResponse response) {
this.response = response;
allHeaders = response.getHeaders();
}

@Override
public int getStatusCode() {
return response.getCode();
}

@Override
public InputStream getContent() throws IOException {
return new ByteArrayInputStream(response.getBodyBytes());
}

@Override
public String getContentEncoding() {
return response.getFirstHeader("Content-Encoding").getValue();
}

@Override
public long getContentLength() {
return response.getBodyText().length();
}

@Override
public String getContentType() {
return response.getContentType().toString();
}

@Override
public String getReasonPhrase() {
return response.getReasonPhrase();
}

@Override
public String getStatusLine() {
return response.toString();
}

public String getHeaderValue(String name) {
return response.getLastHeader(name).getValue();
}

@Override
public int getHeaderCount() {
return allHeaders.length;
}

@Override
public String getHeaderName(int index) {
return allHeaders[index].getName();
}

@Override
public String getHeaderValue(int index) {
return allHeaders[index].getValue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.google.api.client.http.apache.v3;

import java.io.IOException;
import java.net.ProxySelector;
import java.util.concurrent.TimeUnit;

import org.apache.hc.client5.http.async.HttpAsyncClient;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.TlsConfig;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
import org.apache.hc.core5.http.config.Http1Config;
import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.http2.config.H2Config;
import org.apache.hc.core5.reactor.IOReactorConfig;

import com.google.api.client.http.HttpTransport;

public final class ApacheHttp2Transport extends HttpTransport{

public final CloseableHttpAsyncClient httpAsyncClient;

public ApacheHttp2Transport() {
this(newDefaultHttpAsyncClient(false));
}

public ApacheHttp2Transport(Boolean useCustom) {
this(newDefaultHttpAsyncClient(useCustom));
}

public ApacheHttp2Transport(CloseableHttpAsyncClient httpAsyncClient) {
this.httpAsyncClient = httpAsyncClient;
httpAsyncClient.start();
}

public static CloseableHttpAsyncClient newDefaultHttpAsyncClient(Boolean useCustom) {
if (useCustom) {
return defaultHttpAsyncClientBuilder().build();
}
return HttpAsyncClients.createHttp2System();
}

public static HttpAsyncClientBuilder defaultHttpAsyncClientBuilder() {
return HttpAsyncClientBuilder.create()
.setH2Config(H2Config.DEFAULT)
.setHttp1Config(Http1Config.DEFAULT)
.setIOReactorConfig(IOReactorConfig.DEFAULT)
.setConnectionManager(defaultAsyncClientConnectionManager())
.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault()))
.disableRedirectHandling()
.disableAutomaticRetries();
}

public static AsyncClientConnectionManager defaultAsyncClientConnectionManager() {
return defaultPoolingAsyncClientConnectionManagerBuilder()
.build();
}

public static PoolingAsyncClientConnectionManagerBuilder defaultPoolingAsyncClientConnectionManagerBuilder() {
return PoolingAsyncClientConnectionManagerBuilder
.create()
.useSystemProperties()
// .setConnectionConfigResolver(null)
.setDefaultConnectionConfig(defaultConnectionConfig())
// .setTlsConfigResolver(null)
.setDefaultTlsConfig(defaultTlsConfig())
.setTlsStrategy(null)
.setMaxConnTotal(200)
.setMaxConnPerRoute(20);
}

public static TlsConfig defaultTlsConfig() {
return TlsConfig.custom().setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2).build();
}

public static ConnectionConfig defaultConnectionConfig() {
return ConnectionConfig.custom()
// .setConnectTimeout(null)
// .setSocketTimeout(null)
.setTimeToLive(-1, TimeUnit.MILLISECONDS)
.build();
}

@Override
public boolean supportsMethod(String method) {
return true;
}

@Override
protected ApacheHttp2Request buildRequest(String method, String url) {
SimpleRequestBuilder requestBuilder = SimpleRequestBuilder.create(method).setUri(url);
return new ApacheHttp2Request(httpAsyncClient, requestBuilder);
}

@Override
public void shutdown() throws IOException {
if (httpAsyncClient instanceof CloseableHttpAsyncClient) {
((CloseableHttpAsyncClient) httpAsyncClient).close();
}
}

public HttpAsyncClient getHttpClient() {
return httpAsyncClient;
}
}
Loading