You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2007/09/18 14:03:14 UTC

svn commit: r576859 - in /jakarta/httpcomponents/httpcore/trunk: ./ module-nio/src/main/java/org/apache/http/impl/nio/reactor/ module-nio/src/main/java/org/apache/http/nio/reactor/ module-nio/src/test/java/org/apache/http/impl/nio/reactor/ module-nio/s...

Author: olegk
Date: Tue Sep 18 05:03:13 2007
New Revision: 576859

URL: http://svn.apache.org/viewvc?rev=576859&view=rev
Log:
HTTPCORE-86: Allow for optional handling of runtime exceptions thrown by protocol handlers to ensure the I/O dispatch thread remains running.


Modified:
    jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractIOReactor.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractMultiworkerIOReactor.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/BaseIOReactor.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultListeningIOReactor.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/reactor/IOReactorExceptionHandler.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/reactor/TestDefaultIOReactors.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpClient.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpServer.java

Modified: jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt (original)
+++ jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt Tue Sep 18 05:03:13 2007
@@ -1,12 +1,17 @@
 Changes since release 4.0 Alpha 5
 
+* [HTTPCORE-86] Allow for optional handling of runtime exceptions
+  thrown by protocol handlers to ensurev the I/O dispatch thread
+  remains running.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPCORE-116] moved parameter names to interfaces
   Contributed by Roland Weber <rolandw at apache.org>
 
 * [HTTPCORE-109] Improved shutdown process of the I/O reactors in NIO modules. I/O 
   reactors now attempt to terminate connections gracefully before shutting down the
   underlying socket channels.
-  Oleg Kalnichevski <olegk at apache.org>
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
 
 * [HTTPCORE-107] allow sending and receiving of SIP messages
   Contributed by Roland Weber <rolandw at apache.org>

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractIOReactor.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractIOReactor.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractIOReactor.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractIOReactor.java Tue Sep 18 05:03:13 2007
@@ -165,7 +165,7 @@
         selectedKeys.clear();
     }
 
-    private void processEvent(final SelectionKey key) {
+    protected void processEvent(final SelectionKey key) {
         try {
             if (key.isAcceptable()) {
                 acceptable(key);

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractMultiworkerIOReactor.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractMultiworkerIOReactor.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractMultiworkerIOReactor.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/AbstractMultiworkerIOReactor.java Tue Sep 18 05:03:13 2007
@@ -48,6 +48,7 @@
 import org.apache.http.nio.reactor.IOEventDispatch;
 import org.apache.http.nio.reactor.IOReactor;
 import org.apache.http.nio.reactor.IOReactorException;
+import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 
@@ -65,6 +66,8 @@
     private final Worker[] workers;
     private final Thread[] threads;
     
+    protected IOReactorExceptionHandler exceptionHandler;
+    
     private int currentWorker = 0;
     
     public AbstractMultiworkerIOReactor(
@@ -104,6 +107,14 @@
         return this.status;
     }
 
+    public void setExceptionHandler(final IOReactorExceptionHandler exceptionHandler) {
+        this.exceptionHandler = exceptionHandler;
+        for (int i = 0; i < this.workerCount; i++) {
+            BaseIOReactor dispatcher = this.dispatchers[i];
+            dispatcher.setExceptionHandler(exceptionHandler);
+        }
+    }
+    
     protected abstract void processEvents(int count) throws IOReactorException;
     
     public void execute(

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/BaseIOReactor.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/BaseIOReactor.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/BaseIOReactor.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/BaseIOReactor.java Tue Sep 18 05:03:13 2007
@@ -38,6 +38,7 @@
 
 import org.apache.http.nio.reactor.EventMask;
 import org.apache.http.nio.reactor.IOReactorException;
+import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.nio.reactor.IOSession;
 
 public class BaseIOReactor extends AbstractIOReactor {
@@ -47,11 +48,27 @@
     
     private long lastTimeoutCheck;
     
+    private IOReactorExceptionHandler exceptionHandler;
+    
     public BaseIOReactor(long selectTimeout) throws IOReactorException {
         super(selectTimeout);
         this.bufferingSessions = new SessionSet();
         this.timeoutCheckInterval = selectTimeout;
         this.lastTimeoutCheck = System.currentTimeMillis();
+    }
+
+    public void setExceptionHandler(IOReactorExceptionHandler exceptionHandler) {
+        this.exceptionHandler = exceptionHandler;
+    }
+
+    protected void processEvent(final SelectionKey key) {
+        try {
+            super.processEvent(key);
+        } catch (RuntimeException ex) {
+            if (this.exceptionHandler == null || !this.exceptionHandler.handle(ex)) {
+                throw ex;
+            }
+        }
     }
 
     protected void acceptable(final SelectionKey key) {

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java Tue Sep 18 05:03:13 2007
@@ -114,7 +114,13 @@
                 key.cancel();
                 if (channel.isConnected()) {
                     try {
-                        prepareSocket(channel.socket());
+                        try {
+                            prepareSocket(channel.socket());
+                        } catch (IOException ex) {
+                            if (this.exceptionHandler == null || !this.exceptionHandler.handle(ex)) {
+                                throw new IOReactorException("Failure initalizing socket", ex);
+                            }
+                        }
                         ChannelEntry entry = new ChannelEntry(channel, sessionRequest); 
                         addChannel(entry);
                     } catch (IOException ex) {

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultListeningIOReactor.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultListeningIOReactor.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultListeningIOReactor.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultListeningIOReactor.java Tue Sep 18 05:03:13 2007
@@ -41,7 +41,6 @@
 import java.util.Set;
 
 import org.apache.http.nio.reactor.IOReactorException;
-import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.nio.reactor.ListeningIOReactor;
 import org.apache.http.params.HttpParams;
 import org.apache.http.util.concurrent.ThreadFactory;
@@ -49,8 +48,6 @@
 public class DefaultListeningIOReactor extends AbstractMultiworkerIOReactor 
         implements ListeningIOReactor {
 
-    private IOReactorExceptionHandler exceptionHandler;
-    
     public DefaultListeningIOReactor(
             int workerCount, 
             final ThreadFactory threadFactory,
@@ -62,10 +59,6 @@
             int workerCount, 
             final HttpParams params) throws IOReactorException {
         this(workerCount, null, params);
-    }
-    
-    public void setExceptionHandler(final IOReactorExceptionHandler exceptionHandler) {
-        this.exceptionHandler = exceptionHandler;
     }
     
     protected void processEvents(int readyCount) throws IOReactorException {

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/reactor/IOReactorExceptionHandler.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/reactor/IOReactorExceptionHandler.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/reactor/IOReactorExceptionHandler.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/reactor/IOReactorExceptionHandler.java Tue Sep 18 05:03:13 2007
@@ -44,7 +44,7 @@
 
     /**
      * This method is expected to examine the I/O exception passed as a parameter
-     * and decide whether it is safe to continue execution of the i/O reactor 
+     * and decide whether it is safe to continue execution of the I/O reactor 
      * 
      * @param ex potentially recoverable I/O exception 
      * @return <code>true</code> if it is safe to ignore the exception 
@@ -52,5 +52,16 @@
      * I/O reactor must throw {@link IOReactorException} and terminate 
      */
     boolean handle(IOException ex); 
+    
+    /**
+     * This method is expected to examine the runtime exception passed as a parameter
+     * and decide whether it is safe to continue execution of the I/O reactor 
+     * 
+     * @param ex potentially recoverable runtime exception 
+     * @return <code>true</code> if it is safe to ignore the exception 
+     * and continue execution of the I/O reactor; <code>false</code> if the
+     * I/O reactor must throw {@link RuntimeException} and terminate 
+     */
+    boolean handle(RuntimeException ex); 
     
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/reactor/TestDefaultIOReactors.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/reactor/TestDefaultIOReactors.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/reactor/TestDefaultIOReactors.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/reactor/TestDefaultIOReactors.java Tue Sep 18 05:03:13 2007
@@ -49,6 +49,7 @@
 import org.apache.http.nio.protocol.EventListener;
 import org.apache.http.nio.protocol.HttpRequestExecutionHandler;
 import org.apache.http.nio.reactor.IOReactor;
+import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.params.BasicHttpParams;
 import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
@@ -255,4 +256,175 @@
         this.server.shutdown();
     }
 
+    public void testUnhandledRuntimeException() throws Exception {
+
+        final RequestCount requestConns = new RequestCount(1); 
+        
+        HttpRequestHandler requestHandler = new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                throw new IllegalStateException("Oppsie!!!");
+            }
+            
+        };
+        
+        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+
+            public void initalizeContext(final HttpContext context, final Object attachment) {
+            }
+
+            public void finalizeContext(final HttpContext context) {
+            }
+
+            public HttpRequest submitRequest(final HttpContext context) {
+                Boolean b = ((Boolean) context.getAttribute("done"));
+                if (b == null) {
+                    BasicHttpRequest get = new BasicHttpRequest("GET", "/");
+                    context.setAttribute("done", Boolean.TRUE);
+                    return get;
+                } else {
+                    return null;
+                }
+            }
+            
+            public void handleResponse(final HttpResponse response, final HttpContext context) {
+            }
+            
+        };
+     
+        IOReactorExceptionHandler exceptionHandler = new IOReactorExceptionHandler() {
+
+            public boolean handle(final IOException ex) {
+                return false;
+            }
+
+            public boolean handle(final RuntimeException ex) {
+                requestConns.decrement();                    
+                return false;
+            }
+          
+        };
+        
+        NHttpServiceHandler serviceHandler = createHttpServiceHandler(
+                requestHandler, 
+                null,
+                new SimpleEventListener());
+        
+        NHttpClientHandler clientHandler = createHttpClientHandler(
+                requestExecutionHandler,
+                new SimpleEventListener());
+
+        this.server.setExceptionHandler(exceptionHandler);
+        
+        this.server.start(serviceHandler);
+        this.client.start(clientHandler);
+        
+        InetSocketAddress serverAddress = (InetSocketAddress) this.server.getSocketAddress();
+        
+        this.client.openConnection(
+                new InetSocketAddress("localhost", serverAddress.getPort()), 
+                null);
+     
+        requestConns.await(10000);
+        assertEquals(0, requestConns.getValue());
+        
+        this.server.join(20000);
+        
+        Exception ex = this.server.getException();
+        assertNotNull(ex);
+        assertTrue(ex instanceof IllegalStateException);
+        // I/O reactor shut down itself
+        assertEquals(IOReactor.SHUT_DOWN, this.server.getStatus());
+        
+        this.client.shutdown();
+        this.server.shutdown();
+    }
+
+    public void testHandledRuntimeException() throws Exception {
+
+        final RequestCount requestConns = new RequestCount(1); 
+        
+        HttpRequestHandler requestHandler = new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                throw new IllegalStateException("Oppsie!!!");
+            }
+            
+        };
+        
+        HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+
+            public void initalizeContext(final HttpContext context, final Object attachment) {
+            }
+
+            public void finalizeContext(final HttpContext context) {
+            }
+
+            public HttpRequest submitRequest(final HttpContext context) {
+                Boolean b = ((Boolean) context.getAttribute("done"));
+                if (b == null) {
+                    BasicHttpRequest get = new BasicHttpRequest("GET", "/");
+                    context.setAttribute("done", Boolean.TRUE);
+                    return get;
+                } else {
+                    return null;
+                }
+            }
+            
+            public void handleResponse(final HttpResponse response, final HttpContext context) {
+            }
+            
+        };
+     
+        IOReactorExceptionHandler exceptionHandler = new IOReactorExceptionHandler() {
+
+            public boolean handle(final IOException ex) {
+                return false;
+            }
+
+            public boolean handle(final RuntimeException ex) {
+                requestConns.decrement();                    
+                return true;
+            }
+          
+        };
+        
+        NHttpServiceHandler serviceHandler = createHttpServiceHandler(
+                requestHandler, 
+                null,
+                new SimpleEventListener());
+        
+        NHttpClientHandler clientHandler = createHttpClientHandler(
+                requestExecutionHandler,
+                new SimpleEventListener());
+
+        this.server.setExceptionHandler(exceptionHandler);
+        
+        this.server.start(serviceHandler);
+        this.client.start(clientHandler);
+        
+        InetSocketAddress serverAddress = (InetSocketAddress) this.server.getSocketAddress();
+        
+        this.client.openConnection(
+                new InetSocketAddress("localhost", serverAddress.getPort()), 
+                null);
+     
+        requestConns.await(10000);
+        assertEquals(0, requestConns.getValue());
+        
+        this.server.join(1000);
+        
+        assertEquals(IOReactor.ACTIVE, this.server.getStatus());
+        assertNull(this.server.getException());
+        
+        this.client.shutdown();
+        this.server.shutdown();
+    }
+    
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpClient.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpClient.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpClient.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpClient.java Tue Sep 18 05:03:13 2007
@@ -37,13 +37,13 @@
 import org.apache.http.impl.nio.DefaultClientIOEventDispatch;
 import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
 import org.apache.http.nio.NHttpClientHandler;
-import org.apache.http.nio.reactor.ConnectingIOReactor;
 import org.apache.http.nio.reactor.IOEventDispatch;
+import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.params.HttpParams;
 
 public class TestHttpClient {
 
-    private final ConnectingIOReactor ioReactor;
+    private final DefaultConnectingIOReactor ioReactor;
     private final HttpParams params;
     
     private volatile IOReactorThread thread;
@@ -58,6 +58,10 @@
         return this.params;
     }
     
+    public void setExceptionHandler(final IOReactorExceptionHandler exceptionHandler) {
+        this.ioReactor.setExceptionHandler(exceptionHandler);
+    }
+
     private void execute(final NHttpClientHandler clientHandler) throws IOException {
         IOEventDispatch ioEventDispatch = new DefaultClientIOEventDispatch(
                 clientHandler, 

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpServer.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpServer.java?rev=576859&r1=576858&r2=576859&view=diff
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpServer.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/mockup/TestHttpServer.java Tue Sep 18 05:03:13 2007
@@ -38,7 +38,7 @@
 import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
 import org.apache.http.nio.NHttpServiceHandler;
 import org.apache.http.nio.reactor.IOEventDispatch;
-import org.apache.http.nio.reactor.ListeningIOReactor;
+import org.apache.http.nio.reactor.IOReactorExceptionHandler;
 import org.apache.http.params.HttpParams;
 
 /**
@@ -48,7 +48,7 @@
  */
 public class TestHttpServer {
 
-    private final ListeningIOReactor ioReactor;
+    private final DefaultListeningIOReactor ioReactor;
     private final HttpParams params;
     private final Object socketMutex;
 
@@ -66,6 +66,10 @@
         return this.params;
     }
     
+    public void setExceptionHandler(final IOReactorExceptionHandler exceptionHandler) {
+        this.ioReactor.setExceptionHandler(exceptionHandler);
+    }
+
     private void execute(final NHttpServiceHandler serviceHandler) throws IOException {
         synchronized (this.socketMutex) {
             this.address = (InetSocketAddress) this.ioReactor.listen(