Skip to content

Commit

Permalink
Let RestClient can reuse connections
Browse files Browse the repository at this point in the history
Implement #14

Change-Id: I49c0675566145e233e40f25fe0c30c9614bf2c14
  • Loading branch information
Linary authored and javeme committed Apr 17, 2019
1 parent 306b4f1 commit 87c5826
Show file tree
Hide file tree
Showing 8 changed files with 521 additions and 38 deletions.
19 changes: 16 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.baidu.hugegraph</groupId>
<artifactId>hugegraph-common</artifactId>
<version>1.5.8</version>
<version>1.5.9</version>

<name>hugegraph-common</name>
<url>https://github.com/hugegraph/hugegraph-common</url>
Expand Down Expand Up @@ -66,9 +66,11 @@
<javax.json.version>1.0</javax.json.version>
<jsr305.version>3.0.1</jsr305.version>
<javassist.version>3.21.0-GA</javassist.version>
<jersey.version>2.25.1</jersey.version>
<!--TODO: Update to 2.29 when released-->
<jersey.version>2.22</jersey.version>
<jersey.hk2.version>2.27</jersey.hk2.version>
<junit.version>4.12</junit.version>
<mockito.version>2.25.1</mockito.version>
</properties>

<dependencies>
Expand All @@ -78,6 +80,12 @@
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>

<!-- Logging -->
<dependency>
Expand Down Expand Up @@ -157,6 +165,11 @@
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
Expand Down Expand Up @@ -199,7 +212,7 @@
<manifestEntries>
<!-- Must be on one line, otherwise the automatic
upgrade script cannot replace the version number -->
<Implementation-Version>1.5.8.0</Implementation-Version>
<Implementation-Version>1.5.9.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Expand Down
117 changes: 87 additions & 30 deletions src/main/java/com/baidu/hugegraph/rest/RestClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package com.baidu.hugegraph.rest;

import static org.glassfish.jersey.apache.connector.ApacheClientProperties.CONNECTION_MANAGER;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
Expand All @@ -33,6 +35,9 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Variant;

import org.apache.http.config.SocketConfig;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
Expand All @@ -45,24 +50,42 @@

