You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/02/22 13:08:45 UTC

svn commit: r1784019 - in /jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler: ./ hc/

Author: pmouawad
Date: Wed Feb 22 13:08:45 2017
New Revision: 1784019

URL: http://svn.apache.org/viewvc?rev=1784019&view=rev
Log:
Drop Hack of using hc4 package and import in project the required classes of HC4:
See related  https://github.com/apache/httpclient/pull/65

Added:
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java   (with props)
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java   (with props)
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java   (with props)
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java   (with props)
Modified:
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/MeasuringConnectionManager.java

Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/MeasuringConnectionManager.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/MeasuringConnectionManager.java?rev=1784019&r1=1784018&r2=1784019&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/MeasuringConnectionManager.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/MeasuringConnectionManager.java Wed Feb 22 13:08:45 2017
@@ -38,10 +38,10 @@ import org.apache.http.conn.DnsResolver;
 import org.apache.http.conn.ManagedClientConnection;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.impl.conn.JMeterPoolingClientConnectionManager;
 import org.apache.http.impl.conn.PoolingClientConnectionManager;
 import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
+import org.apache.jmeter.protocol.http.sampler.hc.JMeterPoolingClientConnectionManager;
 import org.apache.jmeter.samplers.SampleResult;
 
 /**

Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java?rev=1784019&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java Wed Feb 22 13:08:45 2017
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.protocol.http.sampler.hc;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.LongAccumulator;
+import java.util.concurrent.atomic.LongAdder;
+
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.pool.AbstractConnPool;
+import org.apache.http.pool.ConnFactory;
+import org.slf4j.Logger;
+
+/**
+ * Implementation of AbstractConnPool to allow better connection validity 
+ * management.
+ * @since 3.2
+ */
+public class HttpConnPool extends AbstractConnPool<HttpRoute, OperatedClientConnection, HttpPoolEntry> {
+
+    private static final LongAdder COUNTER = new LongAdder();
+
+    private final Logger log;
+    private final long timeToLive;
+    private final TimeUnit tunit;
+
+    public HttpConnPool(final Logger 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.sum());
+        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;
+        }
+
+        @Override
+        public OperatedClientConnection create(final HttpRoute route) throws IOException {
+            return connOperator.createConnection();
+        }
+    }
+}

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpConnPool.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java?rev=1784019&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java Wed Feb 22 13:08:45 2017
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.protocol.http.sampler.hc;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.RouteTracker;
+import org.apache.http.pool.PoolEntry;
+import org.slf4j.Logger;
+
+/**
+ * Implementation of {@link PoolEntry} 
+ * @since 3.2
+ */
+public class HttpPoolEntry extends PoolEntry<HttpRoute, OperatedClientConnection> {
+
+    private final Logger log;
+    private final RouteTracker tracker;
+
+    public HttpPoolEntry(
+            final Logger 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 {} expired at {}", this, 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);
+        }
+    }
+}

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/HttpPoolEntry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java?rev=1784019&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java Wed Feb 22 13:08:45 2017
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.protocol.http.sampler.hc;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.DnsResolver;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.impl.conn.DefaultClientConnectionOperator;
+import org.apache.http.impl.conn.PoolingClientConnectionManager;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.impl.conn.SchemeRegistryFactory;
+import org.apache.http.impl.conn.SystemDefaultDnsResolver;
+import org.apache.http.pool.ConnPoolControl;
+import org.apache.http.pool.PoolStats;
+import org.apache.http.util.Args;
+import org.apache.http.util.Asserts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Copy/Paste of {@link PoolingClientConnectionManager} with a slight modification 
+ * extracted from {@link PoolingHttpClientConnectionManager} to allow using 
+ * better validation mechanism introduced in 4.4
+ * TODO : Remove when full upgrade to new HttpClient 4.5.X API is finished
+ * Internal class, DO NOT USE
+ */
+public class JMeterPoolingClientConnectionManager implements ClientConnectionManager, ConnPoolControl<HttpRoute> {
+
+    private static final int VALIDATE_AFTER_INACTIVITY_DEFAULT = 1700;
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    
+    private final SchemeRegistry schemeRegistry;
+
+    private final HttpConnPool pool;
+
+    private final ClientConnectionOperator operator;
+    
+
+    /** the custom-configured DNS lookup mechanism. */
+    private final DnsResolver dnsResolver;
+
+    public JMeterPoolingClientConnectionManager(final SchemeRegistry schreg) {
+        this(schreg, -1, TimeUnit.MILLISECONDS);
+    }
+
+    public JMeterPoolingClientConnectionManager(final SchemeRegistry schreg,final DnsResolver dnsResolver) {
+        this(schreg, -1, TimeUnit.MILLISECONDS,dnsResolver);
+    }
+
+    public JMeterPoolingClientConnectionManager() {
+        this(SchemeRegistryFactory.createDefault());
+    }
+
+    public JMeterPoolingClientConnectionManager(
+            final SchemeRegistry schemeRegistry,
+            final long timeToLive, final TimeUnit tunit) {
+        this(schemeRegistry, timeToLive, tunit, new SystemDefaultDnsResolver());
+    }
+    
+    public JMeterPoolingClientConnectionManager(
+            final SchemeRegistry schemeRegistry,
+            final long timeToLive, final TimeUnit tunit,
+            final DnsResolver dnsResolver) {
+        this(schemeRegistry, timeToLive, tunit, dnsResolver, VALIDATE_AFTER_INACTIVITY_DEFAULT);
+    }
+
+    public JMeterPoolingClientConnectionManager(final SchemeRegistry schemeRegistry,
+                final long timeToLive, final TimeUnit tunit,
+                final DnsResolver dnsResolver,
+                int validateAfterInactivity) {
+        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) {
+            /**
+             * @see org.apache.http.pool.AbstractConnPool#validate(org.apache.http.pool.PoolEntry)
+             */
+            @Override
+            protected boolean validate(HttpPoolEntry entry) {
+                return !entry.getConnection().isStale();
+            }
+            
+        };
+        pool.setValidateAfterInactivity(validateAfterInactivity);
+    }
+    
+    /**
+     * @see #setValidateAfterInactivity(int)
+     *
+     * @since 4.5.2
+     */
+    public int getValidateAfterInactivity() {
+        return pool.getValidateAfterInactivity();
+    }
+
+    /**
+     * Defines period of inactivity in milliseconds after which persistent connections must
+     * be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future,
+     *   long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed
+     * to this method disables connection validation. This check helps detect connections
+     * that have become stale (half-closed) while kept inactive in the pool.
+     *
+     * @see #leaseConnection(java.util.concurrent.Future, long, java.util.concurrent.TimeUnit)
+     *
+     * @since 4.5.2
+     */
+    public void setValidateAfterInactivity(final int ms) {
+        pool.setValidateAfterInactivity(ms);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            shutdown();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Hook for creating the connection operator.
+     * It is called by the constructor.
+     * Derived classes can override this method to change the
+     * instantiation of the operator.
+     * The default implementation here instantiates
+     * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
+     *
+     * @param schreg    the scheme registry.
+     *
+     * @return  the connection operator to use
+     */
+    protected ClientConnectionOperator createConnectionOperator(final SchemeRegistry schreg) {
+        return new DefaultClientConnectionOperator(schreg, this.dnsResolver);
+    }
+    @Override
+    public SchemeRegistry getSchemeRegistry() {
+        return this.schemeRegistry;
+    }
+
+    private String format(final HttpRoute route, final Object state) {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("[route: ").append(route).append("]");
+        if (state != null) {
+            buf.append("[state: ").append(state).append("]");
+        }
+        return buf.toString();
+    }
+
+    private String formatStats(final HttpRoute route) {
+        final StringBuilder buf = new StringBuilder();
+        final PoolStats totals = this.pool.getTotalStats();
+        final PoolStats stats = this.pool.getStats(route);
+        buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
+        buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
+        buf.append(" of ").append(stats.getMax()).append("; ");
+        buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
+        buf.append(" of ").append(totals.getMax()).append("]");
+        return buf.toString();
+    }
+
+    private String format(final HttpPoolEntry entry) {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("[id: ").append(entry.getId()).append("]");
+        buf.append("[route: ").append(entry.getRoute()).append("]");
+        final Object state = entry.getState();
+        if (state != null) {
+            buf.append("[state: ").append(state).append("]");
+        }
+        return buf.toString();
+    }
+
+    @Override
+    public ClientConnectionRequest requestConnection(
+            final HttpRoute route,
+            final Object state) {
+        Args.notNull(route, "HTTP route");
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Connection request: "+format(route, state)
+                +", stats:"+formatStats(route)+", pool:"+ pool);
+        }
+        final Future<HttpPoolEntry> future = this.pool.lease(route, state);
+        
+        return new ClientConnectionRequest() {
+            @Override
+            public void abortRequest() {
+                future.cancel(true);
+            }
+            @Override
+            public ManagedClientConnection getConnection(
+                    final long timeout,
+                    final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
+                return leaseConnection(future, timeout, tunit);
+            }
+
+        };
+
+    }
+
+    ManagedClientConnection leaseConnection(
+            final Future<HttpPoolEntry> future,
+            final long timeout,
+            final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
+        final HttpPoolEntry entry;
+        try {
+            entry = future.get(timeout, tunit);
+            if (entry == null || future.isCancelled()) {
+                throw new InterruptedException();
+            }
+            Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
+            }
+            return new ManagedClientConnectionImpl(this, this.operator, entry);
+        } catch (final ExecutionException ex) {
+            Throwable cause = ex.getCause();
+            if (cause == null) {
+                cause = ex;
+            }
+            this.log.error("Unexpected exception leasing connection from pool", cause);
+            // Should never happen
+            throw new InterruptedException();
+        } catch (final TimeoutException ex) {
+            throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
+        }
+    }
+    @Override
+    public void releaseConnection(
+            final ManagedClientConnection conn, final long keepalive, final TimeUnit tunit) {
+
+        Args.check(conn instanceof ManagedClientConnectionImpl, "Connection class mismatch, " +
+            "connection not obtained from this manager");
+        final ManagedClientConnectionImpl managedConn = (ManagedClientConnectionImpl) conn;
+        Asserts.check(managedConn.getManager() == this, "Connection not obtained from this manager");
+        synchronized (managedConn) {
+            final HttpPoolEntry entry = managedConn.detach();
+            if (entry == null) {
+                return;
+            }
+            try {
+                if (managedConn.isOpen() && !managedConn.isMarkedReusable()) {
+                    try {
+                        managedConn.shutdown();
+                    } catch (final IOException iox) {
+                        if (this.log.isDebugEnabled()) {
+                            this.log.debug("I/O exception shutting down released connection", iox);
+                        }
+                    }
+                }
+                // Only reusable connections can be kept alive
+                if (managedConn.isMarkedReusable()) {
+                    entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
+                    if (this.log.isDebugEnabled()) {
+                        final String s;
+                        if (keepalive > 0) {
+                            s = "for " + keepalive + " " + tunit;
+                        } else {
+                            s = "indefinitely";
+                        }
+                        this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
+                    }
+                }
+            } finally {
+                this.pool.release(entry, managedConn.isMarkedReusable());
+            }
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
+            }
+        }
+    }
+    @Override
+    public void shutdown() {
+        this.log.debug("Connection manager is shutting down");
+        try {
+            this.pool.shutdown();
+        } catch (final IOException ex) {
+            this.log.debug("I/O exception shutting down connection manager", ex);
+        }
+        this.log.debug("Connection manager shut down");
+    }
+    @Override
+    public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
+        }
+        this.pool.closeIdle(idleTimeout, tunit);
+    }
+    @Override
+    public void closeExpiredConnections() {
+        this.log.debug("Closing expired connections");
+        this.pool.closeExpired();
+    }
+    @Override
+    public int getMaxTotal() {
+        return this.pool.getMaxTotal();
+    }
+    @Override
+    public void setMaxTotal(final int max) {
+        this.pool.setMaxTotal(max);
+    }
+    @Override
+    public int getDefaultMaxPerRoute() {
+        return this.pool.getDefaultMaxPerRoute();
+    }
+    @Override
+    public void setDefaultMaxPerRoute(final int max) {
+        this.pool.setDefaultMaxPerRoute(max);
+    }
+    @Override
+    public int getMaxPerRoute(final HttpRoute route) {
+        return this.pool.getMaxPerRoute(route);
+    }
+    @Override
+    public void setMaxPerRoute(final HttpRoute route, final int max) {
+        this.pool.setMaxPerRoute(route, max);
+    }
+    @Override
+    public PoolStats getTotalStats() {
+        return this.pool.getTotalStats();
+    }
+    @Override
+    public PoolStats getStats(final HttpRoute route) {
+        return this.pool.getStats(route);
+    }
+
+    /**
+     * @return the dnsResolver
+     */
+    protected DnsResolver getDnsResolver() {
+        return dnsResolver;
+    }
+
+}
+

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/JMeterPoolingClientConnectionManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java?rev=1784019&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java Wed Feb 22 13:08:45 2017
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.protocol.http.sampler.hc;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionOperator;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.OperatedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.RouteTracker;
+import org.apache.http.impl.conn.ConnectionShutdownException;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.Args;
+import org.apache.http.util.Asserts;
+
+/**
+ * Implementation of {@link ManagedClientConnection} 
+ * @since 3.2
+ *
+ */
+public class ManagedClientConnectionImpl implements ManagedClientConnection {
+
+    private final ClientConnectionManager manager;
+    private final ClientConnectionOperator operator;
+    private volatile HttpPoolEntry poolEntry;
+    private volatile boolean reusable;
+    private volatile long duration;
+
+    public ManagedClientConnectionImpl(
+            final ClientConnectionManager manager,
+            final ClientConnectionOperator operator,
+            final HttpPoolEntry entry) {
+        super();
+        Args.notNull(manager, "Connection manager");
+        Args.notNull(operator, "Connection operator");
+        Args.notNull(entry, "HTTP pool entry");
+        this.manager = manager;
+        this.operator = operator;
+        this.poolEntry = entry;
+        this.reusable = false;
+        this.duration = Long.MAX_VALUE;
+    }
+
+    @Override
+    public String getId() {
+        return null;
+    }
+
+    HttpPoolEntry getPoolEntry() {
+        return this.poolEntry;
+    }
+
+    public HttpPoolEntry detach() {
+        final HttpPoolEntry local = this.poolEntry;
+        this.poolEntry = null;
+        return local;
+    }
+
+    public ClientConnectionManager getManager() {
+        return this.manager;
+    }
+
+    private OperatedClientConnection getConnection() {
+        final HttpPoolEntry local = this.poolEntry;
+        if (local == null) {
+            return null;
+        }
+        return local.getConnection();
+    }
+
+    private OperatedClientConnection ensureConnection() {
+        final HttpPoolEntry local = this.poolEntry;
+        if (local == null) {
+            throw new ConnectionShutdownException();
+        }
+        return local.getConnection();
+    }
+
+    private HttpPoolEntry ensurePoolEntry() {
+        final HttpPoolEntry local = this.poolEntry;
+        if (local == null) {
+            throw new ConnectionShutdownException();
+        }
+        return local;
+    }
+
+    @Override
+    public void close() throws IOException {
+        final HttpPoolEntry local = this.poolEntry;
+        if (local != null) {
+            final OperatedClientConnection conn = local.getConnection();
+            local.getTracker().reset();
+            conn.close();
+        }
+    }
+
+    @Override
+    public void shutdown() throws IOException {
+        final HttpPoolEntry local = this.poolEntry;
+        if (local != null) {
+            final OperatedClientConnection conn = local.getConnection();
+            local.getTracker().reset();
+            conn.shutdown();
+        }
+    }
+
+    @Override
+    public boolean isOpen() {
+        final OperatedClientConnection conn = getConnection();
+        if (conn != null) {
+            return conn.isOpen();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isStale() {
+        final OperatedClientConnection conn = getConnection();
+        if (conn != null) {
+            return conn.isStale();
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public void setSocketTimeout(final int timeout) {
+        final OperatedClientConnection conn = ensureConnection();
+        conn.setSocketTimeout(timeout);
+    }
+
+    @Override
+    public int getSocketTimeout() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getSocketTimeout();
+    }
+
+    @Override
+    public HttpConnectionMetrics getMetrics() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getMetrics();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        conn.flush();
+    }
+
+    @Override
+    public boolean isResponseAvailable(final int timeout) throws IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.isResponseAvailable(timeout);
+    }
+
+    @Override
+    public void receiveResponseEntity(
+            final HttpResponse response) throws HttpException, IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        conn.receiveResponseEntity(response);
+    }
+
+    @Override
+    public HttpResponse receiveResponseHeader() throws HttpException, IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.receiveResponseHeader();
+    }
+
+    @Override
+    public void sendRequestEntity(
+            final HttpEntityEnclosingRequest request) throws HttpException, IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        conn.sendRequestEntity(request);
+    }
+
+    @Override
+    public void sendRequestHeader(
+            final HttpRequest request) throws HttpException, IOException {
+        final OperatedClientConnection conn = ensureConnection();
+        conn.sendRequestHeader(request);
+    }
+
+    @Override
+    public InetAddress getLocalAddress() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getLocalAddress();
+    }
+
+    @Override
+    public int getLocalPort() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getLocalPort();
+    }
+
+    @Override
+    public InetAddress getRemoteAddress() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getRemoteAddress();
+    }
+
+    @Override
+    public int getRemotePort() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getRemotePort();
+    }
+
+    @Override
+    public boolean isSecure() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.isSecure();
+    }
+
+    @Override
+    public void bind(final Socket socket) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Socket getSocket() {
+        final OperatedClientConnection conn = ensureConnection();
+        return conn.getSocket();
+    }
+
+    @Override
+    public SSLSession getSSLSession() {
+        final OperatedClientConnection conn = ensureConnection();
+        SSLSession result = null;
+        final Socket sock = conn.getSocket();
+        if (sock instanceof SSLSocket) {
+            result = ((SSLSocket)sock).getSession();
+        }
+        return result;
+    }
+
+    public Object getAttribute(final String id) {
+        final OperatedClientConnection conn = ensureConnection();
+        if (conn instanceof HttpContext) {
+            return ((HttpContext) conn).getAttribute(id);
+        } else {
+            return null;
+        }
+    }
+
+    public Object removeAttribute(final String id) {
+        final OperatedClientConnection conn = ensureConnection();
+        if (conn instanceof HttpContext) {
+            return ((HttpContext) conn).removeAttribute(id);
+        } else {
+            return null;
+        }
+    }
+
+    public void setAttribute(final String id, final Object obj) {
+        final OperatedClientConnection conn = ensureConnection();
+        if (conn instanceof HttpContext) {
+            ((HttpContext) conn).setAttribute(id, obj);
+        }
+    }
+
+    @Override
+    public HttpRoute getRoute() {
+        final HttpPoolEntry local = ensurePoolEntry();
+        return local.getEffectiveRoute();
+    }
+
+    @Override
+    public void open(
+            final HttpRoute route,
+            final HttpContext context,
+            final HttpParams params) throws IOException {
+        Args.notNull(route, "Route");
+        Args.notNull(params, "HTTP parameters");
+        final OperatedClientConnection conn;
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new ConnectionShutdownException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            Asserts.notNull(tracker, "Route tracker");
+            Asserts.check(!tracker.isConnected(), "Connection already open");
+            conn = this.poolEntry.getConnection();
+        }
+
+        final HttpHost proxy  = route.getProxyHost();
+        this.operator.openConnection(
+                conn,
+                (proxy != null) ? proxy : route.getTargetHost(),
+                route.getLocalAddress(),
+                context, params);
+
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new InterruptedIOException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            if (proxy == null) {
+                tracker.connectTarget(conn.isSecure());
+            } else {
+                tracker.connectProxy(proxy, conn.isSecure());
+            }
+        }
+    }
+
+    @Override
+    public void tunnelTarget(
+            final boolean secure, final HttpParams params) throws IOException {
+        Args.notNull(params, "HTTP parameters");
+        final HttpHost target;
+        final OperatedClientConnection conn;
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new ConnectionShutdownException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            Asserts.notNull(tracker, "Route tracker");
+            Asserts.check(tracker.isConnected(), "Connection not open");
+            Asserts.check(!tracker.isTunnelled(), "Connection is already tunnelled");
+            target = tracker.getTargetHost();
+            conn = this.poolEntry.getConnection();
+        }
+
+        conn.update(null, target, secure, params);
+
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new InterruptedIOException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            tracker.tunnelTarget(secure);
+        }
+    }
+
+    @Override
+    public void tunnelProxy(
+            final HttpHost next, final boolean secure, final HttpParams params) throws IOException {
+        Args.notNull(next, "Next proxy");
+        Args.notNull(params, "HTTP parameters");
+        final OperatedClientConnection conn;
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new ConnectionShutdownException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            Asserts.notNull(tracker, "Route tracker");
+            Asserts.check(tracker.isConnected(), "Connection not open");
+            conn = this.poolEntry.getConnection();
+        }
+
+        conn.update(null, next, secure, params);
+
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new InterruptedIOException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            tracker.tunnelProxy(next, secure);
+        }
+    }
+
+    @Override
+    public void layerProtocol(
+            final HttpContext context, final HttpParams params) throws IOException {
+        Args.notNull(params, "HTTP parameters");
+        final HttpHost target;
+        final OperatedClientConnection conn;
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new ConnectionShutdownException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            Asserts.notNull(tracker, "Route tracker");
+            Asserts.check(tracker.isConnected(), "Connection not open");
+            Asserts.check(tracker.isTunnelled(), "Protocol layering without a tunnel not supported");
+            Asserts.check(!tracker.isLayered(), "Multiple protocol layering not supported");
+            target = tracker.getTargetHost();
+            conn = this.poolEntry.getConnection();
+        }
+        this.operator.updateSecureConnection(conn, target, context, params);
+
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                throw new InterruptedIOException();
+            }
+            final RouteTracker tracker = this.poolEntry.getTracker();
+            tracker.layerProtocol(conn.isSecure());
+        }
+    }
+
+    @Override
+    public Object getState() {
+        final HttpPoolEntry local = ensurePoolEntry();
+        return local.getState();
+    }
+
+    @Override
+    public void setState(final Object state) {
+        final HttpPoolEntry local = ensurePoolEntry();
+        local.setState(state);
+    }
+
+    @Override
+    public void markReusable() {
+        this.reusable = true;
+    }
+
+    @Override
+    public void unmarkReusable() {
+        this.reusable = false;
+    }
+
+    @Override
+    public boolean isMarkedReusable() {
+        return this.reusable;
+    }
+
+    @Override
+    public void setIdleDuration(final long duration, final TimeUnit unit) {
+        if(duration > 0) {
+            this.duration = unit.toMillis(duration);
+        } else {
+            this.duration = -1;
+        }
+    }
+
+    @Override
+    public void releaseConnection() {
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                return;
+            }
+            this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
+            this.poolEntry = null;
+        }
+    }
+
+    @Override
+    public void abortConnection() {
+        synchronized (this) {
+            if (this.poolEntry == null) {
+                return;
+            }
+            this.reusable = false;
+            final OperatedClientConnection conn = this.poolEntry.getConnection();
+            try {
+                conn.shutdown();
+            } catch (final IOException ignore) {
+            }
+            this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
+            this.poolEntry = null;
+        }
+    }
+
+}

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/hc/ManagedClientConnectionImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain