All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anthavio.httl.transport.HttpClient3Transport Maven / Gradle / Ivy

The newest version!
package net.anthavio.httl.transport;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.List;

import net.anthavio.httl.HttlBody;
import net.anthavio.httl.HttlBodyMarshaller;
import net.anthavio.httl.HttlRequest;
import net.anthavio.httl.HttlSender.Multival;
import net.anthavio.httl.HttlTransport;
import net.anthavio.httl.util.ReaderInputStream;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.ConnectionPoolTimeoutException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.StatusLine;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.OptionsMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author martin.vanek
 *
 */
public class HttpClient3Transport implements HttlTransport {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	private final HttpClient httpClient;

	private final HttpClient3Config config;

	public HttpClient3Transport(HttpClient3Config config) {
		this.config = config;
		this.httpClient = config.newHttpClient();
	}

	@Override
	public HttpClient3Config getConfig() {
		return config;
	}

	@Override
	public void close() {
		try {
			if (httpClient.getHttpConnectionManager() instanceof MultiThreadedHttpConnectionManager) {
				MultiThreadedHttpConnectionManager connectionManager = (MultiThreadedHttpConnectionManager) httpClient
						.getHttpConnectionManager();
				connectionManager.closeIdleConnections(0); //shutdown do not empty connection pool
				connectionManager.shutdown();
			}
		} catch (Exception x) {
			logger.warn("Exception while closing sender", x);
		}
	}

	/**
	 * Backdoor
	 */
	public HttpClient getHttpClient() {
		return httpClient;
	}

	@Override
	public HttpClient3Response call(HttlRequest request) throws IOException {

		String urlFile = request.getPathAndQuery();
		HttpMethodBase httpMethod;
		switch (request.getMethod()) {
		case GET:
			httpMethod = new GetMethod(urlFile);
			break;
		case HEAD:
			httpMethod = new HeadMethod(urlFile);
			break;
		case OPTIONS:
			httpMethod = new OptionsMethod(urlFile);
			break;
		case DELETE:
			httpMethod = new DeleteMethod(urlFile);
			break;
		case POST:
			PostMethod httpPost = new PostMethod(urlFile);
			setEntity(request, httpPost);
			httpMethod = httpPost;
			break;
		case PUT:
			PutMethod httpPut = new PutMethod(urlFile);
			setEntity(request, httpPut);
			httpMethod = httpPut;
			break;
		case PATCH:
			PatchMethod httpPatch = new PatchMethod(urlFile);
			setEntity(request, httpPatch);
			httpMethod = httpPatch;
			break;
		default:
			throw new IllegalArgumentException("Unsupported method " + request.getMethod());
		}

		Multival headers = request.getHeaders();
		if (headers != null && headers.size() != 0) {
			for (String name : headers) {
				List values = headers.get(name);
				for (String value : values) {
					httpMethod.addRequestHeader(name, value);
				}
			}
		}

		if (request.getReadTimeoutMillis() != null) {
			httpMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, request.getReadTimeoutMillis());
		}
		//cannot be set globally in configuration
		httpMethod.setFollowRedirects(config.getFollowRedirects());

		int statusCode = call(httpMethod);

		Header[] responseHeaders = httpMethod.getResponseHeaders();

		Multival outHeaders = new Multival();
		for (Header header : responseHeaders) {
			outHeaders.add(header.getName(), header.getValue());
		}
		StatusLine statusLine = httpMethod.getStatusLine();

		InputStream responseStream = httpMethod.getResponseBodyAsStream();

		HttpClient3Response response = new HttpClient3Response(request, statusCode, statusLine.getReasonPhrase(),
				outHeaders, responseStream, httpMethod);
		return response;
	}

	private void setEntity(HttlRequest request, EntityEnclosingMethod into) throws IOException {
		HttlBody body = request.getBody();
		if (body != null) {
			RequestEntity entity;
			switch (body.getType()) {
			case MARSHALL:
				entity = new MarshallableEntity(request, request.getSender().getMarshaller());
				break;
			case STRING:
				entity = new StringRequestEntity((String) body.getPayload(), null, request.getCharset());
				break;
			case BYTES:
				entity = new ByteArrayRequestEntity((byte[]) body.getPayload());
				break;
			case STREAM:
				entity = new InputStreamRequestEntity((InputStream) body.getPayload());
				break;
			case READER:
				entity = new InputStreamRequestEntity(new ReaderInputStream((Reader) body.getPayload()));
				break;
			default:
				throw new IllegalStateException("Unsupported HttlBody type: " + body.getType());
			}
			into.setRequestEntity(entity);
		}
	}

	protected int call(HttpMethodBase httpRequest) throws IOException {
		try {
			return this.httpClient.executeMethod(httpRequest);
		} catch (Exception x) {
			//connection might be already open so release request
			httpRequest.releaseConnection();
			//now try to 
			if (x instanceof ConnectionPoolTimeoutException) {
				ConnectException cx = new ConnectException("Pool timeout " + config.getPoolAcquireTimeoutMillis() + " ms");
				cx.setStackTrace(x.getStackTrace());
				throw cx;
			} else if (x instanceof ConnectTimeoutException) {
				ConnectException cx = new ConnectException("Connect timeout " + config.getConnectTimeoutMillis() + " ms");
				cx.setStackTrace(x.getStackTrace());
				throw cx;
			} else if (x instanceof SocketTimeoutException) {
				int timeout = httpRequest.getParams().getIntParameter(HttpMethodParams.SO_TIMEOUT,
						config.getReadTimeoutMillis());
				SocketTimeoutException stx = new SocketTimeoutException("Read timeout " + timeout + " ms");
				stx.setStackTrace(x.getStackTrace());
				throw stx;
			} else if (x instanceof ConnectException) {
				//enhance message with url
				ConnectException ctx = new ConnectException("Connection refused " + httpRequest.getPath());
				ctx.setStackTrace(x.getStackTrace());
				throw ctx;
			} else if (x instanceof IOException) {
				throw (IOException) x;//just rethrow IO
			} else {
				throw new IOException(x.getMessage(), x);//wrap others
			}
		}
	}

	private static class MarshallableEntity implements RequestEntity {

		private final HttlRequest request;

		private final HttlBodyMarshaller marshaller;

		private MarshallableEntity(HttlRequest request, HttlBodyMarshaller marshaller) throws IOException {
			this.request = request;
			this.marshaller = marshaller;
		}

		@Override
		public boolean isRepeatable() {
			return true;
		}

		@Override
		public void writeRequest(OutputStream stream) throws IOException {
			marshaller.marshall(request.getBody().getPayload(), request.getMediaType(), request.getCharset(), stream);
		}

		@Override
		public long getContentLength() {
			return -1;
		}

		@Override
		public String getContentType() {
			return null; //we set ContentType before
		}

	}

}

class PatchMethod extends EntityEnclosingMethod {

	public PatchMethod() {
		super();
	}

	public PatchMethod(String uri) {
		super(uri);
	}

	public String getName() {
		return "PATCH";
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy