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>