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 Adam Megacz <ad...@megacz.com> on 2002/08/14 06:27:03 UTC

system.multicall()

Here's the patch for system.multicall(), plus a new file it adds
(SystemMethods.java). This patch also includes my last patch for HTTP
Basic authentication.

  - a

______________________________________________________________________________
org/apache/xmlrpc/SystemMethods.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 org.apache.xmlrpc.*;
import java.util.*;

/** Implements the XML-RPC standard system.* methods */
public class SystemMethods {

    XmlRpcServer serv = null;

    SystemMethods(XmlRpcServer serv) { this.serv = serv; }

    public Vector multicall(Vector in) {
        Vector ret = new Vector();
        for(int i=0; i<in.size(); i++) {
            try {
                Hashtable call = (Hashtable)in.elementAt(i);
                String methodName = (String)call.get("methodName");
                Vector params = (Vector)call.get("params");
                Object handler = serv.getHandler(methodName);
                Vector v = new Vector();
                v.addElement(serv.invokeHandler(handler, methodName, params, null, null));
                ret.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));
                ret.addElement(h);
            }
        }
        return ret;
    }
    
}




______________________________________________________________________________
patch

Index: src/java/org/apache/xmlrpc/WebServer.java
===================================================================
RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/WebServer.java,v
retrieving revision 1.13
diff -u -r1.13 WebServer.java
--- src/java/org/apache/xmlrpc/WebServer.java	13 Aug 2002 22:27:16 -0000	1.13
+++ src/java/org/apache/xmlrpc/WebServer.java	14 Aug 2002 04:24:39 -0000
@@ -94,6 +94,7 @@
     protected static final byte[] conclose = "Connection: close\r\n".getBytes();
     protected static final byte[] ok = " 200 OK\r\n".getBytes();
     protected static final byte[] server = "Server: Apache XML-RPC 1.0\r\n".getBytes();
+    protected static final byte[] www_authenticate = "WWW-Authenticate: Basic realm=XMLRPC\r\n".getBytes();
 
     private static final String HTTP_11 = "HTTP/1.1";
     private static final String STAR = "*";
@@ -584,29 +585,40 @@
                     {
                         ServerInputStream sin = new ServerInputStream(input,
                                 contentLength);
-                        byte result[] = xmlrpc.execute(sin, user, password);
-                        output.write(httpversion.getBytes());
-                        output.write(ok);
-                        output.write(server);
-                        if (keepalive)
-                        {
-                            output.write(conkeep);
-                        }
-                        else
-                        {
-                            output.write (conclose);
+                        try {
+                            byte result[] = xmlrpc.execute(sin, user, password);
+                            output.write(httpversion.getBytes());
+                            output.write(ok);
+                            output.write(server);
+                            if (keepalive)
+                                {
+                                    output.write(conkeep);
+                                }
+                            else
+                                {
+                                    output.write (conclose);
+                                }
+                            output.write(ctype);
+                            output.write(clength);
+                            output.write(Integer.toString(result.length)
+                                         .getBytes());
+                            output.write(doubleNewline);
+                            output.write(result);
+                        } catch (XmlRpcServer.AuthenticationRequiredException are) {
+                            output.write("HTTP/1.0".getBytes());
+                            output.write(" 401 Unauthorized\r\n".getBytes());
+                            output.write(server);
+                            output.write(www_authenticate);
+                            output.write("\r\n".getBytes());
+                            output.write(("Method " + method
+                                          + " requires a username and password").getBytes());
+                            keepalive = false;
                         }
-                        output.write(ctype);
-                        output.write(clength);
-                        output.write(Integer.toString(result.length)
-                                .getBytes());
-                        output.write(doubleNewline);
-                        output.write(result);
                         output.flush();
                     }
                     else
                     {
-                        output.write(httpversion.getBytes());
+                        output.write("HTTP/1.0".getBytes());
                         output.write(" 400 Bad Request\r\n".getBytes());
                         output.write(server);
                         output.write("\r\n".getBytes());
Index: src/java/org/apache/xmlrpc/XmlRpcServer.java
===================================================================
RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
retrieving revision 1.28
diff -u -r1.28 XmlRpcServer.java
--- src/java/org/apache/xmlrpc/XmlRpcServer.java	9 Aug 2002 09:14:24 -0000	1.28
+++ src/java/org/apache/xmlrpc/XmlRpcServer.java	14 Aug 2002 04:24:41 -0000
@@ -93,6 +93,7 @@
         handlers = new Hashtable();
         pool = new Stack();
         workers = 0;
+        addHandler("system", new SystemMethods(this));
     }
 
     /**
@@ -136,6 +137,7 @@
      * since this is all packed into the response.
      */
     public byte[] execute(InputStream is)
+        throws AuthenticationRequiredException
     {
         return execute(is, null, null);
     }
@@ -146,6 +148,7 @@
      * use the credentials to authenticate the user.
      */
     public byte[] execute(InputStream is, String user, String password)
+        throws AuthenticationRequiredException
     {
         Worker worker = getWorker();
         byte[] retval = worker.execute(is, user, password);
@@ -179,6 +182,61 @@
         }
     }
 
