Use apache httpclient as backend for jersey client base on PoolingHttpClientConnectionManager

948 views Asked by At

i try to use apache httpclient as backend for jersey client to handle cookie automatically and here is my code

class ClientHelper {
  public static HttpClientConnectionManager customConnectionManager() throws Exception {
  final SSLContext sslContext = SSLContext.getInstance("SSL");

sslContext.init(null, new TrustManager[]{new X509TrustManager() {
  @Override
  public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
      throws CertificateException {
    System.out.println("========checkClientTrusted=========");
  }

  @Override
  public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
      throws CertificateException {
    System.out.println("========checkServerTrusted==========");
  }

  @Override
  public X509Certificate[] getAcceptedIssuers() {
    return null;
  }
}}, new SecureRandom());

SSLConnectionSocketFactory
    sslConnectionSocketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
    .register("https", sslConnectionSocketFactory)
    .register("http", PlainConnectionSocketFactory.getSocketFactory())
    .build();
PoolingHttpClientConnectionManager phcc = new PoolingHttpClientConnectionManager(registry);
return phcc;
}

public static Client createClient() {
  HttpClient apacheClient = null;
  try {
  apacheClient =
      HttpClientBuilder.create().setConnectionManager(customConnectionManager()).build();

} catch (Exception e) {
  e.printStackTrace();
}
Client client = new Client(new ApacheHttpClient4Handler(apacheClient,
                                                        new BasicCookieStore(),
                                                        true));
return client;
  }
  }

I try to use the apache httpclient as the backend of jersey client (in order to handle the cookie)

Then, I create a simple class to test client,

import com.sun.jersey.api.client.Client;
....

public class ApiTest {

  private static Client client;

  public String getAuth(String username, String passwd) {

  Map<String, String> formParams = new HashMap<String, String>();
  formParams.put("username", String.valueOf(username));
  formParams.put("passwd", String.valueOf(passwd));

try {
  String basePath = "https://xyzhost/login";

  if (client == null) {
    client = ClientHelper.createClient();
    client.addFilter(new LoggingFilter(System.out));
  }

  WebResource webResource = client.resource(basePath);

  ClientResponse response = webResource.type("application/x-www-form-urlencoded").accept("application/json")
      .post(ClientResponse.class, processFormParams(formParams));
  if (response != null) {
    String authRes = response.getEntity(String.class);
    response.close();

    return authRes;
  } else {
    return null;
  }
} catch (Exception ex) {
  ex.printStackTrace();
  return null;
}
 }


 public String getSummary(){

try {
  String basePath = "https://xyzhost/summary";

  if (client == null) {
    client = ClientHelper.createClient();
  }

  WebResource webResource = client
      .resource(basePath);

  ClientResponse response = webResource.type("application/x-www-form-urlencoded").accept("application/json")
      .post(ClientResponse.class, processFormParams(formParams));

  if (response != null) {
    String serviceRes = response.getEntity(String.class);
    response.close();
    return serviceRes;
  } else {
    return null;
  }
  } catch (Exception ex) {
    ex.printStackTrace();
    return null;
  }
}

public static void main(String[] args) throws ApiException {
  String username = "testuser";
  String passwd = "testpasswd";
  AuthApi apiTest = new ApiTest();
  String auth =apiTest.getAuth(username, passwd);
  String reslut1 = apiTest.getSummary();
  String result2 = apiTest.getSummary();
  String result3 = apiTest.getSummary();
  String result4 = apiTest.getSummary();
}
}

So, I use the same client to hit the service under the same host. I can success get the response for "auth" and "result1" but the client stuck in "result2" in the following part

  ClientResponse response = webResource.type("application/x-www-form-urlencoded").accept("application/json")
      .post(ClientResponse.class, processFormParams(formParams));

I try to modify the following part:

PoolingHttpClientConnectionManager phcc= new PoolingHttpClientConnectionManager(registry);
phcc.setDefaultMaxPerRoute(10);

then, ApiTest works, won't stuck. I guess there is some issue about the connection, since by default, the max per route for poolingHttpClientConnectionManager is 2, so my ApiTest will stuck in the 3rd request. I think the connection has been release since I have consume the response entity ,

if (response != null) {
    String serviceRes = response.getEntity(String.class);
    response.close();
    return serviceRes;
  }

but it seems not work at all, the connection seems not released.

anyone can help ? Appreciate!

1

There are 1 answers

0
Zach Byrant On

I get one solution: switch the version of jersey-client from 1.17 to 1.18 , then problem solved!

<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-client</artifactId>
  <version>1.18</version>
  <scope>compile</scope>
</dependency>