You are viewing a plain text version of this content. The canonical link for it is here.
Posted to rpc-dev@xml.apache.org by ae...@apache.org on 2002/10/21 15:08:51 UTC

cvs commit: xml-rpc/xdocs changes.xml

aevers      2002/10/21 06:08:51

  Modified:    src/java/org/apache/xmlrpc DefaultHandlerMapping.java
                        SystemHandler.java XmlRpcRequest.java
                        XmlRpcRequestProcessor.java XmlRpcServer.java
                        XmlRpcWorker.java
               src/test/org/apache/xmlrpc ClientServerRpcTest.java
               xdocs    changes.xml
  Added:       src/java/org/apache/xmlrpc ContextXmlRpcHandler.java
                        DefaultXmlRpcContext.java MultiCall.java
                        XmlRpcContext.java
  Log:
  Add context support for server side handlers, use
  context support to re-implement system handlers.
  Test case for new "system.multicall" handler. (Andrew Evers)
  
  Revision  Changes    Path
  1.2       +2 -1      xml-rpc/src/java/org/apache/xmlrpc/DefaultHandlerMapping.java
  
  Index: DefaultHandlerMapping.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/DefaultHandlerMapping.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DefaultHandlerMapping.java	26 Aug 2002 17:41:57 -0000	1.1
  +++ DefaultHandlerMapping.java	21 Oct 2002 13:08:50 -0000	1.2
  @@ -94,7 +94,8 @@
       public void addHandler(String handlerName, Object handler)
       {
           if (handler instanceof XmlRpcHandler ||
  -                handler instanceof AuthenticatedXmlRpcHandler)
  +                handler instanceof AuthenticatedXmlRpcHandler ||
  +                handler instanceof ContextXmlRpcHandler)
           {
               handlers.put(handlerName, handler);
           }
  
  
  
  1.5       +76 -35    xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java
  
  Index: SystemHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- SystemHandler.java	26 Aug 2002 20:21:51 -0000	1.4
  +++ SystemHandler.java	21 Oct 2002 13:08:50 -0000	1.5
  @@ -55,11 +55,11 @@
    * <http://www.apache.org/>.
    */
   
  -import java.util.*;
  +import java.util.Vector;
   
   /**
  - * Implements the XML-RPC standard system.* methods (such as
  - * <code>system.multicall</code>.
  + * Wraps calls to the XML-RPC standard system.* methods (such as
  + * <code>system.multicall</code>).
    *
    * @author <a href="mailto:adam@megacz.com">Adam Megacz</a>
    * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
  @@ -67,23 +67,46 @@
    * @since 1.2
    */
   public class SystemHandler
  +implements ContextXmlRpcHandler
   {
  -    private XmlRpcHandlerMapping handlerMapping = null;
  +    private DefaultHandlerMapping systemMapping = null;
   
       /**
  +     * Creates a new instance. This instance contains no system calls. Use the
  +     * addDefaultSystemHandlers() method to add the 'default' set of handlers,
  +     * or add handlers manually.
  +     */
  +    public SystemHandler()
  +    {
  +        this.systemMapping = new DefaultHandlerMapping();
  +    }
  +
  +   /**
        * Creates a new instance that delegates calls via the
  -     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}
  +     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}. This
  +     * method will add the system.multicall handler when a non-null
  +     * handlerMapping is specified. The value itself is ignored.
  +     *
  +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
        */
       public SystemHandler(XmlRpcHandlerMapping handlerMapping)
       {
  -        this.handlerMapping = handlerMapping;
  +        this();
  +        if (handlerMapping != null)
  +        {
  +          addDefaultSystemHandlers();
  +        }
       }
   
       /**
        * Creates a new instance that delegates its multicalls via
        * the mapping used by the specified {@link org.apache.xmlrpc.XmlRpcServer}.
  +     * This method will add the default handlers when the specfied server's
  +     * getHandlerMapping() returns a non-null handler mapping.
        *
        * @param server The server to retrieve the XmlRpcHandlerMapping from.
  +     *
  +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
        */
       protected SystemHandler(XmlRpcServer server)
       {
  @@ -91,40 +114,58 @@
       }
   
       /**
  -     * The <code>system.multicall</code> handler performs several RPC
  -     * calls at a time.
  -     *
  -     * @param requests The request containing multiple RPC calls.
  -     * @return The RPC response.
  +     * Add the default system handlers. The default system handlers are:
  +     * <dl>
  +     *  <dt>system.multicall</dt>
  +     *  <dd>Make multiple XML-RPC calls in one request and receive multiple
  +     *  responses.</dd>
  +     * </dl>
  +     */
  +    public void addDefaultSystemHandlers()
  +    {
  +        addSystemHandler("multicall", new MultiCall());
  +    }
  +
  +    /**
  +     * @see org.apache.xmlrpc.DefaultHandlerMapping#addHandler(String, Object)
        */
  -    public Vector multicall(Vector requests)
  +    public void addSystemHandler(String handlerName, ContextXmlRpcHandler handler)
       {
  -        Vector response = new Vector();
  -        XmlRpcRequest request;
  -        for (int i = 0; i < requests.size(); i++)
  +        systemMapping.addHandler(handlerName, handler);
  +    }
  +
  +    /**
  +     * @see org.apache.xmlrpc.DefaultHandlerMapping#removeHandler(String)
  +     */
  +    public void removeSystemHandler(String handlerName)
  +    {
  +        systemMapping.removeHandler(handlerName);
  +    }
  +
  +    /**
  +     * Execute a &lt;ignored&gt;.&lt;name&gt; call by calling the handler for
  +     * &lt;name&gt; in the the system handler mapping.
  +     */
  +    public Object execute(String method, Vector params, XmlRpcContext context)
  +            throws Exception
  +    {
  +        Object handler = null;
  +        String systemMethod = null;
  +        int dot = method.lastIndexOf('.');
  +        if (dot > -1)
           {
  -            try
  -            {
  -                Hashtable call = (Hashtable) requests.elementAt(i);
  -                request = new XmlRpcRequest((String) call.get("methodName"),
  -                                            (Vector) call.get("params"),
  -                                            null, null);
  -                Object handler = handlerMapping.getHandler(request.getMethodName());
  -                Vector v = new Vector();
  -                v.addElement(XmlRpcWorker.invokeHandler(handler, request));
  -                response.addElement(v);
  -            }
  -            catch (Exception x)
  +            // The last portion of the XML-RPC method name is the systen
  +	    // method name. 
  +	    systemMethod = method.substring(dot + 1);
  +
  +            // Add the "." in at the end, the systemMapping will strip it off
  +            handler = systemMapping.getHandler(systemMethod + ".");
  +            if (handler != null)
               {
  -                String message = x.toString();
  -                int code = (x instanceof XmlRpcException ?
  -                            ((XmlRpcException) x).code : 0);
  -                Hashtable h = new Hashtable();
  -                h.put("faultString", message);
  -                h.put("faultCode", new Integer(code));
  -                response.addElement(h);
  +                return ((ContextXmlRpcHandler) handler).execute(systemMethod, params, context);
               }
           }
  -        return response;
  +
  +        throw new NoSuchMethodException("No method '" + method + "' registered.");
       }
   }
  
  
  
  1.3       +2 -16     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java
  
  Index: XmlRpcRequest.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- XmlRpcRequest.java	26 Aug 2002 20:19:22 -0000	1.2
  +++ XmlRpcRequest.java	21 Oct 2002 13:08:50 -0000	1.3
  @@ -61,22 +61,18 @@
    * Encapsulates an XML-RPC request.
    *
    * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
  + * @version $Id$
    * @since 1.2
    */
   public class XmlRpcRequest
   {
       protected final String methodName;
       protected final Vector parameters;
  -    protected final String userName;
  -    protected final String password;
   
  -    public XmlRpcRequest(String methodName, Vector parameters,
  -                         String userName, String password)
  +    public XmlRpcRequest(String methodName, Vector parameters)
       {
           this.parameters = parameters;
           this.methodName = methodName;
  -        this.userName = userName;
  -        this.password = password;
       }
   
       public Vector getParameters()
  @@ -92,15 +88,5 @@
       public String getMethodName()
       {
           return methodName;
  -    }
  -
  -    public String getUserName()
  -    {
  -        return userName;
  -    }
  -
  -    public String getPassword()
  -    {
  -        return password;
       }
   }
  
  
  
  1.3       +2 -18     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequestProcessor.java
  
  Index: XmlRpcRequestProcessor.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequestProcessor.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- XmlRpcRequestProcessor.java	26 Aug 2002 20:22:45 -0000	1.2
  +++ XmlRpcRequestProcessor.java	21 Oct 2002 13:08:50 -0000	1.3
  @@ -80,7 +80,7 @@
       }
   
       /**
  -     * Process an unauthenticated request.
  +     * Process a request.
        *
        * @param is the stream to read the request from.
        * @returns XMLRpcRequest the request.
  @@ -88,21 +88,6 @@
        */
       public XmlRpcRequest processRequest(InputStream is)
       {
  -        return processRequest(is, null, null);
  -    }
  -
  -    /**
  -     * Process an possibly authenticated request.
  -     *
  -     * @param is the stream to read the request from.
  -     * @param user the username (may be null).
  -     * @param password the password (may be null).
  -     * @returns XMLRpcRequest the request.
  -     * @throws ParseFailed if unable to parse the request.
  -     */
  -    public XmlRpcRequest processRequest(InputStream is, String user,
  -                                        String password)
  -    {
           long now = 0;
   
           if (XmlRpc.debug)
  @@ -130,8 +115,7 @@
                   throw new ParseFailed(errorMsg);
               }
   
  -            return new XmlRpcRequest(methodName, (Vector) requestParams.clone(),
  -                                     user, password);
  +            return new XmlRpcRequest(methodName, (Vector) requestParams.clone());
           }
           finally
           {
  
  
  
  1.35      +23 -5     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java
  
  Index: XmlRpcServer.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
  retrieving revision 1.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- XmlRpcServer.java	26 Aug 2002 17:56:21 -0000	1.34
  +++ XmlRpcServer.java	21 Oct 2002 13:08:50 -0000	1.35
  @@ -120,22 +120,35 @@
        * Parse the request and execute the handler method, if one is
        * found. Returns the result as XML.  The calling Java code
        * doesn't need to know whether the call was successful or not
  -     * since this is all packed into the response.
  +     * since this is all packed into the response. No context information
  +     * is passed.
        */
       public byte[] execute(InputStream is)
       {
  -        return execute(is, null, null);
  +        return execute(is, new DefaultXmlRpcContext(null, null, getHandlerMapping()));
       }
   
       /**
        * Parse the request and execute the handler method, if one is
        * found. If the invoked handler is AuthenticatedXmlRpcHandler,
  -     * use the credentials to authenticate the user.
  +     * use the credentials to authenticate the user. No context information
  +     * is passed.
        */
       public byte[] execute(InputStream is, String user, String password)
       {
  +        return execute(is, new DefaultXmlRpcContext(user, password, getHandlerMapping()));
  +    }
  +    
  +    /**
  +     * Parse the request and execute the handler method, if one is
  +     * found. If the invoked handler is AuthenticatedXmlRpcHandler,
  +     * use the credentials to authenticate the user. Context information
  +     * is passed to the worker, and may be passed to the request handler.
  +     */
  +    public byte[] execute(InputStream is, XmlRpcContext context)
  +    {
           XmlRpcWorker worker = getWorker();
  -        byte[] retval = worker.execute(is, user, password);
  +        byte[] retval = worker.execute(is, context);
           pool.push(worker);
           return retval;
       }
  @@ -161,9 +174,14 @@
                   {
                       System.out.println("95% of XML-RPC server threads in use");
                   }
  -                return new XmlRpcWorker(handlerMapping);
  +                return createWorker();
               }
               throw new RuntimeException("System overload");
           }
  +    }
  +
  +    protected XmlRpcWorker createWorker()
  +    {
  +        return new XmlRpcWorker(handlerMapping);
       }
   }
  
  
  
  1.4       +36 -20    xml-rpc/src/java/org/apache/xmlrpc/XmlRpcWorker.java
  
  Index: XmlRpcWorker.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcWorker.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- XmlRpcWorker.java	27 Sep 2002 17:20:06 -0000	1.3
  +++ XmlRpcWorker.java	21 Oct 2002 13:08:50 -0000	1.4
  @@ -91,12 +91,13 @@
        *
        * @param handler the handler to call.
        * @param request the request information to use.
  +     * @param context the context information to use.
        * @return Object the result of calling the handler.
        * @throws ClassCastException if the handler is not of an appropriate type.
        * @throws NullPointerException if the handler is null.
        * @throws Exception if the handler throws an exception.
        */
  -    protected static Object invokeHandler(Object handler, XmlRpcRequest request)
  +    protected static Object invokeHandler(Object handler, XmlRpcRequest request, XmlRpcContext context)
           throws Exception
       {
           long now = 0;
  @@ -112,6 +113,11 @@
                 throw new NullPointerException
                     ("Null handler passed to XmlRpcWorker.invokeHandler");
               }
  +            else if (handler instanceof ContextXmlRpcHandler)
  +            {
  +                return ((ContextXmlRpcHandler) handler).execute
  +                    (request.getMethodName(), request.getParameters(), context);
  +            }
               else if (handler instanceof XmlRpcHandler)
               {
                   return ((XmlRpcHandler) handler).execute
  @@ -119,20 +125,9 @@
               }
               else if (handler instanceof AuthenticatedXmlRpcHandler)
               {
  -                // If HTTP authentication is in use, XML-RPC must
  -                // return a 401 HTTP status code when no user name is
  -                // supplied.  This provides authentication meta data
  -                // and tells clients to provide authentication on
  -                // subsequent requests.
  -                String userName = request.getUserName();
  -                if (userName == null || userName.length() == 0)
  -                {
  -                    throw new AuthenticationFailed
  -                        ("No user name provided for HTTP authentication");
  -                }
                   return ((AuthenticatedXmlRpcHandler) handler)
                       .execute(request.getMethodName(), request.getParameters(),
  -                             request.getUserName(), request.getPassword());
  +                             context.getUserName(), context.getPassword());
               }
               else
               {
  @@ -153,18 +148,27 @@
   
       /**
        * Decode, process and encode the response or exception for an XML-RPC
  -     * request.
  +     * request. This method executes the handler method with the default context.
  +     */
  +    public byte[] execute(InputStream is, String user, String password)
  +    {
  +        return execute(is, defaultContext(user, password));
  +    }
  +
  +    /**
  +     * Decode, process and encode the response or exception for an XML-RPC
  +     * request. This method executes will pass the specified context to the
  +     * handler if the handler supports context.
        *
        * @param is the InputStream to read the request from.
  -     * @param user the user name (may be null).
  -     * @param password the password (may be null).
  +     * @param context the context for the request (may be null).
        * @return byte[] the response.
        * @throws org.apache.xmlrpc.ParseFailed if the request could not be parsed.
        * @throws org.apache.xmlrpc.AuthenticationFailed if the handler for the
        * specific method required authentication and insufficient credentials were
        * supplied.
        */
  -    public byte[] execute(InputStream is, String user, String password)
  +    public byte[] execute(InputStream is, XmlRpcContext context)
       {
           long now = 0;
   
  @@ -175,11 +179,10 @@
   
           try
           {
  -            XmlRpcRequest request =
  -                requestProcessor.processRequest(is, user, password);
  +            XmlRpcRequest request = requestProcessor.processRequest(is);
               Object handler = handlerMapping.getHandler(request.
                                                          getMethodName());
  -            Object response = invokeHandler(handler, request);
  +            Object response = invokeHandler(handler, request, context);
               return responseProcessor.processResponse
                   (response, requestProcessor.getEncoding());
           }
  @@ -208,5 +211,18 @@
                                      + " millis in request/process/response");
               }
           }
  +    }
  +
  +    /**
  +     * Factory method to return a default context object for the execute() method.
  +     * This method can be overridden to return a custom sub-class of XmlRpcContext.
  +     *
  +     * @param user the username of the user making the request.
  +     * @param password the password of the user making the request.
  +     * @return XmlRpcContext the context for the reqeust.
  +     */
  +    protected XmlRpcContext defaultContext(String user, String password)
  +    {
  +        return new DefaultXmlRpcContext(user, password, handlerMapping);
       }
   }
  
  
  
  1.1                  xml-rpc/src/java/org/apache/xmlrpc/ContextXmlRpcHandler.java
  
  Index: ContextXmlRpcHandler.java
  ===================================================================
  package org.apache.xmlrpc;
  
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "XML-RPC" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.util.Vector;
  
  /**
   * An XML-RPC handler that also handles user authentication.
   *
   * @author <a href="mailto:hannes@apache.org">Hannes Wallnoefer</a>
   * @see org.apache.xmlrpc.AuthenticationFailed
   * @version $Id: ContextXmlRpcHandler.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
   * @since 1.2
   */
  public interface ContextXmlRpcHandler
  {
      /**
       * Return the result, or throw an Exception if something went wrong.
       *
       * @throws AuthenticationFailed If authentication fails, an
       * exception of this type must be thrown.
       * @see org.apache.xmlrpc.AuthenticationFailed
       */
      public Object execute(String method, Vector params, XmlRpcContext context)
              throws Exception;
  }
  
  
  
  1.1                  xml-rpc/src/java/org/apache/xmlrpc/DefaultXmlRpcContext.java
  
  Index: DefaultXmlRpcContext.java
  ===================================================================
  package org.apache.xmlrpc;
  
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "XML-RPC" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /**
   * A basic context object that stores the userName, password and
   * handler mapping.
   *
   * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
   * @version $Id: DefaultXmlRpcContext.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
   * @since 1.2
   */
  public class DefaultXmlRpcContext
  implements XmlRpcContext
  {
      protected String userName, password;
      protected XmlRpcHandlerMapping handlerMapping;
  
      public DefaultXmlRpcContext(String userName, String password, XmlRpcHandlerMapping handlerMapping)
      {
          this.userName = userName;
          this.password = password;
          this.handlerMapping = handlerMapping;
      }
  
      public String getUserName()
      {
          return userName;
      }
  
      public String getPassword()
      {
          return password;
      }
  
      public XmlRpcHandlerMapping getHandlerMapping()
      {
          return handlerMapping;
      }
  }
  
  
  
  1.1                  xml-rpc/src/java/org/apache/xmlrpc/MultiCall.java
  
  Index: MultiCall.java
  ===================================================================
  package org.apache.xmlrpc;
  
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright(c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation(http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "XML-RPC" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.util.Hashtable;
  import java.util.Vector;
  
  /**
   * The <code>system.multicall</code> handler performs several RPC
   * calls at a time.
   *
   * @author <a href="mailto:adam@megacz.com">Adam Megacz</a>
   * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
   * @version $Id: MultiCall.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
   * @since 1.2
   */
  public class MultiCall
  implements ContextXmlRpcHandler
  {
      public Object execute(String method, Vector params, XmlRpcContext context)
              throws Exception
      {
          if ("multicall".equals(method))
          {
              return multicall(params, context);
          }
  
          throw new NoSuchMethodException("No method '" + method + "' in " + this.getClass().getName());
      }
  
      public Vector multicall(Vector requests, XmlRpcContext context)
      {
          Vector response = new Vector();
          XmlRpcRequest request;
          for (int i = 0; i < requests.size(); i++)
          {
              try
              {
                  Hashtable call = (Hashtable) requests.elementAt(i);
                  request = new XmlRpcRequest((String) call.get("methodName"),
                                              (Vector) call.get("params"));
                  Object handler = context.getHandlerMapping().getHandler(request.getMethodName());
                  Vector v = new Vector();
                  v.addElement(XmlRpcWorker.invokeHandler(handler, request, context));
                  response.addElement(v);
              }
              catch (Exception x)
              {
                  String message = x.toString();
                  int code = (x instanceof XmlRpcException ?
                              ((XmlRpcException) x).code : 0);
                  Hashtable h = new Hashtable();
                  h.put("faultString", message);
                  h.put("faultCode", new Integer(code));
                  response.addElement(h);
              }
          }
          return response;
      }
  }
  
  
  
  1.1                  xml-rpc/src/java/org/apache/xmlrpc/XmlRpcContext.java
  
  Index: XmlRpcContext.java
  ===================================================================
  package org.apache.xmlrpc;
  
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "XML-RPC" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /**
   * The minimal context that an XML-RPC request will occur in.
   *
   * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
   * @version $Id: XmlRpcContext.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
   * @since 1.2
   */
  public interface XmlRpcContext
  {
      /**
       * Get the username specified in the outer request.
       *
       * @returns the username (may be null).
       */
      public String getUserName();
  
      /**
       * Get the password specified in the outer request.
       *
       * @returns the password (may be null).
       */
      public String getPassword();
  
      /**
       * Get the XML-RPC handler mapping for the server handling the request.
       *
       * @returns the handler mapping (may be null).
       */
      public XmlRpcHandlerMapping getHandlerMapping();
  }
  
  
  
  1.13      +49 -4     xml-rpc/src/test/org/apache/xmlrpc/ClientServerRpcTest.java
  
  Index: ClientServerRpcTest.java
  ===================================================================
  RCS file: /home/cvs/xml-rpc/src/test/org/apache/xmlrpc/ClientServerRpcTest.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- ClientServerRpcTest.java	10 Oct 2002 00:22:44 -0000	1.12
  +++ ClientServerRpcTest.java	21 Oct 2002 13:08:51 -0000	1.13
  @@ -62,6 +62,7 @@
   import java.net.InetAddress;
   import java.net.UnknownHostException;
   import java.util.Vector;
  +import java.util.Hashtable;
   
   import junit.framework.Test;
   import junit.framework.TestCase;
  @@ -103,6 +104,11 @@
       private static final String REQUEST_PARAM_VALUE = "foobar";
   
       /**
  +     * The number of calls to batch in the multicall.
  +     */
  +    private static final int NUM_MULTICALLS = 10;
  +
  +    /**
        * The value to use in our request parameter.
        */
       private static final String REQUEST_PARAM_XML =
  @@ -159,10 +165,14 @@
               fail(e.toString());
           }
   
  -        // WebServer (contains its own XmlRpcServer instance, binds to
  -        // INADDR_ANY)
  -        webServer = new WebServer(SERVER_PORT);
  +        // Setup system handler
  +        SystemHandler webServerSysHandler = new SystemHandler();
  +        webServerSysHandler.addSystemHandler("multicall", new MultiCall());
  +
  +        // WebServer (contains its own XmlRpcServer instance)
  +        webServer = new WebServer(SERVER_PORT, localhost);
           webServer.addHandler(HANDLER_NAME, new TestHandler());
  +        webServer.addHandler("system", webServerSysHandler);
   
           // XML-RPC client(s)
           try
  @@ -269,6 +279,41 @@
           }
       }
   
  +    public void testSystemMultiCall()
  +    {
  +        try
  +        {
  +            Vector calls = new Vector();
  +
  +            for (int i = 0; i < NUM_MULTICALLS; i++)
  +            {
  +                Hashtable call = new Hashtable();
  +                Vector params = new Vector();
  +
  +                params.add(REQUEST_PARAM_VALUE + i);
  +                call.put("methodName", HANDLER_NAME + ".echo");
  +                call.put("params", params);
  + 
  +                calls.addElement(call);
  +            }
  +
  +            Object response = client.execute("system.multicall", calls);
  +
  +            for (int i = 0; i < NUM_MULTICALLS; i++)
  +            {
  +               Vector result = new Vector();
  +               result.add(REQUEST_PARAM_VALUE + i);
  +
  +               assertEquals(result, ((Vector)response).elementAt(i));
  +            }
  +        }
  +        catch (Exception e)
  +        {
  +            e.printStackTrace();
  +            fail(e.getMessage());
  +        }
  +    }   
  + 
       protected class TestHandler
       {
           public String echo(String message)
  
  
  
  1.15      +13 -0     xml-rpc/xdocs/changes.xml
  
  Index: changes.xml
  ===================================================================
  RCS file: /home/cvs/xml-rpc/xdocs/changes.xml,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- changes.xml	27 Sep 2002 20:01:54 -0000	1.14
  +++ changes.xml	21 Oct 2002 13:08:51 -0000	1.15
  @@ -14,6 +14,19 @@
           <ul>
   
             <li>
  +            <strong>21 Oct 2002</strong>
  +            <ul>
  +
  +              <li>
  +                Add context support for server side handlers, use
  +                context support to re-implement system handlers.
  +                Test case for new "system.multicall" handler. (Andrew Evers)
  +              </li>
  +
  +            </ul>
  +          </li>
  +
  +          <li>
               <strong>27 Sep 2002</strong>
               <ul>
   
  
  
  

Re: cvs commit: xml-rpc/xdocs changes.xml

Posted by Daniel Rall <dl...@finemaltcoding.com>.
aevers@apache.org writes:

> aevers      2002/10/21 06:08:51
> 
>   Modified:    src/java/org/apache/xmlrpc DefaultHandlerMapping.java
>                         SystemHandler.java XmlRpcRequest.java
>                         XmlRpcRequestProcessor.java XmlRpcServer.java
>                         XmlRpcWorker.java
>                src/test/org/apache/xmlrpc ClientServerRpcTest.java
>                xdocs    changes.xml
>   Added:       src/java/org/apache/xmlrpc ContextXmlRpcHandler.java
>                         DefaultXmlRpcContext.java MultiCall.java
>                         XmlRpcContext.java
>   Log:
>   Add context support for server side handlers, use
>   context support to re-implement system handlers.
>   Test case for new "system.multicall" handler. (Andrew Evers)

Andrew, thanks for checking in this code.  Sorry it's taken me so long
to get to it.  Comments inline.

>   1.5       +76 -35    xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java
>   
>   Index: SystemHandler.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java,v
>   retrieving revision 1.4
>   retrieving revision 1.5
>   diff -u -r1.4 -r1.5
>   --- SystemHandler.java	26 Aug 2002 20:21:51 -0000	1.4
>   +++ SystemHandler.java	21 Oct 2002 13:08:50 -0000	1.5
>   @@ -55,11 +55,11 @@
>     * <http://www.apache.org/>.
>     */
>    
>   -import java.util.*;
>   +import java.util.Vector;
>    
>    /**
>   - * Implements the XML-RPC standard system.* methods (such as
>   - * <code>system.multicall</code>.
>   + * Wraps calls to the XML-RPC standard system.* methods (such as
>   + * <code>system.multicall</code>).
>     *
>     * @author <a href="mailto:adam@megacz.com">Adam Megacz</a>
>     * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
>   @@ -67,23 +67,46 @@
>     * @since 1.2
>     */
>    public class SystemHandler
>   +implements ContextXmlRpcHandler

Some indentation to indicate the continuation of the declaration makes
this easier to read (and is more consistent with the formatting in the
rest of the code).

>    {
>   -    private XmlRpcHandlerMapping handlerMapping = null;
>   +    private DefaultHandlerMapping systemMapping = null;

Can we avoid making the type of this reference a concretion instead of
an interface?  Perhaps the add/remove operations should be part of the
XmlRpcHandlerMapping interface?

>        /**
>   +     * Creates a new instance. This instance contains no system calls. Use the
>   +     * addDefaultSystemHandlers() method to add the 'default' set of handlers,
>   +     * or add handlers manually.
>   +     */
>   +    public SystemHandler()
>   +    {
>   +        this.systemMapping = new DefaultHandlerMapping();
>   +    }
>   +
>   +   /**
>         * Creates a new instance that delegates calls via the
>   -     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}
>   +     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}. This
>   +     * method will add the system.multicall handler when a non-null
>   +     * handlerMapping is specified. The value itself is ignored.
>   +     *
>   +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
>         */
>        public SystemHandler(XmlRpcHandlerMapping handlerMapping)
>        {
>   -        this.handlerMapping = handlerMapping;
>   +        this();
>   +        if (handlerMapping != null)
>   +        {
>   +          addDefaultSystemHandlers();
>   +        }
>        }

A four character indent is used throughout the source.

The handlerMapping parameter to the constructor which takes a
XmlRpcHandlerMapping is now never used, which is at odds with the
documentation.

>        /**
>         * Creates a new instance that delegates its multicalls via
>         * the mapping used by the specified {@link org.apache.xmlrpc.XmlRpcServer}.
>   +     * This method will add the default handlers when the specfied server's
>   +     * getHandlerMapping() returns a non-null handler mapping.
>         *
>         * @param server The server to retrieve the XmlRpcHandlerMapping from.
>   +     *
>   +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
>         */
>        protected SystemHandler(XmlRpcServer server)
>        {
>   @@ -91,40 +114,58 @@
>        }
>    
>        /**
>   -     * The <code>system.multicall</code> handler performs several RPC
>   -     * calls at a time.
>   -     *
>   -     * @param requests The request containing multiple RPC calls.
>   -     * @return The RPC response.
>   +     * Add the default system handlers. The default system handlers are:
>   +     * <dl>
>   +     *  <dt>system.multicall</dt>
>   +     *  <dd>Make multiple XML-RPC calls in one request and receive multiple
>   +     *  responses.</dd>
>   +     * </dl>
>   +     */
>   +    public void addDefaultSystemHandlers()
>   +    {
>   +        addSystemHandler("multicall", new MultiCall());
>   +    }

Does the addDefaultSystemHandlers() method really need to be public?
It's called by at least one of the constructors -- why not by both?

>   1.3       +2 -16     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java
>   
>   Index: XmlRpcRequest.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java,v
>   retrieving revision 1.2
>   retrieving revision 1.3
>   diff -u -r1.2 -r1.3
>   --- XmlRpcRequest.java	26 Aug 2002 20:19:22 -0000	1.2
>   +++ XmlRpcRequest.java	21 Oct 2002 13:08:50 -0000	1.3
>   @@ -61,22 +61,18 @@
>     * Encapsulates an XML-RPC request.
>     *
>     * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
>   + * @version $Id$

I really don't like CVS tokens.  IMHO, they unnecessarilly complicate
merging between branches and accepting patches (uh-humm ;).

>   1.35      +23 -5     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java
>   
>   Index: XmlRpcServer.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
>   retrieving revision 1.34
>   retrieving revision 1.35
>   diff -u -r1.34 -r1.35
>   --- XmlRpcServer.java	26 Aug 2002 17:56:21 -0000	1.34
>   +++ XmlRpcServer.java	21 Oct 2002 13:08:50 -0000	1.35
>   @@ -120,22 +120,35 @@
>         * Parse the request and execute the handler method, if one is
>         * found. Returns the result as XML.  The calling Java code
>         * doesn't need to know whether the call was successful or not
>   -     * since this is all packed into the response.
>   +     * since this is all packed into the response. No context information
>   +     * is passed.
>         */
>        public byte[] execute(InputStream is)
>        {
>   -        return execute(is, null, null);
>   +        return execute(is, new DefaultXmlRpcContext(null, null, getHandlerMapping()));
>        }
>
>        /**
>         * Parse the request and execute the handler method, if one is
>         * found. If the invoked handler is AuthenticatedXmlRpcHandler,
>   -     * use the credentials to authenticate the user.
>   +     * use the credentials to authenticate the user. No context information
>   +     * is passed.
>         */
>        public byte[] execute(InputStream is, String user, String password)
>        {
>   +        return execute(is, new DefaultXmlRpcContext(user, password, getHandlerMapping()));
>   +    }

Will you explain why the comments for the previous two methods say "No
context information is passed" when I see a context created
internally?

>   @@ -208,5 +211,18 @@
>                                       + " millis in request/process/response");
>                }
>            }
>   +    }
>   +
>   +    /**
>   +     * Factory method to return a default context object for the execute() method.
>   +     * This method can be overridden to return a custom sub-class of XmlRpcContext.
>   +     *
>   +     * @param user the username of the user making the request.
>   +     * @param password the password of the user making the request.
>   +     * @return XmlRpcContext the context for the reqeust.
>   +     */
>   +    protected XmlRpcContext defaultContext(String user, String password)
>   +    {
>   +        return new DefaultXmlRpcContext(user, password, handlerMapping);
>        }
>    }