+    /** find the handler for a given method */
+    Object getHandler(String methodName) throws Exception {
+        Object handler = null;
+        String handlerName = null;
+        int dot = methodName.lastIndexOf('.');
+        if (dot > -1)
+            {
+                handlerName = methodName.substring(0, dot);
+                handler = handlers.get(handlerName);
+                if (handler != null)
+                    {
+                        methodName = methodName.substring(dot + 1);
+                    }
+            }
+        
+        if (handler == null)
+            {
+                handler = handlers.get("$default");
+            }
+        
+        if (handler == null)
+            {
+                if (dot > -1)
+                    {
+                        throw new Exception("RPC handler object \""
+                                            + handlerName + "\" not found and no default "
+                                            + "handler registered.");
+                    }
+                else
+                    {
+                        throw new Exception("RPC handler object not found for \""
+                                            + methodName
+                                            + "\": no default handler registered.");
+                    }
+            }
+        
+        return handler;
+    }
+    
+    Object invokeHandler(Object handler, String methodName,
+                         Vector inParams, String user, String password)
+        throws Exception {
+        if (handler instanceof AuthenticatedXmlRpcHandler)
+            {
+                if (user == null) throw new XmlRpcServer.AuthenticationRequiredException();
+                return ((AuthenticatedXmlRpcHandler) handler)
+                    .execute(methodName, inParams, user, password);
+            }
+        else
+            {
+                return ((XmlRpcHandler) handler).execute(methodName, inParams);
+            }
+    }
+
+
     /**
      * Performs streaming, parsing, and handler execution.
      * Implementation is not thread-safe.
@@ -202,6 +260,7 @@
          * Given a request for the server, generates a response.
          */
         public byte[] execute(InputStream is, String user, String password)
+            throws AuthenticationRequiredException
         {
             try
             {
@@ -223,10 +282,10 @@
          * @param password
          * @return
          */
-        private byte[] executeInternal(InputStream is, String user,
-                String password)
+        byte[] executeInternal(InputStream is, String user,
+                String password) throws AuthenticationRequiredException
         {
-            byte[] result;
+            byte[] result = null;
             long now = 0;
 
             if (XmlRpc.debug)
@@ -246,63 +305,20 @@
                 {
                     throw new Exception(errorMsg);
                 }
-                Object handler = null;
-
-                String handlerName = null;
-                int dot = methodName.lastIndexOf('.');
-                if (dot > -1)
-                {
-                    handlerName = methodName.substring(0, dot);
-                    handler = handlers.get(handlerName);
-                    if (handler != null)
-                    {
-                        methodName = methodName.substring(dot + 1);
-                    }
-                }
-
-                if (handler == null)
-                {
-                    handler = handlers.get("$default");
-                }
 
-                if (handler == null)
-                {
-                    if (dot > -1)
-                    {
-                        throw new Exception("RPC handler object \""
-                                + handlerName + "\" not found and no default "
-                                + "handler registered.");
-                    }
-                    else
-                    {
-                        throw new Exception("RPC handler object not found for \""
-                                + methodName
-                                + "\": no default handler registered.");
-                    }
-                }
+                Object handler = getHandler(methodName);
+                Object outParam = invokeHandler(handler, methodName, inParams, user, password);
 
-                Object outParam;
-                if (handler instanceof AuthenticatedXmlRpcHandler)
-                {
-                    outParam =((AuthenticatedXmlRpcHandler) handler)
-                            .execute(methodName, inParams, user, password);
-                }
-                else
-                {
-                    outParam =((XmlRpcHandler) handler)
-                            .execute(methodName, inParams);
-                }
                 if (XmlRpc.debug)
                 {
                     System.out.println("outparam = " + outParam);
                 }
-                writer = new XmlWriter(buffer, encoding);
-                writeResponse(outParam, writer);
-                writer.flush();
-                result = buffer.toByteArray();
             }
             catch(Exception x)
             {
+                if (x instanceof XmlRpcServer.AuthenticationRequiredException)
+                    throw (XmlRpcServer.AuthenticationRequiredException)x;
+
                 if (XmlRpc.debug)
                 {
                     x.printStackTrace();
@@ -427,6 +443,11 @@
             writer.endElement("methodResponse");
         }
     } // end of inner class Worker
+
+    public static class AuthenticationRequiredException extends IOException {
+        AuthenticationRequiredException() { }
+    }
+
 } // XmlRpcServer
 
 /**
@@ -555,4 +576,6 @@
         }
         return returnValue;
     }
+
 }
+

Re: system.multicall()

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Adam Megacz <ad...@megacz.com> writes:

> Daniel Rall <dl...@finemaltcoding.com> writes:
> > The multicall handler needs a reference to the XmlRpcServer to
> > perform the multiple RPC calls;
> 
> This is true, and cannot be avoided, since SystemHandler needs access
> (at least indirectly) to XmlRpcServer.handlers in order to dispatch
> the subcalls. You can't get around this.
> 
> > I assume this is why you set things up this way.
> 
> Not really -- I favor automatically adding the handler since just
> about every other XML-RPC implementation that supports
> system.multicall also does so. IMHO the few people who need system.*
> to work differently can use removeHandler(). Same goes for the
> system.introspection methods, which somebody may implement in the
> future.

For now I added the system.multicall handler via the
addDefaultHandler() method of WebServer.
-- 

Daniel Rall <dl...@finemaltcoding.com>

Re: system.multicall()

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Adam Megacz <ad...@megacz.com> writes:

> Daniel Rall <dl...@finemaltcoding.com> writes:
> > The multicall handler needs a reference to the XmlRpcServer to
> > perform the multiple RPC calls;
> 
> This is true, and cannot be avoided, since SystemHandler needs access
> (at least indirectly) to XmlRpcServer.handlers in order to dispatch
> the subcalls. You can't get around this.
> 
> > I assume this is why you set things up this way.
> 
> Not really -- I favor automatically adding the handler since just
> about every other XML-RPC implementation that supports
> system.multicall also does so. IMHO the few people who need system.*
> to work differently can use removeHandler(). Same goes for the
> system.introspection methods, which somebody may implement in the
> future.

For now I added the system.multicall handler via the
addDefaultHandler() method of WebServer.
-- 

Daniel Rall <dl...@finemaltcoding.com>

Re: system.multicall()

Posted by Adam Megacz <ad...@megacz.com>.
Daniel Rall <dl...@finemaltcoding.com> writes:
> The multicall handler needs a reference to the XmlRpcServer to
> perform the multiple RPC calls;

This is true, and cannot be avoided, since SystemHandler needs access
(at least indirectly) to XmlRpcServer.handlers in order to dispatch
the subcalls. You can't get around this.

> I assume this is why you set things up this way.

Not really -- I favor automatically adding the handler since just
about every other XML-RPC implementation that supports
system.multicall also does so. IMHO the few people who need system.*
to work differently can use removeHandler(). Same goes for the
system.introspection methods, which somebody may implement in the
future.

  - a

-- 
Sick of HTML user interfaces?
www.xwt.org

Re: system.multicall()

Posted by Adam Megacz <ad...@megacz.com>.
Daniel Rall <dl...@finemaltcoding.com> writes:
> The multicall handler needs a reference to the XmlRpcServer to
> perform the multiple RPC calls;

This is true, and cannot be avoided, since SystemHandler needs access
(at least indirectly) to XmlRpcServer.handlers in order to dispatch
the subcalls. You can't get around this.

> I assume this is why you set things up this way.

Not really -- I favor automatically adding the handler since just
about every other XML-RPC implementation that supports
system.multicall also does so. IMHO the few people who need system.*
to work differently can use removeHandler(). Same goes for the
system.introspection methods, which somebody may implement in the
future.

  - a

-- 
Sick of HTML user interfaces?
www.xwt.org

Re: system.multicall()

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Adam, I added your handler and associated to XmlRpcServer refactoring
to CVS HEAD (thanks).  I haven't yet looked at the auth changes.

I explicitly didn't add the automatic addition of the system.multicall
handler to the XmlRpcServer class, as I don't think it currently adds
any handler by default and am hoping to keep it that way.  The
multicall handler needs a reference to the XmlRpcServer to perform the
multiple RPC calls; I assume this is why you set things up this way.
Any ideas on avoiding this issue?

- Dan


Adam Megacz <ad...@megacz.com> writes:

> Here's the patch for system.multicall(), plus a new file it adds
> (SystemMethods.java). This patch also includes my last patch for HTTP
> Basic authentication.
> 
>   - a
> 
> ______________________________________________________________________________
> org/apache/xmlrpc/SystemMethods.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 org.apache.xmlrpc.*;
> import java.util.*;
> 
> /** Implements the XML-RPC standard system.* methods */
> public class SystemMethods {
> 
>     XmlRpcServer serv = null;
> 
>     SystemMethods(XmlRpcServer serv) { this.serv = serv; }
> 
>     public Vector multicall(Vector in) {
>         Vector ret = new Vector();
>         for(int i=0; i<in.size(); i++) {
>             try {
>                 Hashtable call = (Hashtable)in.elementAt(i);
>                 String methodName = (String)call.get("methodName");
>                 Vector params = (Vector)call.get("params");
>                 Object handler = serv.getHandler(methodName);
>                 Vector v = new Vector();
>                 v.addElement(serv.invokeHandler(handler, methodName, params, null, null));
>                 ret.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));
>                 ret.addElement(h);
>             }
>         }
>         return ret;
>     }
>     
> }
> 
> 
> 
> 
> ______________________________________________________________________________
> patch
> 
> Index: src/java/org/apache/xmlrpc/WebServer.java
> ===================================================================
> RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/WebServer.java,v
> retrieving revision 1.13
> diff -u -r1.13 WebServer.java
> --- src/java/org/apache/xmlrpc/WebServer.java	13 Aug 2002 22:27:16 -0000	1.13
> +++ src/java/org/apache/xmlrpc/WebServer.java	14 Aug 2002 04:24:39 -0000
> @@ -94,6 +94,7 @@
>      protected static final byte[] conclose = "Connection: close\r\n".getBytes();
>      protected static final byte[] ok = " 200 OK\r\n".getBytes();
>      protected static final byte[] server = "Server: Apache XML-RPC 1.0\r\n".getBytes();
> +    protected static final byte[] www_authenticate = "WWW-Authenticate: Basic realm=XMLRPC\r\n".getBytes();
>  
>      private static final String HTTP_11 = "HTTP/1.1";
>      private static final String STAR = "*";
> @@ -584,29 +585,40 @@
>                      {
>                          ServerInputStream sin = new ServerInputStream(input,
>                                  contentLength);
> -                        byte result[] = xmlrpc.execute(sin, user, password);
> -                        output.write(httpversion.getBytes());
> -                        output.write(ok);
> -                        output.write(server);
> -                        if (keepalive)
> -                        {
> -                            output.write(conkeep);
> -                        }
> -                        else
> -                        {
> -                            output.write (conclose);
> +                        try {
> +                            byte result[] = xmlrpc.execute(sin, user, password);
> +                            output.write(httpversion.getBytes());
> +                            output.write(ok);
> +                            output.write(server);
> +                            if (keepalive)
> +                                {
> +                                    output.write(conkeep);
> +                                }
> +                            else
> +                                {
> +                                    output.write (conclose);
> +                                }
> +                            output.write(ctype);
> +                            output.write(clength);
> +                            output.write(Integer.toString(result.length)
> +                                         .getBytes());
> +                            output.write(doubleNewline);
> +                            output.write(result);
> +                        } catch (XmlRpcServer.AuthenticationRequiredException are) {
> +                            output.write("HTTP/1.0".getBytes());
> +                            output.write(" 401 Unauthorized\r\n".getBytes());
> +                            output.write(server);
> +                            output.write(www_authenticate);
> +                            output.write("\r\n".getBytes());
> +                            output.write(("Method " + method
> +                                          + " requires a username and password").getBytes());
> +                            keepalive = false;
>                          }
> -                        output.write(ctype);
> -                        output.write(clength);
> -                        output.write(Integer.toString(result.length)
> -                                .getBytes());
> -                        output.write(doubleNewline);
> -                        output.write(result);
>                          output.flush();
>                      }
>                      else
>                      {
> -                        output.write(httpversion.getBytes());
> +                        output.write("HTTP/1.0".getBytes());
>                          output.write(" 400 Bad Request\r\n".getBytes());
>                          output.write(server);
>                          output.write("\r\n".getBytes());
> Index: src/java/org/apache/xmlrpc/XmlRpcServer.java
> ===================================================================
> RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
> retrieving revision 1.28
> diff -u -r1.28 XmlRpcServer.java
> --- src/java/org/apache/xmlrpc/XmlRpcServer.java	9 Aug 2002 09:14:24 -0000	1.28
> +++ src/java/org/apache/xmlrpc/XmlRpcServer.java	14 Aug 2002 04:24:41 -0000
> @@ -93,6 +93,7 @@
>          handlers = new Hashtable();
>          pool = new Stack();
>          workers = 0;
> +        addHandler("system", new SystemMethods(this));
>      }
>  
>      /**
> @@ -136,6 +137,7 @@
>       * since this is all packed into the response.
>       */
>      public byte[] execute(InputStream is)
> +        throws AuthenticationRequiredException
>      {
>          return execute(is, null, null);
>      }
> @@ -146,6 +148,7 @@
>       * use the credentials to authenticate the user.
>       */
>      public byte[] execute(InputStream is, String user, String password)
> +        throws AuthenticationRequiredException
>      {
>          Worker worker = getWorker();
>          byte[] retval = worker.execute(is, user, password);
> @@ -179,6 +182,61 @@
>          }
>      }
>  
> +    /** find the handler for a given method */
> +    Object getHandler(String methodName) throws Exception {
> +        Object handler = null;
> +        String handlerName = null;
> +        int dot = methodName.lastIndexOf('.');
> +        if (dot > -1)
> +            {
> +                handlerName = methodName.substring(0, dot);
> +                handler = handlers.get(handlerName);
> +                if (handler != null)
> +                    {
> +                        methodName = methodName.substring(dot + 1);
> +                    }
> +            }
> +        
> +        if (handler == null)
> +            {
> +                handler = handlers.get("$default");
> +            }
> +        
> +        if (handler == null)
> +            {
> +                if (dot > -1)
> +                    {
> +                        throw new Exception("RPC handler object \""
> +                                            + handlerName + "\" not found and no default "
> +                                            + "handler registered.");
> +                    }
> +                else
> +                    {
> +                        throw new Exception("RPC handler object not found for \""
> +                                            + methodName
> +                                            + "\": no default handler registered.");
> +                    }
> +            }
> +        
> +        return handler;
> +    }
> +    
> +    Object invokeHandler(Object handler, String methodName,
> +                         Vector inParams, String user, String password)
> +        throws Exception {
> +        if (handler instanceof AuthenticatedXmlRpcHandler)
> +            {
> +                if (user == null) throw new XmlRpcServer.AuthenticationRequiredException();
> +                return ((AuthenticatedXmlRpcHandler) handler)
> +                    .execute(methodName, inParams, user, password);
> +            }
> +        else
> +            {
> +                return ((XmlRpcHandler) handler).execute(methodName, inParams);
> +            }
> +    }
> +
> +
>      /**
>       * Performs streaming, parsing, and handler execution.
>       * Implementation is not thread-safe.
> @@ -202,6 +260,7 @@
>           * Given a request for the server, generates a response.
>           */
>          public byte[] execute(InputStream is, String user, String password)
> +            throws AuthenticationRequiredException
>          {
>              try
>              {
> @@ -223,10 +282,10 @@
>           * @param password
>           * @return
>           */
> -        private byte[] executeInternal(InputStream is, String user,
> -                String password)
> +        byte[] executeInternal(InputStream is, String user,
> +                String password) throws AuthenticationRequiredException
>          {
> -            byte[] result;
> +            byte[] result = null;
>              long now = 0;
>  
>              if (XmlRpc.debug)
> @@ -246,63 +305,20 @@
>                  {
>                      throw new Exception(errorMsg);
>                  }
> -                Object handler = null;
> -
> -                String handlerName = null;
> -                int dot = methodName.lastIndexOf('.');
> -                if (dot > -1)
> -                {
> -                    handlerName = methodName.substring(0, dot);
> -                    handler = handlers.get(handlerName);
> -                    if (handler != null)
> -                    {
> -                        methodName = methodName.substring(dot + 1);
> -                    }
> -                }
> -
> -                if (handler == null)
> -                {
> -                    handler = handlers.get("$default");
> -                }
>  
> -                if (handler == null)
> -                {
> -                    if (dot > -1)
> -                    {
> -                        throw new Exception("RPC handler object \""
> -                                + handlerName + "\" not found and no default "
> -                                + "handler registered.");
> -                    }
> -                    else
> -                    {
> -                        throw new Exception("RPC handler object not found for \""
> -                                + methodName
> -                                + "\": no default handler registered.");
> -                    }
> -                }
> +                Object handler = getHandler(methodName);
> +                Object outParam = invokeHandler(handler, methodName, inParams, user, password);
>  
> -                Object outParam;
> -                if (handler instanceof AuthenticatedXmlRpcHandler)
> -                {
> -                    outParam =((AuthenticatedXmlRpcHandler) handler)
> -                            .execute(methodName, inParams, user, password);
> -                }
> -                else
> -                {
> -                    outParam =((XmlRpcHandler) handler)
> -                            .execute(methodName, inParams);
> -                }
>                  if (XmlRpc.debug)
>                  {
>                      System.out.println("outparam = " + outParam);
>                  }
> -                writer = new XmlWriter(buffer, encoding);
> -                writeResponse(outParam, writer);
> -                writer.flush();
> -                result = buffer.toByteArray();
>              }
>              catch(Exception x)
>              {
> +                if (x instanceof XmlRpcServer.AuthenticationRequiredException)
> +                    throw (XmlRpcServer.AuthenticationRequiredException)x;
> +
>                  if (XmlRpc.debug)
>                  {
>                      x.printStackTrace();
> @@ -427,6 +443,11 @@
>              writer.endElement("methodResponse");
>          }
>      } // end of inner class Worker
> +
> +    public static class AuthenticationRequiredException extends IOException {
> +        AuthenticationRequiredException() { }
> +    }
> +
>  } // XmlRpcServer
>  
>  /**
> @@ -555,4 +576,6 @@
>          }
>          return returnValue;
>      }
> +
>  }
> +
> 

-- 

Daniel Rall <dl...@finemaltcoding.com>

Re: system.multicall()

Posted by Daniel Rall <dl...@finemaltcoding.com>.
Adam, I added your handler and associated to XmlRpcServer refactoring
to CVS HEAD (thanks).  I haven't yet looked at the auth changes.

I explicitly didn't add the automatic addition of the system.multicall
handler to the XmlRpcServer class, as I don't think it currently adds
any handler by default and am hoping to keep it that way.  The
multicall handler needs a reference to the XmlRpcServer to perform the
multiple RPC calls; I assume this is why you set things up this way.
Any ideas on avoiding this issue?

- Dan


Adam Megacz <ad...@megacz.com> writes:

> Here's the patch for system.multicall(), plus a new file it adds
> (SystemMethods.java). This patch also includes my last patch for HTTP
> Basic authentication.
> 
>   - a
> 
> ______________________________________________________________________________
> org/apache/xmlrpc/SystemMethods.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 org.apache.xmlrpc.*;
> import java.util.*;
> 
> /** Implements the XML-RPC standard system.* methods */
> public class SystemMethods {
> 
>     XmlRpcServer serv = null;
> 
>     SystemMethods(XmlRpcServer serv) { this.serv = serv; }
> 
>     public Vector multicall(Vector in) {
>         Vector ret = new Vector();
>         for(int i=0; i<in.size(); i++) {
>             try {
>                 Hashtable call = (Hashtable)in.elementAt(i);
>                 String methodName = (String)call.get("methodName");
>                 Vector params = (Vector)call.get("params");
>                 Object handler = serv.getHandler(methodName);
>                 Vector v = new Vector();
>                 v.addElement(serv.invokeHandler(handler, methodName, params, null, null));
>                 ret.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));
>                 ret.addElement(h);
>             }
>         }
>         return ret;
>     }
>     
> }
> 
> 
> 
> 
> ______________________________________________________________________________
> patch
> 
> Index: src/java/org/apache/xmlrpc/WebServer.java
> ===================================================================
> RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/WebServer.java,v
> retrieving revision 1.13
> diff -u -r1.13 WebServer.java
> --- src/java/org/apache/xmlrpc/WebServer.java	13 Aug 2002 22:27:16 -0000	1.13
> +++ src/java/org/apache/xmlrpc/WebServer.java	14 Aug 2002 04:24:39 -0000
> @@ -94,6 +94,7 @@
>      protected static final byte[] conclose = "Connection: close\r\n".getBytes();
>      protected static final byte[] ok = " 200 OK\r\n".getBytes();
>      protected static final byte[] server = "Server: Apache XML-RPC 1.0\r\n".getBytes();
> +    protected static final byte[] www_authenticate = "WWW-Authenticate: Basic realm=XMLRPC\r\n".getBytes();
>  
>      private static final String HTTP_11 = "HTTP/1.1";
>      private static final String STAR = "*";
> @@ -584,29 +585,40 @@
>                      {
>                          ServerInputStream sin = new ServerInputStream(input,
>                                  contentLength);
> -                        byte result[] = xmlrpc.execute(sin, user, password);
> -                        output.write(httpversion.getBytes());
> -                        output.write(ok);
> -                        output.write(server);
> -                        if (keepalive)
> -                        {
> -                            output.write(conkeep);
> -                        }
> -                        else
> -                        {
> -                            output.write (conclose);
> +                        try {
> +                            byte result[] = xmlrpc.execute(sin, user, password);
> +                            output.write(httpversion.getBytes());
> +                            output.write(ok);
> +                            output.write(server);
> +                            if (keepalive)
> +                                {
> +                                    output.write(conkeep);
> +                                }
> +                            else
> +                                {
> +                                    output.write (conclose);
> +                                }
> +                            output.write(ctype);
> +                            output.write(clength);
> +                            output.write(Integer.toString(result.length)
> +                                         .getBytes());
> +                            output.write(doubleNewline);
> +                            output.write(result);
> +                        } catch (XmlRpcServer.AuthenticationRequiredException are) {
> +                            output.write("HTTP/1.0".getBytes());
> +                            output.write(" 401 Unauthorized\r\n".getBytes());
> +                            output.write(server);
> +                            output.write(www_authenticate);
> +                            output.write("\r\n".getBytes());
> +                            output.write(("Method " + method
> +                                          + " requires a username and password").getBytes());
> +                            keepalive = false;
>                          }
> -                        output.write(ctype);
> -                        output.write(clength);
> -                        output.write(Integer.toString(result.length)
> -                                .getBytes());
> -                        output.write(doubleNewline);
> -                        output.write(result);
>                          output.flush();
>                      }
>                      else
>                      {
> -                        output.write(httpversion.getBytes());
> +                        output.write("HTTP/1.0".getBytes());
>                          output.write(" 400 Bad Request\r\n".getBytes());
>                          output.write(server);
>                          output.write("\r\n".getBytes());
> Index: src/java/org/apache/xmlrpc/XmlRpcServer.java
> ===================================================================
> RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
> retrieving revision 1.28
> diff -u -r1.28 XmlRpcServer.java
> --- src/java/org/apache/xmlrpc/XmlRpcServer.java	9 Aug 2002 09:14:24 -0000	1.28
> +++ src/java/org/apache/xmlrpc/XmlRpcServer.java	14 Aug 2002 04:24:41 -0000
> @@ -93,6 +93,7 @@
>          handlers = new Hashtable();
>          pool = new Stack();
>          workers = 0;
> +        addHandler("system", new SystemMethods(this));
>      }
>  
>      /**
> @@ -136,6 +137,7 @@
>       * since this is all packed into the response.
>       */
>      public byte[] execute(InputStream is)
> +        throws AuthenticationRequiredException
>      {
>          return execute(is, null, null);
>      }
> @@ -146,6 +148,7 @@
>       * use the credentials to authenticate the user.
>       */
>      public byte[] execute(InputStream is, String user, String password)
> +        throws AuthenticationRequiredException
>      {
>          Worker worker = getWorker();
>          byte[] retval = worker.execute(is, user, password);
> @@ -179,6 +182,61 @@
>          }
>      }
>  
> +    /** find the handler for a given method */
> +    Object getHandler(String methodName) throws Exception {
> +        Object handler = null;
> +        String handlerName = null;
> +        int dot = methodName.lastIndexOf('.');
> +        if (dot > -1)
> +            {
> +                handlerName = methodName.substring(0, dot);
> +                handler = handlers.get(handlerName);
> +                if (handler != null)
> +                    {
> +                        methodName = methodName.substring(dot + 1);
> +                    }
> +            }
> +        
> +        if (handler == null)
> +            {
> +                handler = handlers.get("$default");
> +            }
> +        
> +        if (handler == null)
> +            {
> +                if (dot > -1)
> +                    {
> +                        throw new Exception("RPC handler object \""
> +                                            + handlerName + "\" not found and no default "
> +                                            + "handler registered.");
> +                    }
> +                else
> +                    {
> +                        throw new Exception("RPC handler object not found for \""
> +                                            + methodName
> +                                            + "\": no default handler registered.");
> +                    }
> +            }
> +        
> +        return handler;
> +    }
> +    
> +    Object invokeHandler(Object handler, String methodName,
> +                         Vector inParams, String user, String password)
> +        throws Exception {
> +        if (handler instanceof AuthenticatedXmlRpcHandler)
> +            {
> +                if (user == null) throw new XmlRpcServer.AuthenticationRequiredException();
> +                return ((AuthenticatedXmlRpcHandler) handler)
> +                    .execute(methodName, inParams, user, password);
> +            }
> +        else
> +            {
> +                return ((XmlRpcHandler) handler).execute(methodName, inParams);
> +            }
> +    }
> +
> +
>      /**
>       * Performs streaming, parsing, and handler execution.
>       * Implementation is not thread-safe.
> @@ -202,6 +260,7 @@
>           * Given a request for the server, generates a response.
>           */
>          public byte[] execute(InputStream is, String user, String password)
> +            throws AuthenticationRequiredException
>          {
>              try
>              {
> @@ -223,10 +282,10 @@
>           * @param password
>           * @return
>           */
> -        private byte[] executeInternal(InputStream is, String user,
> -                String password)
> +        byte[] executeInternal(InputStream is, String user,
> +                String password) throws AuthenticationRequiredException
>          {
> -            byte[] result;
> +            byte[] result = null;
>              long now = 0;
>  
>              if (XmlRpc.debug)
> @@ -246,63 +305,20 @@
>                  {
>                      throw new Exception(errorMsg);
>                  }
> -                Object handler = null;
> -
> -                String handlerName = null;
> -                int dot = methodName.lastIndexOf('.');
> -                if (dot > -1)
> -                {
> -                    handlerName = methodName.substring(0, dot);
> -                    handler = handlers.get(handlerName);
> -                    if (handler != null)
> -                    {
> -                        methodName = methodName.substring(dot + 1);
> -                    }
> -                }
> -
> -                if (handler == null)
> -                {
> -                    handler = handlers.get("$default");
> -                }
>  
> -                if (handler == null)
> -                {
> -                    if (dot > -1)
> -                    {
> -                        throw new Exception("RPC handler object \""
> -                                + handlerName + "\" not found and no default "
> -                                + "handler registered.");
> -                    }
> -                    else
> -                    {
> -                        throw new Exception("RPC handler object not found for \""
> -                                + methodName
> -                                + "\": no default handler registered.");
> -                    }
> -                }
> +                Object handler = getHandler(methodName);
> +                Object outParam = invokeHandler(handler, methodName, inParams, user, password);
>  
> -                Object outParam;
> -                if (handler instanceof AuthenticatedXmlRpcHandler)
> -                {
> -                    outParam =((AuthenticatedXmlRpcHandler) handler)
> -                            .execute(methodName, inParams, user, password);
> -                }
> -                else
> -                {
> -                    outParam =((XmlRpcHandler) handler)
> -                            .execute(methodName, inParams);
> -                }
>                  if (XmlRpc.debug)
>                  {
>                      System.out.println("outparam = " + outParam);
>                  }
> -                writer = new XmlWriter(buffer, encoding);
> -                writeResponse(outParam, writer);
> -                writer.flush();
> -                result = buffer.toByteArray();
>              }
>              catch(Exception x)
>              {
> +                if (x instanceof XmlRpcServer.AuthenticationRequiredException)
> +                    throw (XmlRpcServer.AuthenticationRequiredException)x;
> +
>                  if (XmlRpc.debug)
>                  {
>                      x.printStackTrace();
> @@ -427,6 +443,11 @@
>              writer.endElement("methodResponse");
>          }
>      } // end of inner class Worker
> +
> +    public static class AuthenticationRequiredException extends IOException {
> +        AuthenticationRequiredException() { }
> +    }
> +
>  } // XmlRpcServer
>  
>  /**
> @@ -555,4 +576,6 @@
>          }
>          return returnValue;
>      }
> +
>  }
> +
> 

-- 

Daniel Rall <dl...@finemaltcoding.com>