Author: jochen
Date: Wed Oct 11 18:03:54 2006
New Revision: 463093

URL: http://svn.apache.org/viewvc?view=rev&rev=463093
Log:
Rework of the WebServer/ThreadPool framework, in order to overcome an
unreliable Shutdown, as detected by Stanislav Miklik.

Added:
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ShutdownTest.java
Modified:
    
webservices/xmlrpc/trunk/common/src/main/java/org/apache/xmlrpc/util/ThreadPool.java
    webservices/xmlrpc/trunk/pom.xml
    
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/Connection.java
    
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/HttpServletResponseImpl.java
    
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/ServletConnection.java
    webservices/xmlrpc/trunk/src/changes/changes.xml
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/AuthenticationTest.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ClientProvider.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/JiraTest.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/LocalTransportProvider.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ParserTest.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ServletWebServerProvider.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/WebServerProvider.java
    
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/XmlRpcTestCase.java

Modified: 
webservices/xmlrpc/trunk/common/src/main/java/org/apache/xmlrpc/util/ThreadPool.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/common/src/main/java/org/apache/xmlrpc/util/ThreadPool.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/common/src/main/java/org/apache/xmlrpc/util/ThreadPool.java
 (original)
+++ 
webservices/xmlrpc/trunk/common/src/main/java/org/apache/xmlrpc/util/ThreadPool.java
 Wed Oct 11 18:03:54 2006
@@ -32,63 +32,77 @@
                void run() throws Throwable;
        }
 
-       private class MyThread extends Thread {
-               private boolean shuttingDown;
-               private int numTasks;
-               private Task task;
-               MyThread() {
-                       super(threadGroup, threadGroup.getName() + "-" + num++);
-                       setDaemon(true);
-               }
-               synchronized void shutdown() {
-                       shuttingDown = true;
-                       notify();
-               }
-               synchronized boolean isShuttingDown() { return shuttingDown; }
-               synchronized void waitForNotification() {
-                       if (getTask() != null) { return; }
-                       try {
-                               wait();
-                       } catch (InterruptedException e) {
-                       }
-               }
-               synchronized int getNumTasks() { return numTasks; }
-               synchronized Task getTask() { return task; }
-               synchronized void setTask(Task pTask) {
-                       task = pTask;
-                       if (task != null) {
-                               notify();
-                       }
-               }
-               synchronized void runTask() {
-                       Task tsk = getTask();
-                       if (tsk == null) {
-                               return;
-                       }
-                       ++numTasks;
-                       Throwable t;
-                       try {
-                               tsk.run();
-                               t = null;
-                       } catch (Throwable th) {
-                               t = th;
-                       }
-                       if (t == null) {
-                               repool(this);
-                       } else {
-                               discard(this);
-                       }
-               }
-               public void run() {
-                       while (!isShuttingDown()) {
-                               if (getTask() == null) {
-                                       waitForNotification();
-                               } else {
-                                       runTask();
-                               }
-                       }
-               }
-       }
+    /** A task, which may be interrupted, if the pool is shutting down. 
+     */
+    public interface InterruptableTask extends Task {
+        /** Interrupts the task.
+         * @throws Throwable Shutting down the task failed.
+         */
+        void shutdown() throws Throwable;
+    }
+
+    private class Poolable {
+        private boolean shuttingDown;
+        private Task task;
+        private Thread thread;
+        Poolable(ThreadGroup pGroup, int pNum) {
+            thread = new Thread(pGroup, pGroup.getName() + "-" + pNum){
+                public void run() {
+                    while (!isShuttingDown()) {
+                        final Task t = getTask();
+                        if (t == null) {
+                            try {
+                                synchronized (this) {
+                                    wait();
+                                }
+                            } catch (InterruptedException e) {
+                                // Do nothing
+                            }
+                        } else {
+                            try {
+                                t.run();
+                                resetTask();
+                                repool(Poolable.this);
+                            } catch (Throwable e) {
+                                discard(Poolable.this);
+                                resetTask();
+                            }
+                        }
+                    }
+                }
+            };
+            thread.start();
+        }
+        synchronized void shutdown() {
+            shuttingDown = true;
+            final Task t = getTask();
+            if (t != null  &&  t instanceof InterruptableTask) {
+                try {
+                    ((InterruptableTask) t).shutdown();
+                } catch (Throwable th) {
+                    // Ignore me
+                }
+            }
+            task = null;
+            synchronized (thread) {
+                thread.notify();
+            }
+        }
+        private synchronized boolean isShuttingDown() { return shuttingDown; }
+        String getName() { return thread.getName(); }
+        private synchronized Task getTask() {
+            return task;
+        }
+        private synchronized void resetTask() {
+            task = null;
+        }
+        synchronized void start(Task pTask) {
+            task = pTask;
+            synchronized (thread) {
+                thread.notify();
+            }
+        }
+    }
 
        private final ThreadGroup threadGroup;
        private final int maxSize;
@@ -107,25 +121,26 @@
                threadGroup = new ThreadGroup(pName);
        }
 
-       synchronized void discard(MyThread pThread) {
-               pThread.shutdown();
-               if (!runningThreads.remove(pThread)) {
-                       throw new IllegalStateException("The list of running 
threads didn't contain the thread " + pThread.getName());
-               }
-       }
-
-       synchronized void repool(MyThread pThread) {
-               if (maxSize != 0  &&  (runningThreads.size() + 
waitingThreads.size()) > maxSize) {
-                       discard(pThread);
-               } else if (waitingTasks.size() > 0) {
-                       pThread.setTask((Task) waitingTasks.remove(0));
-               } else {
-                       pThread.setTask(null);
-                       if (!runningThreads.remove(pThread)) {
-                               throw new IllegalStateException("The list of 
running threads didn't contain the thread " + pThread.getName());
-                       }
-                       waitingThreads.add(pThread);
-               }
+       synchronized void discard(Poolable pPoolable) {
+               pPoolable.shutdown();
+        runningThreads.remove(pPoolable);
+        waitingThreads.remove(pPoolable);
+       }
+
+       synchronized void repool(Poolable pPoolable) {
+        if (runningThreads.remove(pPoolable)) {
+            if (maxSize != 0  &&  runningThreads.size() + 
waitingThreads.size() >= maxSize) {
+                discard(pPoolable);
+            } else {
+                waitingThreads.add(pPoolable);
+                if (waitingTasks.size() > 0) {
+                    Task task = (Task) waitingTasks.remove(waitingTasks.size() 
- 1);
+                    startTask(task);
+                }
+            }
+        } else {
+            discard(pPoolable);
+        }
        }
 
        /** Starts a task immediately.
@@ -138,15 +153,14 @@
                if (maxSize != 0  &&  runningThreads.size() > maxSize) {
                        return false;
                }
-               MyThread t;
+        Poolable poolable;
                if (waitingThreads.size() > 0) {
-                       t = (MyThread) 
waitingThreads.remove(waitingThreads.size()-1);
+                   poolable = (Poolable) 
waitingThreads.remove(waitingThreads.size()-1);
                } else {
-                       t = new MyThread();
-                       t.start();
+            poolable = new Poolable(threadGroup, num++);
                }
-               runningThreads.add(t);
-               t.setTask(pTask);
+               runningThreads.add(poolable);
+        poolable.start(pTask);
                return true;
        }
 
@@ -166,14 +180,14 @@
        /** Closes the pool.
         */
        public synchronized void shutdown() {
-               for (int i = 0;  i < waitingThreads.size();  i++) {
-                       MyThread t = (MyThread) waitingThreads.get(i);
-                       t.shutdown();
-               }
-               for (int i = 0;  i < runningThreads.size();  i++) {
-                       MyThread t = (MyThread) runningThreads.get(i);
-                       t.shutdown();
-               }
+        while (!waitingThreads.isEmpty()) {
+            Poolable poolable = (Poolable) 
waitingThreads.remove(waitingThreads.size()-1);
+            poolable.shutdown();
+        }
+        while (!runningThreads.isEmpty()) {
+            Poolable poolable = (Poolable) 
runningThreads.remove(runningThreads.size()-1);
+            poolable.shutdown();
+        }
        }
 
        /** Returns the maximum number of concurrent threads.
@@ -184,5 +198,5 @@
        /** Returns the number of threads, which have actually been created,
      * as opposed to the number of currently running threads.
         */
-    public int getNumThreads() { return num; }
+    public synchronized int getNumThreads() { return num; }
 }

Modified: webservices/xmlrpc/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/pom.xml?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- webservices/xmlrpc/trunk/pom.xml (original)
+++ webservices/xmlrpc/trunk/pom.xml Wed Oct 11 18:03:54 2006
@@ -236,7 +236,7 @@
                 <artifactId>commons-httpclient</artifactId>
                 <version>3.0.1</version>
                 <type>jar</type>
-                <scope>optional</scope>
+                <scope>provided</scope>
             </dependency>
             <dependency>
                 <groupId>commons-logging</groupId>
@@ -253,7 +253,7 @@
                 <groupId>javax.servlet</groupId>
                 <artifactId>servlet-api</artifactId>
                 <version>2.4</version>
-                <scope>optional</scope>
+                <scope>provided</scope>
             </dependency>
             <dependency>
                 <groupId>junit</groupId>
@@ -270,7 +270,7 @@
                 <groupId>jaxme</groupId>
                 <artifactId>jaxmeapi</artifactId>
                 <version>0.5.1</version>
-                <scope>optional</scope>
+                <scope>provided</scope>
             </dependency>
         </dependencies>
     </dependencyManagement>

Modified: 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/Connection.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/Connection.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/Connection.java
 (original)
+++ 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/Connection.java
 Wed Oct 11 18:03:54 2006
@@ -23,6 +23,7 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.Socket;
+import java.net.SocketException;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.StringTokenizer;
@@ -42,7 +43,7 @@
  * is able to do HTTP keepalive. In other words, it can serve
  * multiple requests via a single, physical connection.
  */
-public class Connection implements ThreadPool.Task, ServerStreamConnection {
+public class Connection implements ThreadPool.InterruptableTask, 
ServerStreamConnection {
     private static final String US_ASCII = "US-ASCII";
     private static final byte[] ctype = toHTTPBytes("Content-Type: 
text/xml\r\n");
     private static final byte[] clength = toHTTPBytes("Content-Length: ");
@@ -97,6 +98,8 @@
     private byte[] buffer;
     private Map headers;
     private RequestData requestData;
+    private boolean shuttingDown;
+    private boolean firstByte;
 
     /** Creates a new webserver connection on the given socket.
      * @param pWebServer The webserver maintaining this connection.
@@ -133,6 +136,7 @@
         if (headers != null) {
             headers.clear();
         }
+        firstByte = true;
         XmlRpcHttpServerConfig serverConfig = (XmlRpcHttpServerConfig) 
server.getConfig();
         requestData.setBasicEncoding(serverConfig.getBasicEncoding());
         
requestData.setContentLengthOptional(serverConfig.isContentLengthOptional());
@@ -141,6 +145,9 @@
 
         // reset user authentication
         String line = readLine();
+        if (line == null  &&  firstByte) {
+            return null;
+        }
         // Netscape sends an extra \n\r after bodypart, swallow it
         if (line != null && line.length() == 0) {
             line = readLine();
@@ -210,7 +217,9 @@
                 /* Ignore me */
             }
         } catch (Throwable t) {
-            webServer.log(t);
+            if (!shuttingDown) {
+                webServer.log(t);
+            }
         } finally {
             try { output.close(); } catch (Throwable ignore) {}
             try { input.close(); } catch (Throwable ignore) {}
@@ -225,7 +234,16 @@
         int next;
         int count = 0;
         for (;;) {
-            next = input.read();
+            try {
+                next = input.read();
+                firstByte = false;
+            } catch (SocketException e) {
+                if (firstByte) {
+                    return null;
+                } else {
+                    throw e;
+                }
+            }
             if (next < 0 || next == '\n') {
                 break;
             }
@@ -382,5 +400,10 @@
     }
 
     public void close() throws IOException {
+    }
+
+    public void shutdown() throws Throwable {
+        shuttingDown = true;
+        socket.close();
     }
 }

Modified: 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/HttpServletResponseImpl.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/HttpServletResponseImpl.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/HttpServletResponseImpl.java
 (original)
+++ 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/HttpServletResponseImpl.java
 Wed Oct 11 18:03:54 2006
@@ -412,7 +412,7 @@
                }
        }
 
-       String getHttpHeaders(Integer pContentLength) throws IOException {
+       String getHttpHeaders(Integer pContentLength) {
                StringBuffer sb = new StringBuffer();
                sb.append("HTTP/1.0 ");
                sb.append(status);

Modified: 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/ServletConnection.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/ServletConnection.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/ServletConnection.java
 (original)
+++ 
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/webserver/ServletConnection.java
 Wed Oct 11 18:03:54 2006
@@ -22,18 +22,19 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.xmlrpc.util.ThreadPool.Task;
+import org.apache.xmlrpc.util.ThreadPool.InterruptableTask;
 
 
 /** [EMAIL PROTECTED] org.apache.xmlrpc.webserver.ServletWebServer 
ServletWebServer's}
  * [EMAIL PROTECTED] org.apache.xmlrpc.util.ThreadPool.Task} for handling a 
single
  * servlet connection.
  */
-public class ServletConnection implements Task {
+public class ServletConnection implements InterruptableTask {
        private final HttpServlet servlet;
        private final Socket socket;
        private final HttpServletRequest request;
        private final HttpServletResponse response;
+    private boolean shuttingDown;
 
        /** Creates a new instance.
         * @param pServlet The servlet, which ought to handle the request.
@@ -48,6 +49,17 @@
        }
 
        public void run() throws Throwable {
-               servlet.service(request, response);
+        try {
+            servlet.service(request, response);
+        } catch (Throwable t) {
+            if (!shuttingDown) {
+                throw t;
+            }
+        }
        }
+
+    public void shutdown() throws Throwable {
+        shuttingDown = true;
+        socket.close();
+    }
 }

Modified: webservices/xmlrpc/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/changes/changes.xml?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- webservices/xmlrpc/trunk/src/changes/changes.xml (original)
+++ webservices/xmlrpc/trunk/src/changes/changes.xml Wed Oct 11 18:03:54 2006
@@ -24,6 +24,10 @@
         Atomic properties of XmlRpcServer are now configurable as init 
parameters
         in the XmlRpcServlet.
       </action>
+      <action dev="jochen" type="fix">
+        Reworked the WebServer/ThreadPool framework in order to ensure a clean
+        shutdown.
+      </action>
     </release>
     <release version="3.0.1-SNAPSHOT" date="Not yet released">
       <action dev="jochen" type="fix">

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/AuthenticationTest.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/AuthenticationTest.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/AuthenticationTest.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/AuthenticationTest.java
 Wed Oct 11 18:03:54 2006
@@ -17,6 +17,9 @@
 
 import java.io.IOException;
 
+import javax.servlet.ServletException;
+
+import org.apache.log4j.BasicConfigurator;
 import org.apache.xmlrpc.XmlRpcException;
 import org.apache.xmlrpc.XmlRpcRequest;
 import org.apache.xmlrpc.XmlRpcRequestConfig;

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ClientProvider.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ClientProvider.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ClientProvider.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ClientProvider.java
 Wed Oct 11 18:03:54 2006
@@ -39,4 +39,8 @@
      * @return A server instance, which is being used for performing the test.
         */
     XmlRpcServer getServer();
+
+    /** Performs a shutdown of the server.
+     */
+    void shutdown();
 }

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/JiraTest.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/JiraTest.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/JiraTest.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/JiraTest.java
 Wed Oct 11 18:03:54 2006
@@ -20,6 +20,7 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.lang.reflect.UndeclaredThrowableException;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.util.Collections;
@@ -30,6 +31,7 @@
 import java.util.Vector;
 
 import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.client.TimingOutCallback;
 import org.apache.xmlrpc.client.XmlRpcClient;
 import org.apache.xmlrpc.client.XmlRpcHttpClientConfig;
 import org.apache.xmlrpc.client.util.ClientFactory;
@@ -229,6 +231,16 @@
     }
 
     /**
+     * Test case for <a href="http://issues.apache.org/jira/browse/XMLRPC-112";>
+     * XMLRPC-112</a>
+     */
+    public void testXMLRPC112() throws Exception {
+        for (int i = 0;  i < providers.length;  i++) {
+            testXMLRPC112(providers[i]);
+        }
+    }
+
+    /**
      * Test case for <a href="http://issues.apache.org/jira/browse/XMLRPC-113";>
      * XMLRPC-113</a>
      */
@@ -236,6 +248,34 @@
         for (int i = 0;  i < providers.length;  i++) {
             testXMLRPC113(providers[i]);
         }
+    }
+
+
+    private void testXMLRPC112(ClientProvider pProvider) throws Exception {
+        XmlRpcClient client = pProvider.getClient();
+        client.setConfig(getConfig(pProvider));
+        TimingOutCallback toc = new TimingOutCallback(5000);
+        final String methodName = XMLRPC89Handler.class.getName() + ".reverse";
+        client.executeAsync(methodName, new Object[]{new Object[]{"1", "2", 
"3"}}, toc);
+        Object o;
+        try {
+            o = toc.waitForResponse();
+        } catch (Exception e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new UndeclaredThrowableException(t);
+        }
+        checkXMLRPC112Result(o);
+        checkXMLRPC112Result(client.execute(methodName, new Object[]{new 
Object[]{"1", "2", "3"}}));
+        checkXMLRPC112Result(client.execute(methodName, new Object[]{new 
Object[]{"1", "2", "3"}}));
+    }
+
+    private void checkXMLRPC112Result(Object pObject) {
+        Object[] args = (Object[]) pObject;
+        assertEquals(3, args.length);
+        assertEquals("3", args[0]);
+        assertEquals("2", args[1]);
+        assertEquals("1", args[2]);
     }
 
     /**

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/LocalTransportProvider.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/LocalTransportProvider.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/LocalTransportProvider.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/LocalTransportProvider.java
 Wed Oct 11 18:03:54 2006
@@ -51,4 +51,8 @@
     public XmlRpcServer getServer() {
         return server;
     }
+
+    public void shutdown() {
+        // Does nothing
+    }
 }

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ParserTest.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ParserTest.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ParserTest.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ParserTest.java
 Wed Oct 11 18:03:54 2006
@@ -1,7 +1,9 @@
 package org.apache.xmlrpc.test;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
@@ -23,15 +25,24 @@
  */
 public class ParserTest extends TestCase {
        private Object parseResponse(final String s) throws XmlRpcException, 
IOException, SAXException {
-               XmlRpcStreamRequestConfig config = new XmlRpcClientConfigImpl();
+               return parseResponse(new InputSource(new StringReader(s)));
+       }
+
+    private Object parseResponse(final File f) throws XmlRpcException, 
IOException, SAXException {
+        return parseResponse(new 
InputSource(f.toURI().toURL().toExternalForm()));
+    }
+
+    private Object parseResponse(InputSource isource) throws XmlRpcException,
+            IOException, SAXException {
+        XmlRpcStreamRequestConfig config = new XmlRpcClientConfigImpl();
                XmlRpcClient client = new XmlRpcClient();
                XmlRpcResponseParser parser = new XmlRpcResponseParser(config, 
client.getTypeFactory());
                XMLReader xr = SAXParsers.newXMLReader();
                xr.setContentHandler(parser);
-               xr.parse(new InputSource(new StringReader(s)));
+        xr.parse(isource);
                Object o = parser.getResult();
                return o;
-       }
+    }
 
     private XmlRpcRequestParser parseRequest(final String s) throws 
XmlRpcException, IOException, SAXException {
         XmlRpcStreamConfig config = new XmlRpcHttpRequestConfigImpl();

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ServletWebServerProvider.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ServletWebServerProvider.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ServletWebServerProvider.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ServletWebServerProvider.java
 Wed Oct 11 18:03:54 2006
@@ -77,4 +77,8 @@
     public XmlRpcServer getServer() {
         return servlet.getXmlRpcServletServer();
     }
+
+    public void shutdown() {
+        webServer.shutdown();
+    }
 }

Added: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ShutdownTest.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ShutdownTest.java?view=auto&rev=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ShutdownTest.java
 (added)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/ShutdownTest.java
 Wed Oct 11 18:03:54 2006
@@ -0,0 +1,104 @@
+package org.apache.xmlrpc.test;
+
+import java.net.ConnectException;
+import java.net.URL;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.client.XmlRpcClient;
+import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
+import org.apache.xmlrpc.server.PropertyHandlerMapping;
+import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;
+import org.apache.xmlrpc.webserver.WebServer;
+
+
+/**
+ * Tests the web servers shutdown method.
+ */
+public class ShutdownTest extends TestCase {
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        try {
+            new ShutdownTest().testShutdown();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Dummy handler for running the test.
+     */
+    public static class Adder {
+        /** Returns the sum of p1 and p2.
+         */
+        public int add(int p1, int p2) {
+            return p1 + p2;
+        }
+    }
+
+    private WebServer setupServer() throws Exception {
+        WebServer server = new WebServer(0);
+        PropertyHandlerMapping mapping = new PropertyHandlerMapping();
+        mapping.addHandler("Adder", Adder.class);
+        server.getXmlRpcServer().setHandlerMapping(mapping);
+        XmlRpcServerConfigImpl config = new XmlRpcServerConfigImpl();
+        config.setEnabledForExtensions(true);
+        config.setKeepAliveEnabled(true);
+        server.getXmlRpcServer().setConfig(config);
+        server.start();
+        return server;
+    }
+
+    private class Runner extends Thread {
+        private boolean connectExceptionSeen;
+        private boolean successSeen;
+        private final int port;
+        Runner(int pPort) {
+            port = pPort;
+        }
+        public void run() {
+            for (int i = 0; i < 10; i++) {
+                try {
+                    XmlRpcClient client = new XmlRpcClient();
+                    XmlRpcClientConfigImpl config = new 
XmlRpcClientConfigImpl();
+                    config.setServerURL(new URL("http://127.0.0.1:"; + port  + 
"/"));
+                    client.setConfig(config);
+                    Object[] params = new Object[] {
+                            new Integer(3), new Integer(5)
+                    };
+                    Integer result = (Integer) client.execute("Adder.add", 
params);
+                    assertEquals(8, result.intValue());
+                    successSeen = true;
+                    Thread.sleep(200);
+                } catch (XmlRpcException e) {
+                    Assert.assertTrue(e.getCause() != null  &&  e.getCause() 
instanceof ConnectException);
+                    connectExceptionSeen = true;
+                    break;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    break;
+                }
+            }
+        }
+        boolean isConnectExceptionSeen() { return connectExceptionSeen; }
+        boolean isSuccessSeen() { return successSeen; }
+    }
+
+    /** Tests the web servers shutdown method.
+     */
+    public void testShutdown() throws Exception {
+        final WebServer server = setupServer();
+        final int port = server.getPort();
+        Runner runner = new Runner(port);
+        runner.start();
+        Thread.sleep(700);
+        server.shutdown();
+        runner.join();
+        assertTrue(runner.isSuccessSeen());
+        assertTrue(runner.isConnectExceptionSeen());
+    }
+}

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/WebServerProvider.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/WebServerProvider.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/WebServerProvider.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/WebServerProvider.java
 Wed Oct 11 18:03:54 2006
@@ -67,4 +67,8 @@
        public XmlRpcServer getServer() {
            return webServer.getXmlRpcServer();
     }
+
+       public void shutdown() {
+           webServer.shutdown();
+    }
 }

Modified: 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/XmlRpcTestCase.java
URL: 
http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/XmlRpcTestCase.java?view=diff&rev=463093&r1=463092&r2=463093
==============================================================================
--- 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/XmlRpcTestCase.java
 (original)
+++ 
webservices/xmlrpc/trunk/tests/src/test/java/org/apache/xmlrpc/test/XmlRpcTestCase.java
 Wed Oct 11 18:03:54 2006
@@ -64,7 +64,7 @@
         return mapping;
     }
 
-    protected final ClientProvider[] initProviders(XmlRpcHandlerMapping 
pMapping) throws ServletException, IOException {
+    protected ClientProvider[] initProviders(XmlRpcHandlerMapping pMapping) 
throws ServletException, IOException {
         return new ClientProvider[]{
                 new LocalTransportProvider(pMapping),
                 new LocalStreamTransportProvider(pMapping),
@@ -81,6 +81,14 @@
     public void setUp() throws Exception {
         if (providers == null) {
             providers = initProviders(getHandlerMapping());
+        }
+    }
+
+    public void tearDown() throws Exception {
+        if (providers != null) {
+            for (int i = 0;  i < providers.length;  i++) {
+                providers[i].shutdown();
+            }
         }
     }
 


Reply via email to