I like to use the verbNoun method naming scheme.  I realize that
"default" could be used as a verb, but it is a little ambiguous.
Anyone got a better name for this one.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/ContextXmlRpcHandler.java
>   
>   Index: ContextXmlRpcHandler.java
...
>   /**
>    * An XML-RPC handler that also handles user authentication.
>    *
>    * @author <a href="mailto:hannes@apache.org">Hannes Wallnoefer</a>
>    * @see org.apache.xmlrpc.AuthenticationFailed
>    * @version $Id: ContextXmlRpcHandler.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
>    * @since 1.2
>    */
>   public interface ContextXmlRpcHandler
>   {
>       /**
>        * Return the result, or throw an Exception if something went wrong.
>        *
>        * @throws AuthenticationFailed If authentication fails, an
>        * exception of this type must be thrown.
>        * @see org.apache.xmlrpc.AuthenticationFailed
>        */
>       public Object execute(String method, Vector params, XmlRpcContext context)
>               throws Exception;
>   }

After reading the documentation for this class, I'm not exactly sure
what this it does.  The docs don't match up to the API.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/DefaultXmlRpcContext.java
>   
>   Index: DefaultXmlRpcContext.java
...
>   public class DefaultXmlRpcContext
>   implements XmlRpcContext

Formatting.

>   {
>       protected String userName, password;

One decl per line definitely is preferred for instance fields.
JavaDoc should be supplied for fields like this which have visibility
external to the package.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/MultiCall.java
>   
>   Index: MultiCall.java
>   public class MultiCall
>   implements ContextXmlRpcHandler

Formatting.

>   1.13      +49 -4     xml-rpc/src/test/org/apache/xmlrpc/ClientServerRpcTest.java
>   
>   Index: ClientServerRpcTest.java

Yay unit tests!!

- Dan

Re: cvs commit: xml-rpc/xdocs changes.xml

Posted by Daniel Rall <dl...@finemaltcoding.com>.
aevers@apache.org writes:

> aevers      2002/10/21 06:08:51
> 
>   Modified:    src/java/org/apache/xmlrpc DefaultHandlerMapping.java
>                         SystemHandler.java XmlRpcRequest.java
>                         XmlRpcRequestProcessor.java XmlRpcServer.java
>                         XmlRpcWorker.java
>                src/test/org/apache/xmlrpc ClientServerRpcTest.java
>                xdocs    changes.xml
>   Added:       src/java/org/apache/xmlrpc ContextXmlRpcHandler.java
>                         DefaultXmlRpcContext.java MultiCall.java
>                         XmlRpcContext.java
>   Log:
>   Add context support for server side handlers, use
>   context support to re-implement system handlers.
>   Test case for new "system.multicall" handler. (Andrew Evers)

Andrew, thanks for checking in this code.  Sorry it's taken me so long
to get to it.  Comments inline.

>   1.5       +76 -35    xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java
>   
>   Index: SystemHandler.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/SystemHandler.java,v
>   retrieving revision 1.4
>   retrieving revision 1.5
>   diff -u -r1.4 -r1.5
>   --- SystemHandler.java	26 Aug 2002 20:21:51 -0000	1.4
>   +++ SystemHandler.java	21 Oct 2002 13:08:50 -0000	1.5
>   @@ -55,11 +55,11 @@
>     * <http://www.apache.org/>.
>     */
>    
>   -import java.util.*;
>   +import java.util.Vector;
>    
>    /**
>   - * Implements the XML-RPC standard system.* methods (such as
>   - * <code>system.multicall</code>.
>   + * Wraps calls to the XML-RPC standard system.* methods (such as
>   + * <code>system.multicall</code>).
>     *
>     * @author <a href="mailto:adam@megacz.com">Adam Megacz</a>
>     * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
>   @@ -67,23 +67,46 @@
>     * @since 1.2
>     */
>    public class SystemHandler
>   +implements ContextXmlRpcHandler

Some indentation to indicate the continuation of the declaration makes
this easier to read (and is more consistent with the formatting in the
rest of the code).

>    {
>   -    private XmlRpcHandlerMapping handlerMapping = null;
>   +    private DefaultHandlerMapping systemMapping = null;

Can we avoid making the type of this reference a concretion instead of
an interface?  Perhaps the add/remove operations should be part of the
XmlRpcHandlerMapping interface?

>        /**
>   +     * Creates a new instance. This instance contains no system calls. Use the
>   +     * addDefaultSystemHandlers() method to add the 'default' set of handlers,
>   +     * or add handlers manually.
>   +     */
>   +    public SystemHandler()
>   +    {
>   +        this.systemMapping = new DefaultHandlerMapping();
>   +    }
>   +
>   +   /**
>         * Creates a new instance that delegates calls via the
>   -     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}
>   +     * specified {@link org.apache.xmlrpc.XmlRpcHandlerMapping}. This
>   +     * method will add the system.multicall handler when a non-null
>   +     * handlerMapping is specified. The value itself is ignored.
>   +     *
>   +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
>         */
>        public SystemHandler(XmlRpcHandlerMapping handlerMapping)
>        {
>   -        this.handlerMapping = handlerMapping;
>   +        this();
>   +        if (handlerMapping != null)
>   +        {
>   +          addDefaultSystemHandlers();
>   +        }
>        }

A four character indent is used throughout the source.

The handlerMapping parameter to the constructor which takes a
XmlRpcHandlerMapping is now never used, which is at odds with the
documentation.

>        /**
>         * Creates a new instance that delegates its multicalls via
>         * the mapping used by the specified {@link org.apache.xmlrpc.XmlRpcServer}.
>   +     * This method will add the default handlers when the specfied server's
>   +     * getHandlerMapping() returns a non-null handler mapping.
>         *
>         * @param server The server to retrieve the XmlRpcHandlerMapping from.
>   +     *
>   +     * @deprecated use new SystemHandler() and addDefaultSystemHandlers() instead.
>         */
>        protected SystemHandler(XmlRpcServer server)
>        {
>   @@ -91,40 +114,58 @@
>        }
>    
>        /**
>   -     * The <code>system.multicall</code> handler performs several RPC
>   -     * calls at a time.
>   -     *
>   -     * @param requests The request containing multiple RPC calls.
>   -     * @return The RPC response.
>   +     * Add the default system handlers. The default system handlers are:
>   +     * <dl>
>   +     *  <dt>system.multicall</dt>
>   +     *  <dd>Make multiple XML-RPC calls in one request and receive multiple
>   +     *  responses.</dd>
>   +     * </dl>
>   +     */
>   +    public void addDefaultSystemHandlers()
>   +    {
>   +        addSystemHandler("multicall", new MultiCall());
>   +    }

Does the addDefaultSystemHandlers() method really need to be public?
It's called by at least one of the constructors -- why not by both?

>   1.3       +2 -16     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java
>   
>   Index: XmlRpcRequest.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcRequest.java,v
>   retrieving revision 1.2
>   retrieving revision 1.3
>   diff -u -r1.2 -r1.3
>   --- XmlRpcRequest.java	26 Aug 2002 20:19:22 -0000	1.2
>   +++ XmlRpcRequest.java	21 Oct 2002 13:08:50 -0000	1.3
>   @@ -61,22 +61,18 @@
>     * Encapsulates an XML-RPC request.
>     *
>     * @author <a href="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
>   + * @version $Id$

I really don't like CVS tokens.  IMHO, they unnecessarilly complicate
merging between branches and accepting patches (uh-humm ;).

>   1.35      +23 -5     xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java
>   
>   Index: XmlRpcServer.java
>   ===================================================================
>   RCS file: /home/cvs/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
>   retrieving revision 1.34
>   retrieving revision 1.35
>   diff -u -r1.34 -r1.35
>   --- XmlRpcServer.java	26 Aug 2002 17:56:21 -0000	1.34
>   +++ XmlRpcServer.java	21 Oct 2002 13:08:50 -0000	1.35
>   @@ -120,22 +120,35 @@
>         * Parse the request and execute the handler method, if one is
>         * found. Returns the result as XML.  The calling Java code
>         * doesn't need to know whether the call was successful or not
>   -     * since this is all packed into the response.
>   +     * since this is all packed into the response. No context information
>   +     * is passed.
>         */
>        public byte[] execute(InputStream is)
>        {
>   -        return execute(is, null, null);
>   +        return execute(is, new DefaultXmlRpcContext(null, null, getHandlerMapping()));
>        }
>
>        /**
>         * Parse the request and execute the handler method, if one is
>         * found. If the invoked handler is AuthenticatedXmlRpcHandler,
>   -     * use the credentials to authenticate the user.
>   +     * use the credentials to authenticate the user. No context information
>   +     * is passed.
>         */
>        public byte[] execute(InputStream is, String user, String password)
>        {
>   +        return execute(is, new DefaultXmlRpcContext(user, password, getHandlerMapping()));
>   +    }

Will you explain why the comments for the previous two methods say "No
context information is passed" when I see a context created
internally?

>   @@ -208,5 +211,18 @@
>                                       + " millis in request/process/response");
>                }
>            }
>   +    }
>   +
>   +    /**
>   +     * Factory method to return a default context object for the execute() method.
>   +     * This method can be overridden to return a custom sub-class of XmlRpcContext.
>   +     *
>   +     * @param user the username of the user making the request.
>   +     * @param password the password of the user making the request.
>   +     * @return XmlRpcContext the context for the reqeust.
>   +     */
>   +    protected XmlRpcContext defaultContext(String user, String password)
>   +    {
>   +        return new DefaultXmlRpcContext(user, password, handlerMapping);
>        }
>    }

