package org.jboss.resteasy.client.jaxrs.engines;

import org.jboss.resteasy.client.jaxrs.ClientHttpEngine;
import org.jboss.resteasy.client.jaxrs.i18n.Messages;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
import org.jboss.resteasy.client.jaxrs.internal.ClientResponse;
import org.jboss.resteasy.client.jaxrs.internal.FinalizedClientResponse;
import org.jboss.resteasy.tracing.RESTEasyTracingLogger;
import org.jboss.resteasy.util.CaseInsensitiveMap;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.Map;

Author:Alexey Ogarkov
Version:$Revision: 1 $
/** * @author <a href="mailto:alexey.ogarkov@gmail.com">Alexey Ogarkov</a> * @version $Revision: 1 $ */
public class URLConnectionEngine implements ClientHttpEngine { protected SSLContext sslContext; protected HostnameVerifier hostnameVerifier; protected Integer readTimeout; protected Integer connectTimeout; protected String proxyHost; protected Integer proxyPort; protected String proxyScheme; protected boolean followRedirects;
{@inheritDoc}
/** * {@inheritDoc} */
@Override public Response invoke(Invocation inv) { ClientInvocation request = (ClientInvocation) inv; final HttpURLConnection connection; final int status; try { connection = createConnection(request); executeRequest(request, connection); status = connection.getResponseCode(); } catch (IOException e) { throw new ProcessingException(Messages.MESSAGES.unableToInvokeRequest(e.toString()), e); } //Creating response with stream content ClientResponse response = new FinalizedClientResponse(request.getClientConfiguration(), RESTEasyTracingLogger.empty()) { private InputStream stream; @Override protected InputStream getInputStream() { if (stream == null) { try { stream = (status < 300) ? connection.getInputStream() : connection.getErrorStream(); } catch (IOException e) { throw new RuntimeException(e); } } return stream; } @Override protected void setInputStream(InputStream is) { stream = is; resetEntity(); } @Override public void releaseConnection() throws IOException { releaseConnection(false); } @Override public void releaseConnection(boolean consumeInputStream) throws IOException { InputStream is = getInputStream(); if (is != null) { // https://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html if (consumeInputStream) { while (is.read() > 0) { } } is.close(); } connection.disconnect(); } }; //Setting attributes response.setStatus(status); response.setHeaders(getHeaders(connection)); return response; }
Create map with response headers.
Params:
  • connection – - HttpURLConnection
Returns:map key - list of values
/** * Create map with response headers. * * @param connection - HttpURLConnection * @return map key - list of values */
protected MultivaluedMap<String, String> getHeaders( final HttpURLConnection connection) { MultivaluedMap<String, String> headers = new CaseInsensitiveMap<String>(); for (Map.Entry<String, List<String>> header : connection.getHeaderFields() .entrySet()) { if (header.getKey() != null) { for (String value : header.getValue()) { headers.add(header.getKey(), value); } } } return headers; } @Override public void close() { //empty }
Create HttpUrlConnection from ClientInvorcation and set request method.
Params:
  • request – ClientInvocation
Throws:
Returns:HttpURLConnection with method & url already set
/** * Create HttpUrlConnection from ClientInvorcation and set request method. * @param request ClientInvocation * @return HttpURLConnection with method {@literal &} url already set * @throws IOException if url or io exceptions */
protected HttpURLConnection createConnection(final ClientInvocation request) throws IOException { Proxy proxy = null; if (this.proxyHost != null && this.proxyPort != null) { proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.proxyHost, this.proxyPort)); } else { proxy = Proxy.NO_PROXY; } HttpURLConnection connection = (HttpURLConnection) request.getUri().toURL().openConnection(proxy); connection.setRequestMethod(request.getMethod()); if (this.connectTimeout != null) { connection.setConnectTimeout(this.connectTimeout); } if (this.readTimeout != null) { connection.setReadTimeout(this.readTimeout); } return connection; }
Execute request using HttpURLConnection with body from invocation if needed.
Params:
  • request – ClientInvocation
  • connection – HttpURLConnection
/** * Execute request using HttpURLConnection with body from invocation if needed. * * @param request ClientInvocation * @param connection HttpURLConnection */
protected void executeRequest(final ClientInvocation request, HttpURLConnection connection) { connection.setInstanceFollowRedirects(request.getMethod().equals("GET")); if (request.getEntity() != null) { if (request.getMethod().equals("GET")) throw new ProcessingException(Messages.MESSAGES.getRequestCannotHaveBody()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); request.getDelegatingOutputStream().setDelegate(baos); try { request.writeRequestBody(request.getEntityStream()); baos.close(); commitHeaders(request, connection); connection.setDoOutput(true); OutputStream os = connection.getOutputStream(); os.write(baos.toByteArray()); os.flush(); os.close(); } catch (IOException e) { throw new RuntimeException(e); } } else // no body { commitHeaders(request, connection); } }
Add headers to HttpURLConnection from ClientInvocation. Should be executed before writing body.
Params:
  • request – ClientInvocation
  • connection – HttpURLConnection
/** * Add headers to HttpURLConnection from ClientInvocation. Should be executed before writing body. * @param request ClientInvocation * @param connection HttpURLConnection */
protected void commitHeaders(ClientInvocation request, HttpURLConnection connection) { MultivaluedMap<String, String> headers = request.getHeaders().asMap(); for (Map.Entry<String, List<String>> header : headers.entrySet()) { List<String> values = header.getValue(); for (String value : values) { connection.addRequestProperty(header.getKey(), value); } } }
{inheritDoc}
/** * {inheritDoc} */
@Override public SSLContext getSslContext() { return sslContext; }
{inheritDoc}
/** * {inheritDoc} */
@Override public HostnameVerifier getHostnameVerifier() { return hostnameVerifier; } public void setSslContext(SSLContext sslContext) { this.sslContext = sslContext; } public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { this.hostnameVerifier = hostnameVerifier; } public void setConnectTimeout(Integer connectTimeout) { this.connectTimeout = connectTimeout; } public void setReadTimeout(Integer readTimeout) { this.readTimeout = readTimeout; } public void setProxyHost(String proxyHost) { this.proxyHost = proxyHost; } public void setProxyPort(Integer proxyPort) { this.proxyPort = proxyPort; } public void setProxyScheme(String proxyScheme) { this.proxyScheme = proxyScheme; } public void setFollowRedirects(boolean followRedirects) { this.followRedirects = followRedirects; } public boolean isFollowRedirects() { return this.followRedirects; } }