public class PoolingClientConnectionManager implements ClientConnectionManager, ConnPoolControl<HttpRoute> { private final Log log = LogFactory.getLog(getClass()); private final SchemeRegistry schemeRegistry; private final HttpConnPool pool; private final ClientConnectionOperator operator; /** the custom-configured DNS lookup mechanism. */ private final DnsResolver dnsResolver; public PoolingClientConnectionManager(final SchemeRegistry schreg) { this(schreg, -1, TimeUnit.MILLISECONDS); } public PoolingClientConnectionManager(final SchemeRegistry schreg,final DnsResolver dnsResolver) { this(schreg, -1, TimeUnit.MILLISECONDS,dnsResolver); } public PoolingClientConnectionManager() { this(SchemeRegistryFactory.createDefault()); } public PoolingClientConnectionManager( final SchemeRegistry schemeRegistry, final long timeToLive, final TimeUnit tunit) { this(schemeRegistry, timeToLive, tunit, new SystemDefaultDnsResolver()); } public PoolingClientConnectionManager(final SchemeRegistry schemeRegistry, final long timeToLive, final TimeUnit tunit, final DnsResolver dnsResolver) { super(); Args.notNull(schemeRegistry, "Scheme registry"); Args.notNull(dnsResolver, "DNS resolver"); this.schemeRegistry = schemeRegistry; this.dnsResolver = dnsResolver; this.operator = createConnectionOperator(schemeRegistry); this.pool = new HttpConnPool(this.log, this.operator, 2, 20, timeToLive, tunit); } @Override protected void finalize() throws Throwable { try { shutdown(); } finally { super.finalize(); } }
class HttpConnPool extends AbstractConnPool<HttpRoute, OperatedClientConnection, HttpPoolEntry> { private static final AtomicLong COUNTER = new AtomicLong(); private final Log log; private final long timeToLive; private final TimeUnit tunit; public HttpConnPool(final Log log, final ClientConnectionOperator connOperator, final int defaultMaxPerRoute, final int maxTotal, final long timeToLive, final TimeUnit tunit) { super(new InternalConnFactory(connOperator), defaultMaxPerRoute, maxTotal); this.log = log; this.timeToLive = timeToLive; this.tunit = tunit; } @Override protected HttpPoolEntry createEntry(final HttpRoute route, final OperatedClientConnection conn) { final String id = Long.toString(COUNTER.getAndIncrement()); return new HttpPoolEntry(this.log, id, route, conn, this.timeToLive, this.tunit); } static class InternalConnFactory implements ConnFactory<HttpRoute, OperatedClientConnection> { private final ClientConnectionOperator connOperator; InternalConnFactory(final ClientConnectionOperator connOperator) { this.connOperator = connOperator; } public OperatedClientConnection create(final HttpRoute route) throws IOException { return connOperator.createConnection(); } } }
public abstract class AbstractConnPool<T, C, E extends PoolEntry<T, C>> implements ConnPool<T, E>, ConnPoolControl<T> { private final Lock lock; private final ConnFactory<T, C> connFactory; private final Map<T, RouteSpecificPool<T, C, E>> routeToPool; private final Set<E> leased; private final LinkedList<E> available; private final LinkedList<PoolEntryFuture<E>> pending; private final Map<T, Integer> maxPerRoute; private volatile boolean isShutDown; private volatile int defaultMaxPerRoute; private volatile int maxTotal; public AbstractConnPool( final ConnFactory<T, C> connFactory, final int defaultMaxPerRoute, final int maxTotal) { super(); this.connFactory = Args.notNull(connFactory, "Connection factory"); this.defaultMaxPerRoute = Args.notNegative(defaultMaxPerRoute, "Max per route value"); this.maxTotal = Args.notNegative(maxTotal, "Max total value"); this.lock = new ReentrantLock(); this.routeToPool = new HashMap<T, RouteSpecificPool<T, C, E>>(); this.leased = new HashSet<E>(); this.available = new LinkedList<E>(); this.pending = new LinkedList<PoolEntryFuture<E>>(); this.maxPerRoute = new HashMap<T, Integer>(); }
class HttpPoolEntry extends PoolEntry<HttpRoute, OperatedClientConnection> { private final Log log; private final RouteTracker tracker; public HttpPoolEntry( final Log log, final String id, final HttpRoute route, final OperatedClientConnection conn, final long timeToLive, final TimeUnit tunit) { super(id, route, conn, timeToLive, tunit); this.log = log; this.tracker = new RouteTracker(route); } @Override public boolean isExpired(final long now) { final boolean expired = super.isExpired(now); if (expired && this.log.isDebugEnabled()) { this.log.debug("Connection " + this + " expired @ " + new Date(getExpiry())); } return expired; } RouteTracker getTracker() { return this.tracker; } HttpRoute getPlannedRoute() { return getRoute(); } HttpRoute getEffectiveRoute() { return this.tracker.toRoute(); } @Override public boolean isClosed() { final OperatedClientConnection conn = getConnection(); return !conn.isOpen(); } @Override public void close() { final OperatedClientConnection conn = getConnection(); try { conn.close(); } catch (final IOException ex) { this.log.debug("I/O error closing connection", ex); } } }
public final class RouteTracker implements RouteInfo, Cloneable { /** The target host to connect to. */ private final HttpHost targetHost; /** * The local address to connect from. * <code>null</code> indicates that the default should be used. */ private final InetAddress localAddress; // the attributes above are fixed at construction time // now follow attributes that indicate the established route /** Whether the first hop of the route is established. */ private boolean connected; /** The proxy chain, if any. */ private HttpHost[] proxyChain; /** Whether the the route is tunnelled end-to-end through proxies. */ private TunnelType tunnelled; /** Whether the route is layered over a tunnel. */ private LayerType layered; /** Whether the route is secure. */ private boolean secure; /** * Creates a new route tracker. * The target and origin need to be specified at creation time. * * @param target the host to which to route * @param local the local address to route from, or * <code>null</code> for the default */ public RouteTracker(final HttpHost target, final InetAddress local) { Args.notNull(target, "Target host"); this.targetHost = target; this.localAddress = local; this.tunnelled = TunnelType.PLAIN; this.layered = LayerType.PLAIN; }