public abstract class RestClient {

private Client client;
private WebTarget target;
private final ClientConfig config;
private final Client client;
private final WebTarget target;

public RestClient(String url, int timeout) {
this(url, buildConfig(timeout));
this(url, new ConfigBuilder().config(timeout).build());
}

public RestClient(String url, int timeout, int maxTotal, int maxPerRoute) {
this(url, new ConfigBuilder().config(timeout)
.config(timeout, maxTotal, maxPerRoute)
.build());
}

public RestClient(String url, String user, String password, int timeout) {
this(url, buildConfigWithBasicAuth(user, password, timeout));
this(url, new ConfigBuilder().config(timeout)
.config(user, password)
.build());
}

public RestClient(String url, String user, String password, int timeout,
int maxTotal, int maxPerRoute) {
this(url, new ConfigBuilder().config(timeout)
.config(user, password)
.config(timeout, maxTotal, maxPerRoute)
.build());
}

public RestClient(String url, ClientConfig config) {
this.client = ClientBuilder.newClient(config);
this.config = config;
this.client = ClientBuilder.newClient(this.config);
this.client.register(GZipEncoder.class);
this.target = this.client.target(url);
}

private Response request(Callable<Response> method) {
protected Response request(Callable<Response> method) {
try {
return method.call();
} catch (Exception e) {
Expand Down Expand Up @@ -208,30 +231,64 @@ private static String encode(String raw) {
return UriComponent.encode(raw, UriComponent.Type.PATH_SEGMENT);
}

private static ClientConfig buildConfigWithBasicAuth(String username,
String password,
int timeout) {
ClientConfig config = buildConfig(timeout);
/*
* NOTE: don't use non-preemptive mode
* In non-preemptive mode the authentication information is added
* only when server refuses the request with 401 status code and
* then the request is repeated.
* Non-preemptive has negative impact on the performance. The advantage
* is that it does not send credentials when they are not needed.
* https://jersey.github.io/documentation/latest/client.html#d0e5461
*/
config.register(HttpAuthenticationFeature.basic(username, password));
return config;
}

private static ClientConfig buildConfig(int timeout) {
ClientConfig config = new ClientConfig();
config.property(ClientProperties.CONNECT_TIMEOUT, timeout);
config.property(ClientProperties.READ_TIMEOUT, timeout);
return config;
}

protected abstract void checkStatus(Response response,
Response.Status... statuses);

private static class ConfigBuilder {

private final ClientConfig config;

public ConfigBuilder() {
this.config = new ClientConfig();
}

public ConfigBuilder config(int timeout) {
this.config.property(ClientProperties.CONNECT_TIMEOUT, timeout);
this.config.property(ClientProperties.READ_TIMEOUT, timeout);
return this;
}

public ConfigBuilder config(String username, String password) {
/*
* NOTE: don't use non-preemptive mode
* In non-preemptive mode the authentication information is added
* only when server refuses the request with 401 status code and
* then the request is repeated.
* Non-preemptive has negative impact on the performance. The
* advantage is it doesn't send credentials when they are not needed
* https://jersey.github.io/documentation/latest/client.html#d0e5461
*/
this.config.register(HttpAuthenticationFeature.basic(username,
password));
return this;
}

public ConfigBuilder config(int timeout, int maxTotal,
int maxPerRoute) {
/*
* Using httpclient with connection pooling, and configuring the
* jersey connector, reference:
* http://www.theotherian.com/2013/08/jersey-client-2.0-httpclient-timeouts-max-connections.html
* https://stackoverflow.com/questions/43228051/memory-issue-with-jax-rs-using-jersey/46175943#46175943
*
* But the jersey that has been released in the maven central
* repository seems to have a bug.
* https://github.com/jersey/jersey/pull/3752
*/
PoolingHttpClientConnectionManager pcm =
new PoolingHttpClientConnectionManager();
pcm.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(timeout)
.build());
pcm.setMaxTotal(maxTotal);
pcm.setDefaultMaxPerRoute(maxPerRoute);
this.config.property(CONNECTION_MANAGER, pcm);
this.config.connectorProvider(new ApacheConnectorProvider());
return this;
}

public ClientConfig build() {
return this.config;
}
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/baidu/hugegraph/rest/RestResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ public class RestResult {

private static final ObjectMapper mapper = new ObjectMapper();

private int status;
private MultivaluedMap<String, Object> headers;
private String content;
private final int status;
private final MultivaluedMap<String, Object> headers;
private final String content;

public RestResult(Response response) {
this.status = response.getStatus();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/baidu/hugegraph/util/VersionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static boolean match(Version version, String begin, String end) {
/**
* Compare if a version is greater than the other one (inclusive)
* @param version The version to be compared
* @param begin The lower bound of the range
* @param other The lower bound of the range
* @return true if it's greater than the other, otherwise false
*/
public static boolean gte(String version, String other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ public class CommonVersion {

// The second parameter of Version.of() is for all-in-one JAR
public static final Version VERSION = Version.of(CommonVersion.class,
"1.5.8");
"1.5.9");
}
4 changes: 4 additions & 0 deletions src/test/java/com/baidu/hugegraph/unit/UnitTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.baidu.hugegraph.unit.iterator.FlatMapperIteratorTest;
import com.baidu.hugegraph.unit.iterator.MapperIteratorTest;
import com.baidu.hugegraph.unit.perf.PerfUtilTest;
import com.baidu.hugegraph.unit.rest.RestClientTest;
import com.baidu.hugegraph.unit.rest.RestResultTest;
import com.baidu.hugegraph.unit.util.BytesTest;
import com.baidu.hugegraph.unit.util.CollectionUtilTest;
import com.baidu.hugegraph.unit.util.HashUtilTest;
Expand All @@ -46,6 +48,8 @@
HugeConfigTest.class,
EventHubTest.class,
PerfUtilTest.class,
RestClientTest.class,
RestResultTest.class,
VersionTest.class,

ExtendableIteratorTest.class,
Expand Down
Loading

0 comments on commit 87c5826

Please sign in to comment.