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 2008/02/01 19:26:44 UTC
svn commit: r617593 [1/2] - in /geronimo/sandbox/async-http-client-mina2: ./
src/main/java/org/apache/ahc/ src/main/java/org/apache/ahc/auth/
src/main/java/org/apache/ahc/codec/ src/main/java/org/apache/ahc/proxy/
src/main/java/org/apache/ahc/util/ src...
Author: rickmcguire
Date: Fri Feb 1 10:26:11 2008
New Revision: 617593
URL: http://svn.apache.org/viewvc?rev=617593&view=rev
Log:
GERONIMO-3801 Merge Mina 1.1.5 AsyncHttpClient into Mina 2.0 based version.
Added:
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java (with props)
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java (with props)
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/MonitoringTest.java (with props)
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/ProxyTest.java (with props)
Modified:
geronimo/sandbox/async-http-client-mina2/pom.xml
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/AsyncHttpClient.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/auth/AuthChallengeParser.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpIoHandler.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestEncoder.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestMessage.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/ResponseFuture.java
geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/SessionCache.java
geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/index.jsp
geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/timeout.jsp
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/AsyncHttpClientTest.java
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/AsyncHttpClientWithFutureTest.java
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/AuthTest.java
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/ConnectionReuseTest.java
geronimo/sandbox/async-http-client-mina2/src/test/java/org/apache/ahc/RetryTest.java
Modified: geronimo/sandbox/async-http-client-mina2/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/pom.xml?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/pom.xml (original)
+++ geronimo/sandbox/async-http-client-mina2/pom.xml Fri Feb 1 10:26:11 2008
@@ -125,6 +125,10 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>pertest</forkMode>
+ <excludes>
+ <exclude>**/ProxyTest.java</exclude>
+ <exclude>**/AbstractTest.java</exclude>
+ </excludes>
</configuration>
</plugin>
<plugin>
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/AsyncHttpClient.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/AsyncHttpClient.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/AsyncHttpClient.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/AsyncHttpClient.java Fri Feb 1 10:26:11 2008
@@ -20,6 +20,9 @@
package org.apache.ahc;
import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
@@ -33,8 +36,12 @@
import org.apache.ahc.codec.HttpRequestMessage;
import org.apache.ahc.codec.ResponseFuture;
import org.apache.ahc.codec.SessionCache;
+import org.apache.ahc.proxy.ProxyFilter;
import org.apache.ahc.ssl.TrustManagerFactoryImpl;
import org.apache.ahc.util.AsyncHttpClientException;
+import org.apache.ahc.util.EventDispatcher;
+import org.apache.ahc.util.MonitoringEvent;
+import org.apache.ahc.util.MonitoringListener;
import org.apache.mina.common.*;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
@@ -52,9 +59,6 @@
*/
public class AsyncHttpClient {
- /** The Constant DEFAULT_REUSE_CONNECTION. */
- public static final boolean DEFAULT_REUSE_CONNECTION = false;
-
/** The Constant DEFAULT_CONNECTION_TIMEOUT. */
public static final int DEFAULT_CONNECTION_TIMEOUT = 30000;
@@ -110,9 +114,9 @@
/** The HttpIoHandler handler. */
private final HttpIoHandler handler;
- /** connection reuse option */
- private volatile boolean reuseConnection = DEFAULT_REUSE_CONNECTION;
-
+ /** The cache for session reuse */
+ private SessionCache sessionCache;
+
/** The Reuse Address Socket Parameter. */
private boolean reuseAddress = DEFAULT_REUSE_ADDRESS;
@@ -140,24 +144,14 @@
/** flag to make this as having been disposed of */
private boolean destroyed = false;
- /**
- * Returns if it reuses established connections for more requests.
- *
- * @return true if it reuses connections
- */
- public boolean isReuseConnection() {
- return reuseConnection;
- }
-
- /**
- * Sets if it should reuse established connections for more requests.
- *
- * @param reuseConnection the new value
- */
- public void setReuseConnection(boolean reuseConnection) {
- this.reuseConnection = reuseConnection;
- }
+ /** a dispatcher for dispatching monitoring events */
+ private EventDispatcher eventDispatcher;
+ public static final String SSL_FILTER = "SSL";
+ public static final String PROTOCOL_FILTER = "protocolFilter";
+ public static final String PROXY_FILTER = "proxyFilter";
+ public static final String EVENT_THREAD_POOL_FILTER = "eventThreadPoolFilter";
+
/**
* Checks if is reuse address.
*
@@ -373,25 +367,48 @@
threadPool = executor;
- if (scheduler == null)
+ if (scheduler == null) {
handler = new HttpIoHandler();
- else
+ }
+ else {
handler = new HttpIoHandler(scheduler);
+ }
- if (threadPool == null)
+ if (threadPool == null) {
connector = new NioSocketConnector();
- else{
- // connector = new NioSocketConnector((Runtime.getRuntime().availableProcessors(), threadPool);
+ }
+ else {
connector = new NioSocketConnector(threadPool, new SimpleIoProcessorPool(NioProcessor.class));
}
-
connector.setHandler(handler);
-
applyConnectionTimeout();
-// connector.setWorkerTimeout(1);
-
}
+
+ /**
+ * Set the session cache that should be used for
+ * connection reuse.
+ *
+ * @param cache The new session cache. If null, this will disable
+ * future connection reuse.
+ */
+ public void setSessionCache(SessionCache cache) {
+ sessionCache = cache;
+ // our I/O Handler instance needs to be fitted with the same
+ // cache
+ handler.setSessionCache(cache);
+ }
+
+ /**
+ * Retrieve the session cache used for storing
+ * connections for reuse.
+ *
+ * @return The current session cache for the client.
+ */
+ public SessionCache getSessionCache() {
+ return sessionCache;
+ }
+
/**
* Sends a request. The call is non-blocking, and returns a future object
* with which the caller can synchronize on the completion of the request.
@@ -431,6 +448,11 @@
throw new IllegalStateException("AsyncHttpClient has been destroyed and cannot be reused.");
}
+ // set the request start time
+ message.setRequestStartTime();
+ // notify any interesting parties that this is starting
+ notifyMonitoringListeners(MonitoringEvent.REQUEST_STARTED, message);
+
// we need to provide a new result future and associate it with the
// request unless it already exists (i.e. sendRequest() is called
// multiple times for the request)
@@ -441,20 +463,33 @@
// *IF* connection reuse is enabled, we should see if we have a cached
// connection first; if not, always open a new one
ConnectFuture future = null;
- if (reuseConnection) {
+ if (!message.isProxyEnabled()) {
+ SessionCache cache = getSessionCache();
+ if (cache != null) {
future = getCachedConnection(message);
} else {
// add the Connection close header explicitly
message.setHeader(HttpDecoder.CONNECTION, HttpDecoder.CLOSE);
}
+ }
// if no cached connection is found or keep-alive is disabled, force a
// new connection
if (future == null) {
+ // set the connect start time
+ message.setConnectStartTime();
+ // NB: We broadcast this here rather than in open connection to avoid
+ // having a connection retry result in both a CONNECTION_ATTEMPTED and
+ // CONNECTION_RETRIED event getting dispatched.
+ notifyMonitoringListeners(MonitoringEvent.CONNECTION_ATTEMPTED, message);
future = openConnection(message);
}
ResponseFuture response = message.getResponseFuture();
- future.addListener(new FutureListener(message, response, connectionRetries));
+ FutureListener listener =
+ message.isProxyEnabled() ?
+ new ProxyFutureListener(message, response) :
+ new FutureListener(message, response);
+ future.addListener(listener);
return response;
}
@@ -468,21 +503,49 @@
* attempt. This should be one less than the count
* used for the previous attempt.
*/
- private void retryConnection(HttpRequestMessage message, ResponseFuture response, int retries) {
+ private void retryConnection(HttpRequestMessage message, ResponseFuture response, FutureListener listener) {
+ // set the connect start time again
+ message.setConnectStartTime();
+ notifyMonitoringListeners(MonitoringEvent.CONNECTION_RETRIED, message);
ConnectFuture future = openConnection(message);
- future.addListener(new FutureListener(message, response, retries));
+ future.addListener(listener);
}
+ /**
+ * Open the appropriate connection for this message.
+ * This will either open a direct connection or connect
+ * to the configured proxy server.
+ *
+ * @param message The message getting sent. This defines the target
+ * location and also holds the proxy configuration.
+ *
+ * @return A ConnectFuture instance for managing the connection.
+ */
private ConnectFuture openConnection(HttpRequestMessage message) {
- return connector.connect((new InetSocketAddress(message.getHost(), message.getPort())));
+ InetSocketAddress remote =
+ message.isProxyEnabled() ?
+ message.getProxyConfiguration().getProxyAddress(message.getUrl()) :
+ new InetSocketAddress(message.getHost(), message.getPort());
+ return connector.connect(remote);
}
+ /**
+ * Attempt to get a connection from the session cache.
+ *
+ * @param message The message we're sending.
+ *
+ * @return A cached connection. This returns null if there's
+ * no available connection for the target location.
+ */
private ConnectFuture getCachedConnection(HttpRequestMessage message) {
- IoSession cached = SessionCache.getInstance().getActiveSession(message);
+ IoSession cached = sessionCache.getActiveSession(message);
if (cached == null) {
return null;
}
+ // clear the connect start time to prevent misreporting
+ message.clearConnectStartTime();
+ notifyMonitoringListeners(MonitoringEvent.CONNECTION_REUSED, message);
// create a containing future object and set the session right away
ConnectFuture future = new DefaultConnectFuture();
future.setSession(cached);
@@ -534,23 +597,61 @@
}
/**
+ * Add a statistics listener to this client object.
+ *
+ * @param listener The listener to add.
+ */
+ public void addMonitoringListener(MonitoringListener listener) {
+ synchronized (this) {
+ // we've deferred creation until we have someone listening
+ if (eventDispatcher == null) {
+ eventDispatcher = new EventDispatcher();
+ }
+ }
+ eventDispatcher.addListener(listener);
+ }
+
+ /**
+ * Remove a listener from the client.
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeMonitoringListener(MonitoringListener listener) {
+ if (eventDispatcher != null) {
+ eventDispatcher.removeListener(listener);
+ }
+ }
+
+ /**
+ * Send a notification event to any monitoring listeners.
+ *
+ * @param type The type of event.
+ * @param request The HttpRequestMessage that triggerd the event.
+ */
+ public void notifyMonitoringListeners(int type, HttpRequestMessage request) {
+ // if there's no event dispatcher, no point in dispatching this
+ if (eventDispatcher == null) {
+ return;
+ }
+
+ MonitoringEvent event = new MonitoringEvent(type, request);
+ eventDispatcher.dispatchEvent(event);
+ }
+
+ /**
* The listener interface for receiving connection events. Its main purpose is to notify the
* callback of any exceptions that may have occurred, or to handle the session and inject
* the proper SSL filter if the connection is to be used for <code>https</code>. If a good
* connection occurs, it is also responsible for sending the request.
*/
class FutureListener implements IoFutureListener {
- static final String SSL_FILTER = "SSL";
- static final String PROTOCOL_FILTER = "protocolFilter";
- static final String EVENT_THREAD_POOL_FILTER = "eventThreadPoolFilter";
-
/** The request. */
final HttpRequestMessage request;
/** The response future. */
final ResponseFuture response;
/** The count of additional retries for the connection */
- int retries = 0;
+ volatile int retries = getConnectionRetries();
/**
* Instantiates a new future listener for a connection.
@@ -558,10 +659,9 @@
* @param request the <code>HttpRequestMessage</code> request that is to be sent.
* @param response the response future object.
*/
- public FutureListener(HttpRequestMessage request, ResponseFuture response, int retries) {
+ public FutureListener(HttpRequestMessage request, ResponseFuture response) {
this.request = request;
this.response = response;
- this.retries = retries;
}
/**
@@ -574,24 +674,48 @@
public void operationComplete(IoFuture future) {
ConnectFuture connFuture = (ConnectFuture) future;
if (connFuture.isConnected()) {
+ notifyMonitoringListeners(MonitoringEvent.CONNECTION_SUCCESSFUL, request);
IoSession sess = future.getSession();
// see if we need to add the SSL filter
addSSLFilter(sess);
// add the protocol filter (if it's not there already like in a
// reused session)
- if (!sess.getFilterChain().contains(PROTOCOL_FILTER)) {
- sess.getFilterChain().addLast(PROTOCOL_FILTER, new ProtocolCodecFilter(
- new HttpProtocolCodecFactory()));
- }
+ addProtocolCodecFilter(sess);
// (optional) add the executor filter for the event thread pool
// (if it's not there already like in a reused session)
- if (eventThreadPool != null &&
- !sess.getFilterChain().contains(EVENT_THREAD_POOL_FILTER)) {
- sess.getFilterChain().addLast(EVENT_THREAD_POOL_FILTER,
- new ExecutorFilter(eventThreadPool));
+ addEventThreadPoolFilter(sess);
+ // now that we're connection, configure the session appropriately.
+ configureSession(sess);
+ // and finally start the request process rolling.
+ sess.write(request);
+ }
+ else {
+ if (retries-- > 0) {
+ // go retry this connection
+ retryConnection(request, response, this);
}
-
+ else {
+ try {
+ notifyMonitoringListeners(MonitoringEvent.CONNECTION_FAILED, request);
+ future.getSession();
+ response.setException(new AsyncHttpClientException("Connection failed."));
+ } catch (RuntimeIoException e) {
+ //Set the future exception
+ response.setException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Configure the IoSession with the client connection
+ * parameters.
+ *
+ * @param sess The session to which the configuration values are to
+ * be applied.
+ */
+ protected void configureSession(IoSession sess) {
sess.setAttribute(HttpIoHandler.CURRENT_REQUEST, request);
sess.setAttachment(AsyncHttpClient.this);
@@ -606,25 +730,44 @@
config.setSoLinger(soLinger);
config.setTcpNoDelay(tcpNoDelay);
config.setTrafficClass(trafficClass);
+ }
- sess.write(request);
- } else {
- if (retries > 0) {
- // go retry this connection
- retryConnection(request, response, --retries);
- }
- else {
- try {
- future.getSession();
- response.setException(new AsyncHttpClientException("Connection failed."));
- } catch (RuntimeIoException e) {
- //Set the future exception
- response.setException(e);
- }
- }
+ /**
+ * Add the ExecutorFilter to the session filter chain.
+ * The ExecutorFilter allows session callbacks to be
+ * dispatched using a different thread pool than the one
+ * used for the I/O threads.
+ *
+ * @param sess The session to configure.
+ */
+ protected void addEventThreadPoolFilter(IoSession sess) {
+ if (eventThreadPool != null &&
+ !sess.getFilterChain().contains(EVENT_THREAD_POOL_FILTER)) {
+ sess.getFilterChain().addLast(EVENT_THREAD_POOL_FILTER,
+ new ExecutorFilter(eventThreadPool));
}
}
+ /**
+ * Add the HttpProtocol filter to the session processing
+ * chain. The protocol filter handles the returned
+ * response information.
+ *
+ * @param sess The target session.
+ */
+ protected void addProtocolCodecFilter(IoSession sess) {
+ if (!sess.getFilterChain().contains(PROTOCOL_FILTER)) {
+ sess.getFilterChain().addLast(PROTOCOL_FILTER, new ProtocolCodecFilter(
+ new HttpProtocolCodecFactory()));
+ }
+ }
+
+ /**
+ * Add an SSL filter to the io session when the
+ * connection type is "https".
+ *
+ * @param sess The session to configure.
+ */
private void addSSLFilter(IoSession sess) {
String scheme = request.getUrl().getProtocol();
@@ -634,14 +777,7 @@
// session
if (!sess.getFilterChain().contains(SSL_FILTER)) {
try {
- SSLContext context = request.getSSLContext();
- if (context == null) {
- // if the caller did not provide an SSL context
- // create a default SSL context
- context = createDefaultSSLContext();
- }
- SslFilter sslFilter = new SslFilter(context);
- sslFilter.setUseClientMode(true);
+ SslFilter sslFilter = createSSLFilter();
sess.getFilterChain().addLast(SSL_FILTER, sslFilter);
} catch (GeneralSecurityException e) {
try {
@@ -655,6 +791,27 @@
}
/**
+ * Create an SslFilter instance for this client. The
+ * filter will be configured using any SSL context defined
+ * for the request, or a default context if one has not
+ * been explicitly configured.
+ *
+ * @return An appropriately configured SSLFilter for this connection.
+ * @exception GeneralSecurityException
+ */
+ protected SslFilter createSSLFilter() throws GeneralSecurityException {
+ SSLContext context = request.getSSLContext();
+ if (context == null) {
+ // if the caller did not provide an SSL context
+ // create a default SSL context
+ context = createDefaultSSLContext();
+ }
+ SslFilter sslFilter = new SslFilter(context);
+ sslFilter.setUseClientMode(true);
+ return sslFilter;
+ }
+
+ /**
* Creates a default SSL context in case it was not provided by the
* caller.
*
@@ -666,6 +823,103 @@
context.init(null, TrustManagerFactoryImpl.X509_MANAGERS, null);
return context;
}
+ }
+
+ /**
+ * A FutureListener for managing connections used with
+ * proxied connections. This Future manages establishing
+ * the appropriate connection type with the proxy before
+ * handling the actual client request.
+ */
+ class ProxyFutureListener extends FutureListener {
+ public ProxyFutureListener(HttpRequestMessage request,
+ ResponseFuture response) {
+ super(request, response);
+ }
+ @Override
+ /**
+ * Handle operation completion events. This is primarly
+ * to handle the tunneling protocol required by
+ * https requests through a proxy server.
+ *
+ * @param future The Future object associated with the operation.
+ */
+ public void operationComplete(IoFuture future) {
+ ConnectFuture connectFuture = (ConnectFuture)future;
+ if (connectFuture.isConnected()) {
+ IoSession session = future.getSession();
+ // add the protocol filter (if it's not there already like in a
+ // reused session)
+ addProtocolCodecFilter(session);
+ addProxyFilter(session);
+ // (optional) add the executor filter for the event thread pool
+ // (if it's not there already like in a reused session)
+ addEventThreadPoolFilter(session);
+
+ configureSession(session);
+
+ // write the connect request if the protocol is https
+ String protocol = request.getUrl().getProtocol();
+ if (protocol.toLowerCase().equals("https")) {
+ session.write(createConnectRequest());
+ } else {
+ session.write(request);
+ }
+ } else {
+ super.operationComplete(future);
+ }
+ }
+
+ /**
+ * Compose the connection request used for SSL proxy
+ * tunneling connections. This CONNECT request tells
+ * the proxy server to establish a connection with
+ * the remote target and tunnel it through to the
+ * client. Once the connection has been established,
+ * an SLL connection will be layered over the top
+ * of the connection, creating a secure channel between
+ * the client and the server.
+ *
+ * @return The request message to send back to the proxy for
+ * establishing the tunneled connection.
+ */
+ private HttpRequestMessage createConnectRequest() {
+ try {
+ HttpRequestMessage req = new HttpRequestMessage(new URL("http", request.getHost(), request.getPort(), ""), null);
+ req.setRequestMethod(HttpRequestMessage.REQUEST_CONNECT);
+ return req;
+ } catch (MalformedURLException e) {
+ // ignored, shouldn't happen
+ } catch (ProtocolException e) {
+ // ignored, shouldn't happen
+ }
+ // this can't happen
+ return null;
+ }
+
+ /**
+ * Add a proxy filter to the session filter chain.
+ * The proxy filter will be either a plain filter or a
+ * tunneling SSL filter.
+ *
+ * @param session
+ */
+ private void addProxyFilter(IoSession session) {
+ if (!session.getFilterChain().contains(PROXY_FILTER)) {
+ String scheme = request.getUrl().getProtocol();
+ ProxyFilter proxyFilter = null;
+ if (scheme.toLowerCase().equals("https")) {
+ try {
+ proxyFilter = new ProxyFilter(createSSLFilter());
+ } catch (GeneralSecurityException e) {
+ // this normally cannot happen
+ }
+ } else {
+ proxyFilter = new ProxyFilter();
+ }
+ session.getFilterChain().addLast(PROXY_FILTER, proxyFilter);
+ }
+ }
}
}
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/auth/AuthChallengeParser.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/auth/AuthChallengeParser.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/auth/AuthChallengeParser.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/auth/AuthChallengeParser.java Fri Feb 1 10:26:11 2008
@@ -86,28 +86,4 @@
}
return map;
}
-
- /**
- * Extracts a map of challenges ordered by authentication scheme name
- *
- * @param headers the array of authorization challenges
- * @return a map of authorization challenges
- *
- * @throws MalformedChallengeException if any of challenge strings
- * is malformed
- */
-// public static Map parseChallenges(final Header[] headers)
-// throws MalformedChallengeException {
-// if (headers == null) {
-// throw new IllegalArgumentException("Array of challenges may not be null");
-// }
-// String challenge = null;
-// Map challengemap = new HashMap(headers.length);
-// for (int i = 0; i < headers.length; i++) {
-// challenge = headers[i].getValue();
-// String s = AuthChallengeParser.extractScheme(challenge);
-// challengemap.put(s, challenge);
-// }
-// return challengemap;
-// }
}
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpIoHandler.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpIoHandler.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpIoHandler.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpIoHandler.java Fri Feb 1 10:26:11 2008
@@ -33,6 +33,7 @@
import org.apache.ahc.auth.AuthScheme;
import org.apache.ahc.auth.AuthState;
import org.apache.ahc.util.NameValuePair;
+import org.apache.ahc.util.MonitoringEvent;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
@@ -64,6 +65,11 @@
private final ScheduledExecutorService scheduler;
/**
+ * The session cache used for reusable connections
+ */
+ private SessionCache sessionCache;
+
+ /**
* Instantiates a new HttpIoHandler with a new a single-threaded executor.
*/
public HttpIoHandler() {
@@ -80,6 +86,27 @@
}
/**
+ * Set the session cache that should be used for
+ * connection reuse.
+ *
+ * @param cache The new session cache. If null, this will disable
+ * future connection reuse.
+ */
+ public void setSessionCache(SessionCache cache) {
+ sessionCache = cache;
+ }
+
+ /**
+ * Retrieve the session cache used for storing
+ * connections for reuse.
+ *
+ * @return The current session cache for the client.
+ */
+ public SessionCache getSessionCache() {
+ return sessionCache;
+ }
+
+ /**
* Destroys the handler and shuts down the scheduler.
*/
public void destroy() {
@@ -108,14 +135,17 @@
HttpRequestMessage request = (HttpRequestMessage) ioSession.getAttribute(CURRENT_REQUEST);
+ AsyncHttpClient client = (AsyncHttpClient) ioSession.getAttachment();
+
//Check if we are to handle redirects
if ((response.getStatusCode() == 301
|| response.getStatusCode() == 302
|| response.getStatusCode() == 307)
&& request.isFollowRedirects())
{
- AsyncHttpClient client = (AsyncHttpClient) ioSession.getAttachment();
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.REQUEST_REDIRECTED, request);
//Change the request url to the redirect
request.setUrl(new URL(response.getLocation()));
// if we're redirected via 30x, the request method should be reset to GET
@@ -128,13 +158,20 @@
//Send the redirect
client.sendRequest(request);
+ // if we've been provided with a cache, put this session into
+ // the cache.
+ SessionCache cache = getSessionCache();
+ if (cache != null) {
// cache the session before we return
- SessionCache.getInstance().cacheSession(ioSession);
+ cache.cacheSession(ioSession);
+ }
return;
}
//Check if we have authentication
if (response.getChallenges().size() > 0) {
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.REQUEST_CHALLENGED, request);
for (NameValuePair nvp : response.getChallenges()) {
AuthState state = request.getAuthState();
if (state == null) {
@@ -147,28 +184,39 @@
}
}
- AsyncHttpClient client = (AsyncHttpClient) ioSession.getAttachment();
-
//Authenticate
int authCount = request.getAuthCount() + 1;
if (authCount <= 3) {
+ // if we've been provided with a cache, put this session into
+ // the cache.
+ SessionCache cache = getSessionCache();
+ if (cache != null) {
+ // cache the session before we return
+ cache.cacheSession(ioSession);
+ }
+
request.setAuthCount(authCount);
client.sendRequest(request);
- // cache the session before we return
- SessionCache.getInstance().cacheSession(ioSession);
return;
}
}
cancelTasks(request);
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.REQUEST_COMPLETED, request);
// complete the future which will also fire the callback
ResponseFuture result = request.getResponseFuture();
result.set(response);
+ // if we've been provided with a cache, put this session into
+ // the cache.
+ SessionCache cache = getSessionCache();
+ if (cache != null) {
// cache the session before we return
- SessionCache.getInstance().cacheSession(ioSession);
+ cache.cacheSession(ioSession);
+ }
}
/**
@@ -185,6 +233,10 @@
HttpRequestMessage request = (HttpRequestMessage) ioSession.getAttribute(CURRENT_REQUEST);
cancelTasks(request);
+ AsyncHttpClient client = (AsyncHttpClient) ioSession.getAttachment();
+
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.REQUEST_FAILED, request);
// complete the future which will also fire the callback
ResponseFuture result = request.getResponseFuture();
result.setException(throwable);
@@ -202,10 +254,20 @@
public void sessionClosed(IoSession ioSession) throws Exception {
//Clean up if any in-proccess decoding was occurring
ioSession.removeAttribute(CURRENT_RESPONSE);
- // remove it from the cache
- SessionCache.getInstance().removeSession(ioSession);
+
+ // if we've been provided with a cache, remove this session from
+ // the cache.
+ SessionCache cache = getSessionCache();
+ if (cache != null) {
+ // cache the session before we return
+ cache.removeSession(ioSession);
+ }
HttpRequestMessage request = (HttpRequestMessage) ioSession.getAttribute(CURRENT_REQUEST);
cancelTasks(request);
+ AsyncHttpClient client = (AsyncHttpClient) ioSession.getAttachment();
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.CONNECTION_CLOSED_BY_SERVER, request);
+
AsyncHttpClientCallback callback = request.getCallback();
if (callback != null) {
callback.onClosed();
@@ -276,6 +338,12 @@
public void run() {
// complete the future which will also fire the callback
HttpRequestMessage request = (HttpRequestMessage)sess.getAttribute(CURRENT_REQUEST);
+
+ AsyncHttpClient client = (AsyncHttpClient) sess.getAttachment();
+
+ // notify any interesting parties that this is starting
+ client.notifyMonitoringListeners(MonitoringEvent.REQUEST_TIMEOUT, request);
+
ResponseFuture result = request.getResponseFuture();
result.setException(new TimeoutException());
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestEncoder.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestEncoder.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestEncoder.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestEncoder.java Fri Feb 1 10:26:11 2008
@@ -106,16 +106,26 @@
CharsetEncoder encoder = Charset.forName(HttpMessage.HTTP_ELEMENT_CHARSET).newEncoder();
buf.putString(msg.getRequestMethod(), encoder);
buf.putString(" ", encoder);
- buf.putString(msg.getPath(), encoder);
+ if (msg.getRequestMethod().equals(HttpRequestMessage.REQUEST_CONNECT)) {
+ buf.putString(msg.getHost(), encoder);
+ buf.putString(":", encoder);
+ buf.putString(msg.getPort() + "", encoder);
+ } else {
+ if (msg.isProxyEnabled() && !msg.getProtocol().toLowerCase().equals("https")) {
+ buf.putString(msg.getUrl().toString(), encoder);
+ } else {
+ buf.putString(msg.getUrl().getFile(), encoder);
+ }
//If its a GET, append the attributes
if (msg.getRequestMethod().equals(HttpRequestMessage.REQUEST_GET) && attrCount > 0) {
//If there is not already a ? in the query, append one, otherwise append a &
- if (!msg.getPath().contains("?")) {
+ if (!msg.getUrl().getFile().contains("?")) {
buf.putString("?", encoder);
} else {
buf.putString("&", encoder);
}
buf.putString(urlAttrs, encoder);
+ }
}
buf.putString(" HTTP/1.1", encoder);
buf.put(CRLF);
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestMessage.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestMessage.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestMessage.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/HttpRequestMessage.java Fri Feb 1 10:26:11 2008
@@ -32,6 +32,7 @@
import org.apache.ahc.auth.AuthScope;
import org.apache.ahc.auth.AuthState;
import org.apache.ahc.auth.Credentials;
+import org.apache.ahc.proxy.ProxyConfiguration;
/**
* The Class HttpRequestMessage. This is an object representation of an HTTP request.
@@ -83,6 +84,8 @@
*/
public static final String REQUEST_TRACE = "TRACE";
+ public static final String REQUEST_CONNECT = "CONNECT";
+
/**
* The request method.
*/
@@ -154,6 +157,12 @@
*/
private SSLContext sslContext;
+ private ProxyConfiguration proxyConfig;
+
+ private volatile long requestStartTime = 0L;
+
+ private volatile long connectStartTime = 0L;
+
/**
* Instantiates a new http request message.
*
@@ -249,7 +258,8 @@
|| requestMethod.equals(REQUEST_OPTIONS)
|| requestMethod.equals(REQUEST_PUT)
|| requestMethod.equals(REQUEST_DELETE)
- || requestMethod.equals(REQUEST_TRACE)) {
+ || requestMethod.equals(REQUEST_TRACE)
+ || requestMethod.equals(REQUEST_CONNECT)) {
this.requestMethod = requestMethod;
return;
}
@@ -538,5 +548,88 @@
*/
public void setSSLContext(SSLContext sslContext) {
this.sslContext = sslContext;
+ }
+
+ /**
+ * Get the message proxy configuration. This controls
+ * how downstream filters handle the message connections.
+ *
+ * @return The current proxy configuration. Returns null if
+ * no proxying support is configured.
+ */
+ public ProxyConfiguration getProxyConfiguration() {
+ return proxyConfig;
+ }
+
+ /**
+ * Set the proxy configuration use to control proxied
+ * connections.
+ *
+ * @param config The new proxy configuration.
+ */
+ public void setProxyConfiguration(ProxyConfiguration config) {
+ proxyConfig = config;
+ }
+
+ /**
+ * Test if this request needs to go through a proxy
+ * server. To be proxied, there must be a proxy configuration
+ * set and the request target must not be specified in
+ * the proxy exclusion list.
+ *
+ * @return true if this request must go through a proxy server,
+ * false if a direct connection can be used.
+ */
+ public boolean isProxyEnabled() {
+ return proxyConfig != null && !proxyConfig.isExcluded(getUrl());
+ }
+
+ /**
+ * Return the time when the request was first initiated.
+ *
+ * @return The time, in milliseconds, for when request processing
+ * was initiated.
+ */
+ public long getRequestStartTime() {
+ return requestStartTime;
+ }
+
+ /**
+ * Mark the start of request processing.
+ */
+ public void setRequestStartTime() {
+ requestStartTime = System.nanoTime()/1000000;
+ }
+
+ /**
+ * Clear the request starting time back to zero.
+ */
+ public void clearRequestStartTime() {
+ requestStartTime = 0L;
+ }
+
+ /**
+ * Get the time stamp for when the connection request was
+ * started.
+ *
+ * @return The timestamp (in milliseconds) for when the connection
+ * for this message request was initiated.
+ */
+ public long getConnectStartTime() {
+ return connectStartTime;
+ }
+
+ /**
+ * Set the timestamp for connection initiation.
+ */
+ public void setConnectStartTime() {
+ connectStartTime = System.nanoTime()/1000000;
+ }
+
+ /**
+ * Reset the connection start time.
+ */
+ public void clearConnectStartTime() {
+ connectStartTime = 0L;
}
}
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/ResponseFuture.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/ResponseFuture.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/ResponseFuture.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/ResponseFuture.java Fri Feb 1 10:26:11 2008
@@ -91,11 +91,16 @@
*/
@Override
public void set(HttpResponseMessage v) {
- super.set(v);
- // fire the callback once the future is done
+ try {
+ // fire the callback before completing the future to
+ // ensure everything gets handled before the future gets
+ // completed.
if (callback != null) {
callback.onResponse(v);
}
+ } finally {
+ super.set(v);
+ }
}
/**
@@ -107,14 +112,19 @@
*/
@Override
public void setException(Throwable t) {
- super.setException(t);
- // fire the callback once the future is done
+ try {
+ // fire the callback before completing the future to
+ // ensure everything gets handled before the future gets
+ // completed.
if (callback != null) {
if (t instanceof TimeoutException) {
callback.onTimeout();
} else {
callback.onException(t);
}
+ }
+ } finally {
+ super.setException(t);
}
}
Modified: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/SessionCache.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/SessionCache.java?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/SessionCache.java (original)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/codec/SessionCache.java Fri Feb 1 10:26:11 2008
@@ -32,19 +32,10 @@
* 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() {}
+ public SessionCache() {}
/**
* Returns an IoSession that is connected and considered usable. Note that
@@ -116,10 +107,24 @@
}
}
+ /**
+ * Generate a request key from an HTTP request message.
+ *
+ * @param msg The request message we need a key from.
+ *
+ * @return A String key instance for this request.
+ */
private String getKey(HttpRequestMessage msg) {
return getKey(msg.getHost(), msg.getPort());
}
+ /**
+ * Generate a session key from an InetSocketAddress
+ *
+ * @param remote The endpoint address of the connection.
+ *
+ * @return A string key for this endpoint.
+ */
private String getKey(InetSocketAddress remote) {
return getKey(remote.getHostName(), remote.getPort());
}
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,252 @@
+package org.apache.ahc.proxy;
+
+import java.net.InetSocketAddress;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.ahc.auth.AuthScheme;
+
+public class ProxyConfiguration {
+ private final String httpProxyHost;
+ private final int httpProxyPort;
+ private final String httpsProxyHost;
+ private final int httpsProxyPort;
+ private String exclusionList = null;
+ private String proxyUser = null;
+ private String proxyPassword = null;
+ private AuthScheme scheme = null;
+ private List<String> wildCardExclusions = new ArrayList<String>();
+ private Map<String,String> directExclusions = new HashMap<String,String>();
+
+ /**
+ * Construct a ProxyConfiguration instance.
+ *
+ * @param proxyHost The host to be used for both http and https connections.
+ * @param proxyPort The port to be used for both http and https connections.
+ */
+ public ProxyConfiguration(String proxyHost, int proxyPort) {
+ this.httpProxyHost = proxyHost;
+ this.httpProxyPort = proxyPort;
+ this.httpsProxyHost = proxyHost;
+ this.httpsProxyPort = proxyPort;
+ }
+
+ /**
+ * Construct a proxy configuration that uses separate
+ * http and https proxy targets.
+ *
+ * @param httpProxyHost
+ * The host to be used for http requests.
+ * @param httpProxyPort
+ * The port to be used for http requests.
+ * @param httpsProxyHost
+ * The host to use for https requests.
+ * @param httpsProxyPort
+ */
+ public ProxyConfiguration(String httpProxyHost, int httpProxyPort, String httpsProxyHost, int httpsProxyPort) {
+ this.httpProxyHost = httpProxyHost;
+ this.httpProxyPort = httpProxyPort;
+ this.httpsProxyHost = httpsProxyHost;
+ this.httpsProxyPort = httpsProxyPort;
+ }
+
+
+ /**
+ * Get the target connection for a proxied request.
+ * The target will depend on whether this is an http
+ * or an https request.
+ *
+ * @param target The target URL
+ *
+ * @return An InetSocketAddress for the appropriate proxy target.
+ */
+ public InetSocketAddress getProxyAddress(URL target)
+ {
+ if (target.getProtocol().equalsIgnoreCase("https")) {
+ return new InetSocketAddress(getHttpsProxyHost(), getHttpsProxyPort());
+ }
+ else {
+ return new InetSocketAddress(getHttpProxyHost(), getHttpProxyPort());
+ }
+ }
+
+ /**
+ * Get the proxy host name for http connections.
+ *
+ * @return The string name of the proxy host.
+ */
+ public String getHttpProxyHost() {
+ return httpProxyHost;
+ }
+
+ /**
+ * Get the port of the proxy server used for servicing
+ * http requests.
+ *
+ * @return The port number of the configured http proxy server.
+ */
+ public int getHttpProxyPort() {
+ return httpProxyPort;
+ }
+
+ /**
+ * Get the host of the proxy server for handling
+ * https requests. If not explicitly set this defaults
+ * to the http proxy host.
+ *
+ * @return The string name of the proxy host.
+ */
+ public String getHttpsProxyHost() {
+ return httpsProxyHost;
+ }
+
+ /**
+ * Get the port used to connect to the https proxy
+ * server. If not explictly set, this is the same as the
+ * http server.
+ *
+ * @return The connection port number for handling https requests.
+ */
+ public int getHttpsProxyPort() {
+ return httpsProxyPort;
+ }
+
+ /**
+ * Retrieve the exclusion list used for this configuration.
+ * If set, this returns a string containing the
+ * individual exclusion domains separated by ";".
+ *
+ * @return The string value of the exclusion list, or null
+ * if this has not been set.
+ */
+ public String getExclusionList() {
+ return exclusionList;
+ }
+
+ /**
+ * Set the exclusion list for the proxy configuration.
+ * The exclusion list is a set of explicit hosts and/or
+ * wildcard domains ("*.apache.org") separated by ";".
+ *
+ * @param exclusionList
+ */
+ public void setExclusionList(String exclusionList) {
+ this.exclusionList = exclusionList;
+ // we clear these out regardless
+ wildCardExclusions.clear();
+ directExclusions.clear();
+
+ if (exclusionList != null) {
+ // now divide the exclusion list into the explict and wildcard lists
+ StringTokenizer tokenizer = new StringTokenizer(exclusionList, ";");
+ while (tokenizer.hasMoreTokens()) {
+ String domain = tokenizer.nextToken();
+ // wild card versions we just create a matching list that we run through
+ if (domain.startsWith("*.")) {
+ wildCardExclusions.add(domain.substring(1));
+ }
+ else {
+ // the direct exlusions are names we can look up via a map.
+ directExclusions.put(domain, domain);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the proxy authentication userid.
+ *
+ * @return The name of the authentication userid. Returns null
+ * if no user has been specified.
+ */
+ public String getProxyUser() {
+ return proxyUser;
+ }
+
+ /**
+ * Set the userid used for proxy server authentication.
+ *
+ * @param proxyUser The userid to be used by the authentication schema.
+ */
+ public void setProxyUser(String proxyUser) {
+ this.proxyUser = proxyUser;
+ }
+
+ /**
+ * Returns the configured password used to access the
+ * proxy server.
+ *
+ * @return The configured password. Returns null if no password is
+ * set.
+ */
+ public String getProxyPassword() {
+ return proxyPassword;
+ }
+
+ /**
+ * Set the password to be used for accessing the
+ * proxy server.
+ *
+ * @param proxyPassword
+ * The password to be used for authentication.
+ */
+ public void setProxyPassword(String proxyPassword) {
+ this.proxyPassword = proxyPassword;
+ }
+
+ /**
+ * Returns the authentication scheme used for logging
+ * in the proxy server.
+ *
+ * @return The configured authentication scheme. Returns null
+ * if one has not been set.
+ */
+ public AuthScheme getAuthScheme() {
+ return scheme;
+ }
+
+ /**
+ * Set the authentication scheme to be used for logging
+ * in the proxy server.
+ *
+ * @param scheme The scheme to be used for logging in. If null,
+ * no login will be attempted with the proxy server.
+ */
+ public void setAuthScheme(AuthScheme scheme) {
+ this.scheme = scheme;
+ }
+
+ /**
+ * Tests if the host in a target URL is specified in
+ * the proxy configuration exclusion list.
+ *
+ * @param target The target URL of the connection.
+ *
+ * @return true if the host is included in the configuration
+ * exclusion list. false indicates the connection
+ * needs to go through the proxy server.
+ */
+ public boolean isExcluded(URL target) {
+ String host = target.getHost();
+
+ // if the host is explicitly listed, this is easy
+ if (directExclusions.get(host) != null) {
+ return true;
+ }
+ // the wildcard elements are stored as ".apache.org", so
+ // a simple endsWith() test will gives a match on something
+ // like "people.apache.org".
+ for (String domain : wildCardExclusions) {
+ if (host.endsWith(domain)) {
+ return true;
+ }
+ }
+ // not found in any host
+ return false;
+ }
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyConfiguration.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,143 @@
+package org.apache.ahc.proxy;
+
+import org.apache.ahc.AsyncHttpClient;
+import org.apache.ahc.auth.UsernamePasswordCredentials;
+import org.apache.ahc.codec.HttpIoHandler;
+import org.apache.ahc.codec.HttpRequestMessage;
+import org.apache.ahc.codec.HttpResponseMessage;
+import org.apache.mina.common.IoFilterAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.WriteRequest;
+import org.apache.mina.filter.ssl.SslFilter;
+
+public class ProxyFilter extends IoFilterAdapter {
+ public static final String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
+
+ private volatile boolean connectHandshakeComplete;
+ private final SslFilter sslFilter;
+
+ /**
+ * Create a proxy filter for a plain (http request)
+ * to a proxy server.
+ */
+ public ProxyFilter() {
+ this(null);
+ }
+
+ /**
+ * Create a proxy filter that works in conjunction with
+ * an SslFilter for a secure connection.
+ *
+ * @param sslFilter The SSL filter to use for the secure connection. If
+ * null, a plain connection will be used.
+ */
+ public ProxyFilter(SslFilter sslFilter) {
+ this.sslFilter = sslFilter;
+ }
+
+ @Override
+ /**
+ * Process a message send event to the proxy. This
+ * will add any required proxy authentication headers
+ * to the request.
+ *
+ * @param nextFilter
+ * @param session
+ * @param message
+ *
+ * @exception Exception
+ */
+ public void messageSent(NextFilter nextFilter, IoSession session,
+ WriteRequest message) throws Exception {
+ HttpRequestMessage request = (HttpRequestMessage)message.getMessage();
+ ProxyConfiguration proxyConfig = request.getProxyConfiguration();
+ if (proxyConfig != null &&
+ proxyConfig.getProxyUser() != null &&
+ proxyConfig.getProxyPassword() != null &&
+ proxyConfig.getAuthScheme() != null) { // can proxy config ever be null?
+ // add the proxy authorization header
+ UsernamePasswordCredentials cred =
+ new UsernamePasswordCredentials(proxyConfig.getProxyUser(),
+ proxyConfig.getProxyPassword());
+ String authHeader = proxyConfig.getAuthScheme().authenticate(cred, request);
+ request.setHeader(PROXY_AUTHORIZATION_HEADER, authHeader);
+ }
+ // always forward
+ super.messageSent(nextFilter, session, message);
+ }
+
+ /**
+ * Returns the HttpRequestMessage instance currently
+ * being processed by the IoSession.
+ *
+ * @param session The current session using the filter.
+ *
+ * @return The request message being processed.
+ */
+ private HttpRequestMessage getRequest(IoSession session) {
+ HttpRequestMessage request =
+ (HttpRequestMessage)session.getAttribute(HttpIoHandler.CURRENT_REQUEST);
+ return request;
+ }
+
+ @Override
+ /**
+ * Process the messageReceived() filter response. this
+ * will handle any proxy handshaking and SSL connection
+ * creation required.
+ *
+ * @param nextFilter The next filter in the chain.
+ * @param session The IoSession this operation is associated with.
+ * @param message The message object under construction.
+ *
+ * @exception Exception
+ */
+ public void messageReceived(NextFilter nextFilter, IoSession session,
+ Object message) throws Exception {
+ if (needConnectHandshake()) {
+ // we need to complete the connect handshake
+ handleConnectResponse(session, message);
+ } else {
+ // the connection is established, just allow this
+ // to flow down the chain.
+ super.messageReceived(nextFilter, session, message);
+ }
+ }
+
+ /**
+ * Tests if we need to perform the SSL tunneling handshake.
+ * If this is an https request, we need to handle the
+ * tunneling here. If we've already established this,
+ * then the processing can continue with the next filter.
+ *
+ * @return true if we need to establish the handshake.
+ */
+ private boolean needConnectHandshake() {
+ return (sslFilter != null && !connectHandshakeComplete);
+ }
+
+ /**
+ * Handle the response from a CONNECT request sent to
+ * the proxy server. If we got a good CONNECT request
+ * back, we add the SSL filter to the chain and
+ * write the original request back to the proxy
+ * server.
+ *
+ * @param session The current session.
+ * @param message The message object representing the request.
+ */
+ private void handleConnectResponse(IoSession session, Object message) {
+ HttpResponseMessage response = (HttpResponseMessage)message;
+ int status = response.getStatusCode();
+ if (status == 200) {
+ // layer the SSL socket by inserting the SSL filter
+ session.getFilterChain().addBefore(AsyncHttpClient.PROTOCOL_FILTER, "SSL", sslFilter);
+ connectHandshakeComplete = true; // handshake is done
+ HttpRequestMessage request = getRequest(session);
+ // write the original request intended for the remote target
+ session.write(request);
+ } else {
+ session.close();
+ }
+ }
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/proxy/ProxyFilter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,83 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Simple implementation of an AsyncHttpMonitor that
+ * just keeps a count of all of the events.
+ */
+public class CountingMonitor implements MonitoringListener {
+ private AtomicInteger[] counters =
+ new AtomicInteger[MonitoringEvent.CONNECTION_CLOSED + 1];
+
+ /**
+ * Default constructor
+ */
+ public CountingMonitor() {
+ for (int i = 0; i < counters.length; i++) {
+ counters[i] = new AtomicInteger(0);
+ }
+ }
+
+ /**
+ * Handle a notification event from an AsyncHttpClient.
+ *
+ * @param event The triggered event.
+ */
+ public void notification(MonitoringEvent event) {
+ int type = event.getType();
+ if (type < counters.length) {
+ counters[type].incrementAndGet();
+ }
+ }
+
+
+ /**
+ * Get the counter from a specific MonitoringEvent.
+ *
+ * @param type The type number of the event.
+ *
+ * @return The current counter value.
+ */
+ public int getCount(int type) {
+ // we only return values for ones in the defined range. Anything else is
+ // zero.
+ if (type < counters.length) {
+ return counters[type].get();
+ } else {
+ return 0;
+ }
+ }
+
+
+ /**
+ * Zero all of the event counters.
+ */
+ public void clearCounters() {
+ AtomicInteger[] newCounters = new AtomicInteger[MonitoringEvent.CONNECTION_CLOSED + 1];
+ for (int i = 0; i < newCounters.length; i++) {
+ newCounters[i] = new AtomicInteger(0);
+ }
+ counters = newCounters;
+ }
+}
+
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/CountingMonitor.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Simple implementation of a ThreadFactory that
+ * marks all of the threads as daemon threads.
+ */
+public class DaemonThreadFactory implements ThreadFactory {
+ private final ThreadFactory factory = Executors.defaultThreadFactory();
+
+ /**
+ * Create a new thread for the thread pool. The create
+ * thread will be a daemon thread.
+ *
+ * @param r The runnable used by the thread pool.
+ *
+ * @return The newly created thread.
+ */
+ public Thread newThread(Runnable r) {
+ Thread t = factory.newThread(r);
+ if (!t.isDaemon()) {
+ t.setDaemon(true);
+ }
+ return t;
+ }
+
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/DaemonThreadFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,95 @@
+/*
+ * 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.util;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * This is an event dispatcher to dispatch monitoring events on separate threads
+ * from the main thread.
+ * @version $Rev$ $Date$
+ */
+public class EventDispatcher {
+ /** shared thread pool for dispatching events */
+ private static ExecutorService dispatchThreadPool;
+
+ /** list of listeners for monitoring events */
+ private final List<MonitoringListener> listeners =
+ new CopyOnWriteArrayList<MonitoringListener>();
+
+ /**
+ * Creates a new EventDispatcher, including starting the new thread.
+ */
+ public EventDispatcher() {
+ // initialize the thread pool if it is not initialized yet
+ synchronized (EventDispatcher.class) {
+ if (dispatchThreadPool == null) {
+ dispatchThreadPool = Executors.newSingleThreadExecutor(new DaemonThreadFactory());
+ }
+ }
+ }
+
+ /**
+ * Add a listener for the dispatched events.
+ *
+ * @param listener The new listener.
+ */
+ public void addListener(MonitoringListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove a listener from the dispatch queue.
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeListener(MonitoringListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Dispatch an event.
+ *
+ * @param event The event to dispatch.
+ */
+ public void dispatchEvent(final MonitoringEvent event) {
+ // if there's no active listeners, no point in dispatching this
+ if (listeners.isEmpty()) {
+ return;
+ }
+
+ Runnable job = new Runnable() {
+ public void run() {
+ // iterate through the listeners list calling the handlers.
+ for (MonitoringListener listener : listeners) {
+ try {
+ event.dispatch(listener);
+ } catch (Throwable e) {
+ // just eat these
+ }
+ }
+ }
+ };
+ dispatchThreadPool.execute(job);
+ }
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/EventDispatcher.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,162 @@
+/*
+ * 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.util;
+
+import org.apache.ahc.codec.HttpRequestMessage;
+
+/**
+ * An event triggered during various lifecycle events
+ * of an HTTP request. Intended for collection of
+ * performance and general monitoring status.
+ */
+public class MonitoringEvent {
+ /**
+ * The event was triggered by a new HTTP request.
+ */
+ public static final int REQUEST_STARTED = 0;
+ /**
+ * The event was triggered by successful completion of
+ * an HTTP request.
+ */
+ public static final int REQUEST_COMPLETED = 1;
+ /**
+ * The event was triggered by a failure return from
+ * an HTTP request.
+ */
+ public static final int REQUEST_FAILED = 2;
+ /**
+ * The event was triggered due to a timeout while
+ * waiting for an HTTP request to complete.
+ */
+ public static final int REQUEST_TIMEOUT = 3;
+ /**
+ * Indicates a new connection attempt.
+ */
+ public static final int CONNECTION_ATTEMPTED = 4;
+ /**
+ * Indicates a failure occurred when attempting to
+ * connect to a host.
+ */
+ public static final int CONNECTION_FAILED = 5;
+ /**
+ * Indicates an attempt at retrying a host connect.
+ */
+ public static final int CONNECTION_RETRIED = 6;
+ /**
+ * Indicates an existing connection is being reused
+ * for a request.
+ */
+ public static final int CONNECTION_REUSED = 7;
+ /**
+ * Indicates a connection was successfully established
+ * for a request.
+ */
+ public static final int CONNECTION_SUCCESSFUL = 8;
+ /**
+ * The request was redirected to a different location.
+ */
+ public static final int REQUEST_REDIRECTED = 9;
+ /**
+ * An authentication challenge was received for the request
+ */
+ public static final int REQUEST_CHALLENGED = 10;
+ /**
+ * Indicates the connection was closed by the server.
+ */
+ public static final int CONNECTION_CLOSED_BY_SERVER = 11;
+ /**
+ * Indicates the connection was closed by the client.
+ */
+ public static final int CONNECTION_CLOSED = 12;
+
+ /** the type of the event */
+ private final int eventType;
+ /** timestamp of when the event occurred */
+ private final long timeStamp;
+ /** the request message associated with the event */
+ private final HttpRequestMessage request;
+
+ /**
+ * Create a new monitoring event.
+ *
+ * @param eventType The type of event.
+ * @param request The Http request that his event is triggered by.
+ *
+ * @see #REQUEST_STARTED
+ * @see #REQUEST_COMPLETED
+ * @see #REQUEST_FAILED
+ * @see #REQUEST_TIMEOUT
+ * @see #CONNECTION_ATTEMPTED
+ * @see #CONNECTION_FAILED
+ * @see #CONNECTION_RETRIED
+ * @see #CONNECTION_REUSED
+ * @see #CONNECTION_SUCCESSFUL
+ * @see #REQUEST_REDIRECTED
+ * @see #REQUEST_CHALLENGED
+ * @see #CONNECTION_CLOSED_BY_SERVER
+ * @see #CONNECTION_CLOSED
+ */
+ public MonitoringEvent(int eventType, HttpRequestMessage request) {
+ this.eventType = eventType;
+ this.request = request;
+ // timestamp the event (hi-res)
+ this.timeStamp = System.nanoTime()/1000000;
+ }
+
+ /**
+ * Returns the type code for the event.
+ *
+ * @return The integer type code for the event.
+ */
+ public int getType() {
+ return eventType;
+ }
+
+ /**
+ * Get the HTTP request that is associated with this event.
+ *
+ * @return The HTTP message request being processed when one
+ * of these events occurred.
+ */
+ public HttpRequestMessage getRequest()
+ {
+ return request;
+ }
+
+ /**
+ * Returns the timestamp that was taken when the event
+ * was generated.
+ *
+ * @return The hi-res timer value (in ms) for when the
+ * event was generated.
+ */
+ public long getTimeStamp() {
+ return timeStamp;
+ }
+
+ /**
+ * Dispatch an event to a listener.
+ *
+ * @param listener The target listener
+ */
+ public void dispatch(Object listener) {
+ ((MonitoringListener)listener).notification(this);
+ }
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringEvent.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,34 @@
+/**
+ *
+ * Copyright 2003-2004 The Apache Software Foundation
+ *
+ * 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.apache.ahc.util;
+
+import java.util.EventListener;
+
+/**
+ * The interface for listening for monitoring events.
+ * @version $Rev$ $Date$
+ */
+public interface MonitoringListener extends EventListener {
+ /**
+ * Process a notification for a MonitoringEvent.
+ *
+ * @param event The particular event to be processed.
+ */
+ public void notification(MonitoringEvent event);
+}
+
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/MonitoringListener.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java?rev=617593&view=auto
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java (added)
+++ geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java Fri Feb 1 10:26:11 2008
@@ -0,0 +1,96 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Simple monitoring listener for tracking average request times and average
+ * connect times. This is provided mainly to illustrate how one can collect
+ * timing data.
+ */
+public final class TimeMonitor extends CountingMonitor {
+ private final AtomicInteger requestCount = new AtomicInteger();
+ private final AtomicLong requestTimes = new AtomicLong();
+
+ private final AtomicInteger connectCount = new AtomicInteger();
+ private final AtomicLong connectTimes = new AtomicLong();
+
+ @Override
+ /**
+ * Process a notification event. If this is a
+ * REQUEST_COMPLETED event, the request timing
+ * information is added to the accumulators to that
+ * average response time can be calculated.
+ *
+ * @param event The notification event.
+ */
+ public void notification(MonitoringEvent event) {
+ super.notification(event);
+
+ // get the response time
+ int type = event.getType();
+ if (type == MonitoringEvent.REQUEST_COMPLETED) {
+ long requestStartTime = event.getRequest().getRequestStartTime();
+ if (requestStartTime != 0L) {
+ requestCount.incrementAndGet();
+ long elapsed = event.getTimeStamp() - requestStartTime;
+ requestTimes.addAndGet(elapsed);
+ }
+ } else if (type == MonitoringEvent.CONNECTION_SUCCESSFUL) {
+ long connectStartTime = event.getRequest().getConnectStartTime();
+ if (connectStartTime != 0L) {
+ connectCount.incrementAndGet();
+ long elapsed = event.getTimeStamp() - connectStartTime;
+ connectTimes.addAndGet(elapsed);
+ }
+ }
+ }
+
+ /**
+ * Return the average calculated response time for
+ * the processed requests.
+ *
+ * @return The average response time, in milliseconds, for
+ * all recorded completed requests.
+ */
+ public long getAverageResponseTime() {
+ if (requestCount.get() == 0) {
+ return 0L;
+ }
+ return requestTimes.get()/requestCount.get();
+ }
+
+
+ /**
+ * Return the average calculated connect time for
+ * the processed requests.
+ *
+ * @return The average connect time, in milliseconds, for
+ * all recorded completed requests.
+ */
+ public long getAverageConnectTime() {
+ if (connectCount.get() == 0) {
+ return 0L;
+ }
+ return connectTimes.get()/connectCount.get();
+ }
+}
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/async-http-client-mina2/src/main/java/org/apache/ahc/util/TimeMonitor.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/index.jsp
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/index.jsp?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/index.jsp (original)
+++ geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/index.jsp Fri Feb 1 10:26:11 2008
@@ -2,5 +2,4 @@
Cookie cookie = new Cookie("test","value");
cookie.setMaxAge(3600);
response.addCookie(cookie);
-%>
-Hello World!
\ No newline at end of file
+%>Hello World!
\ No newline at end of file
Modified: geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/timeout.jsp
URL: http://svn.apache.org/viewvc/geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/timeout.jsp?rev=617593&r1=617592&r2=617593&view=diff
==============================================================================
--- geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/timeout.jsp (original)
+++ geronimo/sandbox/async-http-client-mina2/src/test/catalina/webapps/ROOT/timeout.jsp Fri Feb 1 10:26:11 2008
@@ -1,5 +1,4 @@
<%
Thread.sleep(5000);
-%>
-Hello World!
+%>Hello World!