/** * * Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com> * * ==================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== */ package org.jclouds.http.httpnio.config; import static com.google.common.base.Preconditions.checkState; import java.io.Closeable; import java.io.IOException; import java.net.URI; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import org.apache.http.ConnectionReuseStrategy; import org.apache.http.HttpEntity; import org.apache.http.HttpVersion; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.nio.NHttpConnection; import org.apache.http.nio.entity.BufferingNHttpEntity; import org.apache.http.nio.entity.ConsumingNHttpEntity; import org.apache.http.nio.protocol.AsyncNHttpClientHandler; import org.apache.http.nio.protocol.NHttpRequestExecutionHandler; import org.apache.http.nio.reactor.IOReactorException; import org.apache.http.nio.util.ByteBufferAllocator; import org.apache.http.nio.util.HeapByteBufferAllocator; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.RequestConnControl; import org.apache.http.protocol.RequestContent; import org.apache.http.protocol.RequestExpectContinue; import org.apache.http.protocol.RequestTargetHost; import org.apache.http.protocol.RequestUserAgent; import org.jclouds.Constants; import org.jclouds.http.HttpCommandRendezvous; import org.jclouds.http.HttpUtils; import org.jclouds.http.TransformingHttpCommandExecutorService; import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; import org.jclouds.http.httpnio.pool.NioHttpCommandConnectionPool; import org.jclouds.http.httpnio.pool.NioHttpCommandExecutionHandler; import org.jclouds.http.httpnio.pool.NioTransformingHttpCommandExecutorService; import org.jclouds.http.httpnio.pool.NioHttpCommandExecutionHandler.ConsumingNHttpEntityFactory; import org.jclouds.http.pool.config.ConnectionPoolCommandExecutorServiceModule; import org.jclouds.lifecycle.Closer; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; /** * * @author Adrian Cole */ @ConfiguresHttpCommandExecutorService public class NioTransformingHttpCommandExecutorServiceModule extends ConnectionPoolCommandExecutorServiceModule<NHttpConnection> { @Provides // @Singleton per uri... public AsyncNHttpClientHandler provideAsyncNttpConnectionHandler( BasicHttpProcessor httpProcessor, NHttpRequestExecutionHandler execHandler, ConnectionReuseStrategy connStrategy, ByteBufferAllocator allocator, HttpParams params) { return new AsyncNHttpClientHandler(httpProcessor, execHandler, connStrategy, allocator, params); } @Provides @Singleton public BasicHttpProcessor provideConnectionProcessor() { BasicHttpProcessor httpproc = new BasicHttpProcessor(); httpproc.addInterceptor(new RequestContent()); httpproc.addInterceptor(new RequestTargetHost()); httpproc.addInterceptor(new RequestConnControl()); httpproc.addInterceptor(new RequestUserAgent()); httpproc.addInterceptor(new RequestExpectContinue()); return httpproc; } @Singleton @Provides HttpParams newBasicHttpParams(HttpUtils utils) { BasicHttpParams params = new BasicHttpParams(); params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true) .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true).setParameter( CoreProtocolPNames.ORIGIN_SERVER, "jclouds/1.0"); if (utils.getConnectionTimeout() > 0) { params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, utils .getConnectionTimeout()); } if (utils.getSocketOpenTimeout() > 0) { params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, utils.getSocketOpenTimeout()); } HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); return params; } protected void configure() { super.configure(); bind(TransformingHttpCommandExecutorService.class).to( NioTransformingHttpCommandExecutorService.class); bind(new TypeLiteral<BlockingQueue<HttpCommandRendezvous<?>>>() { }).to(new TypeLiteral<LinkedBlockingQueue<HttpCommandRendezvous<?>>>() { }).in(Scopes.SINGLETON); bind(NioHttpCommandExecutionHandler.ConsumingNHttpEntityFactory.class).to( ConsumingNHttpEntityFactoryImpl.class).in(Scopes.SINGLETON); bind(NHttpRequestExecutionHandler.class).to(NioHttpCommandExecutionHandler.class).in( Scopes.SINGLETON); bind(ConnectionReuseStrategy.class).to(DefaultConnectionReuseStrategy.class).in( Scopes.SINGLETON); bind(ByteBufferAllocator.class).to(HeapByteBufferAllocator.class); bind(NioHttpCommandConnectionPool.Factory.class).to(Factory.class).in(Scopes.SINGLETON); } private static class Factory implements NioHttpCommandConnectionPool.Factory { Closer closer; ExecutorService executor; int maxConnectionReuse; int maxSessionFailures; Provider<Semaphore> allConnections; Provider<BlockingQueue<HttpCommandRendezvous<?>>> commandQueue; Provider<BlockingQueue<NHttpConnection>> available; Provider<AsyncNHttpClientHandler> clientHandler; Provider<DefaultConnectingIOReactor> ioReactor; HttpParams params; @SuppressWarnings("unused") @Inject Factory(Closer closer, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, @Named(Constants.PROPERTY_MAX_CONNECTION_REUSE) int maxConnectionReuse, @Named(Constants.PROPERTY_MAX_SESSION_FAILURES) int maxSessionFailures, Provider<Semaphore> allConnections, Provider<BlockingQueue<HttpCommandRendezvous<?>>> commandQueue, Provider<BlockingQueue<NHttpConnection>> available, Provider<AsyncNHttpClientHandler> clientHandler, Provider<DefaultConnectingIOReactor> ioReactor, HttpParams params) { this.closer = closer; this.executor = executor; this.maxConnectionReuse = maxConnectionReuse; this.maxSessionFailures = maxSessionFailures; this.allConnections = allConnections; this.commandQueue = commandQueue; this.available = available; this.clientHandler = clientHandler; this.ioReactor = ioReactor; this.params = params; } public NioHttpCommandConnectionPool create(URI endPoint) { NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(executor, allConnections.get(), commandQueue.get(), available.get(), clientHandler.get(), ioReactor.get(), params, endPoint, maxConnectionReuse, maxSessionFailures); pool.start(); closer.addToClose(new PoolCloser(pool)); return pool; } private static class PoolCloser implements Closeable { private final NioHttpCommandConnectionPool pool; protected PoolCloser(NioHttpCommandConnectionPool pool) { this.pool = pool; } public void close() throws IOException { pool.shutdown(); } } } private static class ConsumingNHttpEntityFactoryImpl implements ConsumingNHttpEntityFactory { @Inject javax.inject.Provider<ByteBufferAllocator> allocatorProvider; public ConsumingNHttpEntity create(HttpEntity httpEntity) { return new BufferingNHttpEntity(httpEntity, allocatorProvider.get()); } } @Override public BlockingQueue<NHttpConnection> provideAvailablePool(HttpUtils utils) throws Exception { return new ArrayBlockingQueue<NHttpConnection>(utils.getMaxConnectionsPerHost() != 0 ? utils .getMaxConnectionsPerHost() : utils.getMaxConnections(), true); } @Provides // uri scope public DefaultConnectingIOReactor provideDefaultConnectingIOReactor( @Named(Constants.PROPERTY_IO_WORKER_THREADS) int maxWorkerThreads, HttpParams params) throws IOReactorException { checkState(maxWorkerThreads > 0, "io reactor needs at least 1 thread"); return new DefaultConnectingIOReactor(maxWorkerThreads, params); } }