You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ri...@apache.org on 2007/12/12 17:13:35 UTC
svn commit: r603657 - in /geronimo/sandbox/AsyncHttpClient/src:
main/java/org/apache/ahc/codec/SessionCache.java
test/java/org/apache/ahc/ConnectionReuseTest.java
Author: rickmcguire
Date: Wed Dec 12 08:13:35 2007
New Revision: 603657
URL: http://svn.apache.org/viewvc?rev=603657&view=rev
Log:
GERONIMO-3686 AsyncHttpClient does not reuse connection even if connections are persistent
Missed adding the new files to the repository.
Added:
geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java (with props)
geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java (with props)
Added: geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java?rev=603657&view=auto
==============================================================================
--- geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java (added)
+++ geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java Wed Dec 12 08:13:35 2007
@@ -0,0 +1,133 @@
+/*
+ * 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.ahc.codec;
+
+import java.net.InetSocketAddress;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.mina.common.IoSession;
+
+/**
+ * Class that provides access to cached sessions. IoSessions are cached using
+ * the host and the port. This class is thread safe.
+ */
+public final class SessionCache {
+ private static final SessionCache theInstance = new SessionCache();
+
+ private final ConcurrentMap<String,Queue<IoSession>> cachedSessions =
+ new ConcurrentHashMap<String,Queue<IoSession>>();
+
+ /**
+ * Returns a singleton instance of the session cache.
+ */
+ public static SessionCache getInstance() {
+ return theInstance;
+ }
+
+ private SessionCache() {}
+
+ /**
+ * Returns an IoSession that is connected and considered usable. Note that
+ * this is still on a best-effort basis, and there is no guarantee that the
+ * connection can be used without errors, although it should be usually
+ * safe to use it.
+ *
+ * @param msg the message for which to look up an active session.
+ * @throws IllegalArgumentException if a null request message was passed in.
+ * @return an active IoSession, or null if none are found.
+ */
+ public IoSession getActiveSession(HttpRequestMessage msg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("null request was passed in");
+ }
+
+ Queue<IoSession> queue = cachedSessions.get(getKey(msg));
+ if (queue == null) {
+ return null;
+ }
+
+ IoSession cached = null;
+ while ((cached = queue.poll()) != null) {
+ // see if the session is usable
+ if (cached.isConnected() && !cached.isClosing()) {
+ return cached;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Caches the given session using its remote host and port information.
+ *
+ * @param session IoSession to cache
+ * @throws IllegalArgumentException if a null session was passed in.
+ */
+ void cacheSession(IoSession session) {
+ if (session == null) {
+ throw new IllegalArgumentException("null session was passed in");
+ }
+
+ String key = getKey((InetSocketAddress)session.getRemoteAddress());
+ Queue<IoSession> newQueue = new ConcurrentLinkedQueue<IoSession>();
+ Queue<IoSession> queue = cachedSessions.putIfAbsent(key, newQueue);
+ if (queue == null) {
+ // the value was previously empty
+ queue = newQueue;
+ }
+ // add it to the queue
+ queue.offer(session);
+ }
+
+ /**
+ * Removes the given session from the cache if it is in the cache.
+ *
+ * @param session IoSession to remove from the cache
+ * @throws IllegalArgumentException if a null session was passed in
+ */
+ void removeSession(IoSession session) {
+ if (session == null) {
+ throw new IllegalArgumentException("null session was passed in");
+ }
+
+ String key = getKey((InetSocketAddress)session.getRemoteAddress());
+ Queue<IoSession> queue = cachedSessions.get(key);
+ if (queue != null) {
+ queue.remove(session);
+ }
+ }
+
+ private String getKey(HttpRequestMessage msg) {
+ return getKey(msg.getHost(), msg.getPort());
+ }
+
+ private String getKey(InetSocketAddress remote) {
+ return getKey(remote.getHostName(), remote.getPort());
+ }
+
+ /**
+ * The key is of the form "host:port".
+ */
+ private String getKey(String host, int port) {
+ return new StringBuilder(host).append(':').append(port).toString();
+ }
+}
Propchange: geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/AsyncHttpClient/src/main/java/org/apache/ahc/codec/SessionCache.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java?rev=603657&view=auto
==============================================================================
--- geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java (added)
+++ geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java Wed Dec 12 08:13:35 2007
@@ -0,0 +1,105 @@
+/*
+ * 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.ahc;
+
+import java.net.URL;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.ahc.codec.HttpRequestMessage;
+import org.apache.ahc.codec.HttpResponseMessage;
+
+public class ConnectionReuseTest extends AbstractTest {
+ // variable that keeps count of session close's
+ private final AtomicInteger closeCount = new AtomicInteger(0);
+
+ // It is important that this test case contains these methods in this order.
+ // It is because to test connection reuse we need to keep the embedded
+ // server running while connections are reused. However, AbstractTest
+ // starts and tears down the server around each test method.
+ public void testConnectionReuse() throws Exception {
+ // reset the count
+ closeCount.set(0);
+ Future<HttpResponseMessage> future =
+ submitRequest("http://localhost:8282/", true, new SessionCloseCounter());
+
+ HttpResponseMessage msg = future.get();
+ assertEquals("\nHello World!", msg.getStringContent());
+
+ // do another request for the same host
+ future = submitRequest("http://localhost:8282/params.jsp", true,
+ new SessionCloseCounter());
+
+ msg = future.get();
+ assertEquals("Test One Test Two", msg.getStringContent());
+
+ // check that I got zero close at this point
+ assertEquals(0, closeCount.get());
+ }
+
+ public void testConnectionClose() throws Exception {
+ // reset the count
+ closeCount.set(0);
+ Future<HttpResponseMessage> future =
+ submitRequest("http://localhost:8282/", false, new SessionCloseCounter());
+
+ HttpResponseMessage msg = future.get();
+ assertEquals("\nHello World!", msg.getStringContent());
+
+ // do another request for the same host
+ future = submitRequest("http://localhost:8282/params.jsp", false,
+ new SessionCloseCounter());
+
+ msg = future.get();
+ assertEquals("Test One Test Two", msg.getStringContent());
+
+ // give it a bit of time to catch up
+ Thread.sleep(500L);
+
+ // check that I got close count of 2 at this point
+ assertEquals(2, closeCount.get());
+ }
+
+ private Future<HttpResponseMessage> submitRequest(String url,
+ boolean reuseConnection,
+ AsyncHttpClientCallback cb)
+ throws Exception {
+ HttpRequestMessage request = new HttpRequestMessage(new URL(url), cb);
+
+ request.setParameter("TEST1", "Test One");
+ request.setParameter("TEST2", "Test Two");
+ AsyncHttpClient ahc = new AsyncHttpClient();
+ ahc.setReuseConnection(reuseConnection);
+ ahc.setTcpNoDelay(true);
+ return ahc.sendRequest(request);
+ }
+
+ private class SessionCloseCounter implements AsyncHttpClientCallback {
+ public void onClosed() {
+ System.out.println("onClosed()");
+ // increment the counter on every close
+ closeCount.incrementAndGet();
+ }
+
+ public void onException(Throwable cause) {}
+ public void onResponse(HttpResponseMessage message) {}
+ public void onTimeout() {}
+ }
+}
Propchange: geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/AsyncHttpClient/src/test/java/org/apache/ahc/ConnectionReuseTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain