Hi - I've discovered three issues in the 2.0 branch of the XML-RPC libraries, which are solved by this series of patches (which can be applied independently, without dependency on one another): Problems verified on version 2.0.1 of the Apache XML-RPC libraries, but were also present in version 2.0 (so not a regression, per se).
Hope this helps and thanks for your time, Elizabeth Fong Intern software engineer, Three Rings Design http://www.threerings.net Fix issue with NoSuchElementException being thrown after each request (tested by using XmlRpcClient) --- src/java/org/apache/xmlrpc/WebServer.java (revision 394582) +++ src/java/org/apache/xmlrpc/WebServer.java (working copy) @@ -719,6 +720,10 @@ // tokenize first line of HTTP request StringTokenizer tokens = new StringTokenizer(line); + if (!tokens.hasMoreElements()) + { + continue; + } String method = tokens.nextToken(); String uri = tokens.nextToken(); String httpVersion = tokens.nextToken(); Properly detect and bail out when a keepalive socket connection is closed, instead of instantiating new empty Strings each time readLine() is called. If keepalive is on and the connection is closed, then keepalive cannot be set to off and readLine() is called in an infinite loop. This behavior resulted in extremely frequent garbage collection until I applied the patch. --- src/java/org/apache/xmlrpc/WebServer.java (revision 394582) +++ src/java/org/apache/xmlrpc/WebServer.java (working copy @@ -19,6 +19,7 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.EOFException; import java.io.IOException; import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; @@ -776,6 +781,9 @@ } while (keepAlive); } + catch (EOFException ignore) + { + } catch (Exception exception) { if (XmlRpc.debug) @@ -818,6 +823,10 @@ for (;;) { next = input.read(); + if (count == 0 && next < 0) + { + throw new EOFException("Connection closed"); + } if (next < 0 || next == '\n') { break; Support using all Collections and Maps, not just Vectors and Hashtables. There's no need to specify that return types be specific when we can be more generic - all we're doing is iterating through the collection/map elements and stuffing them in the response, and the specific implementation doesn't matter. --- src/java/org/apache/xmlrpc/XmlWriter.java (revision 394582) +++ src/java/org/apache/xmlrpc/XmlWriter.java (working copy) @@ -21,11 +21,11 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.util.Collection; import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; import java.util.Properties; -import java.util.Vector; import org.apache.xmlrpc.util.DateTool; import org.apache.commons.codec.binary.Base64; @@ -286,27 +286,29 @@ endElement("data"); endElement("array"); } - else if (obj instanceof Vector) + else if (obj instanceof Collection) { startElement("array"); startElement("data"); - Vector array = (Vector) obj; - int size = array.size(); - for (int i = 0; i < size; i++) + Collection array = (Collection)obj; + Iterator it = array.iterator(); + while (it.hasNext()) { - writeObject(array.elementAt(i)); + writeObject(it.next()); } endElement("data"); endElement("array"); } - else if (obj instanceof Hashtable) + else if (obj instanceof Map) { startElement("struct"); - Hashtable struct = (Hashtable) obj; - for (Enumeration e = struct.keys(); e.hasMoreElements(); ) + Map struct = (Map)obj; + Iterator it = struct.entrySet().iterator(); + while (it.hasNext()) { - String key = (String) e.nextElement(); - Object value = struct.get(key); + Map.Entry entry = (Map.Entry)it.next(); + String key = (String)entry.getKey(); + Object value = entry.getValue(); startElement("member"); startElement("name"); chardata(key);