I like to use the verbNoun method naming scheme.  I realize that
"default" could be used as a verb, but it is a little ambiguous.
Anyone got a better name for this one.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/ContextXmlRpcHandler.java
>   
>   Index: ContextXmlRpcHandler.java
...
>   /**
>    * An XML-RPC handler that also handles user authentication.
>    *
>    * @author <a href="mailto:hannes@apache.org">Hannes Wallnoefer</a>
>    * @see org.apache.xmlrpc.AuthenticationFailed
>    * @version $Id: ContextXmlRpcHandler.java,v 1.1 2002/10/21 13:08:50 aevers Exp $
>    * @since 1.2
>    */
>   public interface ContextXmlRpcHandler
>   {
>       /**
>        * Return the result, or throw an Exception if something went wrong.
>        *
>        * @throws AuthenticationFailed If authentication fails, an
>        * exception of this type must be thrown.
>        * @see org.apache.xmlrpc.AuthenticationFailed
>        */
>       public Object execute(String method, Vector params, XmlRpcContext context)
>               throws Exception;
>   }

After reading the documentation for this class, I'm not exactly sure
what this it does.  The docs don't match up to the API.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/DefaultXmlRpcContext.java
>   
>   Index: DefaultXmlRpcContext.java
...
>   public class DefaultXmlRpcContext
>   implements XmlRpcContext

Formatting.

>   {
>       protected String userName, password;

One decl per line definitely is preferred for instance fields.
JavaDoc should be supplied for fields like this which have visibility
external to the package.

>   1.1                  xml-rpc/src/java/org/apache/xmlrpc/MultiCall.java
>   
>   Index: MultiCall.java
>   public class MultiCall
>   implements ContextXmlRpcHandler

Formatting.

>   1.13      +49 -4     xml-rpc/src/test/org/apache/xmlrpc/ClientServerRpcTest.java
>   
>   Index: ClientServerRpcTest.java

Yay unit tests!!

- Dan