When using an XmlRpcProxy is it possible to omit the class name when calling a method on the XML-RPC server? For example:
Server server = ( Server) XmlRpcProxy.createProxy( "http://localhost/RPC2", new Class[] { Server.class } );
String serverTime = server.time();
If you look at the XML-RPC method call for this you would see "Server.login" for the method name. The service I am connecting to just expects the method name instead of class.methodname
Thanks,
--Mark
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You can override the default behaviour of using the interface name as a prefix when constructing method names during invocation by using the following constructor:
public static Object createProxy(
URL url,
String objectName, // This will override the default handler name (Server in your case)
Class[] interfaces,
boolean streamMessages )
However, I just spotted that supplying an empty prefix/object name is not supported. The resulting method name would become ".login" for instance, which is not what you want. I fixed this in Subversion and I emailed a new build to your SF email address.
So for it to work for you you will have to construct the proxy like so:
Server server = ( Server) XmlRpcProxy.createProxy( "http://localhost/RPC2", "", new Class[] { Server.class } );
That is, you add a new argument to createProxy() stating that the handler name/prefix is "" and only the actual method names like "time" and "login" will be used. The new build is in the mail, and will be included in the next official release. Thanks for your input.
Best Regards,
Greger.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2010-12-10
Hi there, Is there some way for me to do this using a Client instead of a Proxy???
I've got a project running that needs this changes but I don't know how to do this.
I thought about using a interceptor or add a handler with a class that implements XmlRpcInvocationHandler but I didn't solve this…
Thanks for your attention,
André.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes you can, the XmlRpcProxy is just a utility class for wrapping an XML-RPC interface with a Java interface. You can just as well use an XmlRpcClient directly (which is what XmlRpcProxy does behind the scenes).
So the steos are to create an XmlRpcClient pointing to the service URL. And then use invoke() on it. The first argument is the name of the method to call which does not have to use dot-notation as in the example - it can be just "login". The second argument is an array of the arguments you want to pass to the service, for instance:
new Object { 1, "one", 1.0 }
Hope this helps,
Greger.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2010-12-10
Hi Greger,
first of all, thanks for the quick response, me and my friend Andre are running tests on both server and clients, and we run into this problem. On the client side it wasn't much of a problem in the begging, the real pain was to receive only the method name and not the "classname.methodname" in the Request XML.
the server would still be able do put some answer. The library we got from the sourceforge has two methods to addHandlers in the server side, one with the {String , Object (we put some class here)} and the {string, xmlrpcinvocationhandler (which I couldn't put to work)}. So we had to modify the XmlRpcDispatcher to duplicate the MethodName with the handlerName. This way in my server app. I have one class for each method with only this method being called by the handler. It works, but is not so nicely as I expected. Could you give some help on using the addInvocationHandler with the XmlRpcInvocationHandler as parameter. The dispatch method modifications can be seen as follows:
public void dispatch(InputStream xmlInput, Writer xmlOutput) throws XmlRpcException {
// Parse the inbound XML-RPC message. May throw an exception.
parse(xmlInput);
// Response is written directly to the Writer supplied by the XmlRpcServer.
this.writer = xmlOutput;
// Exceptions will from hereon be encoded in the XML-RPC response.
int separator = methodName.lastIndexOf(".");
// if ( separator > -1 )
// {
final String handlerName = methodName;
// methodName = methodName.substring( separator + 1 );
XmlRpcInvocationHandler handler = server.getInvocationHandler(handlerName);
if (handler != null) {
final int callId = ++callSequence;
XmlRpcInvocation invocation = null;
if (server.getInvocationInterceptors().size() > 0) {
invocation = new XmlRpcInvocation(
callId,
handlerName,
methodName,
handler,
arguments,
writer);
}
try {
// Invoke the method, which may throw any kind of exception. If any of the
// preProcess calls thinks the invocation should be cancelled, we do so.
if (!preProcess(invocation)) {
writeError(-1, XmlRpcMessages.getString("XmlRpcDispatcher.InvocationCancelled"));
} else {
Object returnValue = handler.invoke(methodName, arguments);
returnValue = postProcess(invocation, returnValue);
// If the return value wasn't intercepted by any of the interceptors,
// write the response using the current serlialization mechanism.
if (returnValue != null) {
writeValue(returnValue);
}
}
} catch (Throwable t) {
processException(invocation, t);
int code = -1;
if (t instanceof XmlRpcFault) {
code = ((XmlRpcFault) t).getErrorCode();
}
writeError(code, t.getClass().getName() + ": " + t.getMessage());
}
} else {
writeError(-1, XmlRpcMessages.getString("XmlRpcDispatcher.HandlerNotFound"));
}
// }
// else
// {
// writeError( -1, XmlRpcMessages.getString( "XmlRpcDispatcher.InvalidMethodNameFormat" ) );
// }
}
Thanks a lot.
Cya!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK, I think I know what you're after. When the Redstone library was designed we decided to use dot-notation in the service names since that would allow a single server to expose multiple namespaced services and it allowed the dispatcher to locate which object that should be invoked in a natural way. This seemed to align well with the examples in the spec:
So as you mention in your latest post, you see that the dispatcher is hard coded with this behavior;
int separator = methodName.lastIndexOf(".");
if ( separator > -1 )
{
...dispatch...
}
The reasoning for not allowing non-namespaced, kind of "root" objects, to be published in the server was that we figured since the server defines the API that clients need to follow it wouldn't really matter if the method names were namespaced or not - the server defines the API.
In your case, I assume there's a reason for your service not to use a namespaced API and that you need to follow a pre-defined set of method names. I see you found the code in the XmlRpcDispatcher that needs to be commented out for this name test to be removed.
Since this is not the default behaviour of the library and you need to patch it to support this somehow, I would suggest the following, which may actually be something that we could include in the public release of the library:
1. If there is no "." in the method name we assume that the client wants to include the "default" handler.
2. The object that represents the default handler can be published under a special namespace called "__default" for instance.
3. If the method name invoked has no namespace, the dispatcher adds "__default" as the namespace.
The code changes for this would be:
[b]XmlRpcDispatcher.java[/b]// Somewhere at the toppublic static String DEFAULT_HANDLER_NAME== "__default__";// In dispatch()int separator=methodName.lastIndexOf( "." );if ( separator== -1 ){ methodName=DEFAULT_HANDLER_NAME + "." + methodName;}// code carries on as-is in the dispatcher since the method name has now// been qualified with a handler name.
Now, when an object is published in the server with for instance:
server.addInvocationHandler("__default__", new HashMap());
This would mean that the published HashMap would be the default handler and all its
methods can be invoked without a namespace (since the dispatcher will add "__default__."
to the method name if it is not included.
Since the HashMap exposes the put() method. And get(), and size() and the other methods would
also be available.
To make publishing easier in the server, developers should not need to know about the special
"__default__" handler name so we have two options;
1. Make addInvocationHandler(null, …) mean that we don't want a namespace but instead publish the
handler as the "default" or "root" or "non-namespaced" handler.
2. Overload an extra addInvocationHandler() that only accepts the handler argument and no name parameter.
Alternative 1. would look like this in XmlRpcServer:
public void addInvocationHandler( String name, Object handler )
{
if ( name == null ) name = XmlRpcDispatcher.DEFAULT_HANDLER_NAME;
handlers.put( name, new ReflectiveInvocationHandler( handler ) );
}
I'm undecided which of 1. or 2. is best here. I'm leaning towards 2., but 1. would be fine as well.
What do you think?
BR,
Greger.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Support for default-namespaced invocation handlers are in the SVN repository now and will be included in the next public release. This means that when you add an invocation handler object to a server and you supply 'null' as its namespace the object will become the 'default' handler. All requests with a non-namespaced method name will target this default handler.
Example:
Server.java
public class Server {
public static void main(String[] args) throws Throwable {
redstone.xmlrpc.simple.Server server = new redstone.xmlrpc.simple.Server( 8080 );
server.getXmlRpcServer().addInvocationHandler( null, new java.util.HashMap() );
server.start();
}
}
Above a regular HashMap is published as the default invocation handler in an XmlRpcServer, since no namespace is given when the handler is published.
All methods in the HashMap are now exposed without a namespace and can be invoked directly by the client:
Client.java
publicclassClient{publicstaticvoidmain(String[]args)throwsThrowable{redstone.xmlrpc.XmlRpcClientclient=newredstone.xmlrpc.XmlRpcClient("http://localhost:8080", false); client.invoke("put", new Object[] { "greeting", "HEY!" }); System.out.println(client.invoke("get", new Object[] { "greeting"}));}}
As can be seen, an XmlRpcClient is used to invoke the plain "put" and "get" methods in the server's default handler, without namespacing it.
If you checkout the SVN source you can run 'ant' to build the JAR-files. If you don't have Ant installed I can send you the files.
If this functionality is not what you were after, please let me know. Either way it was actually a good addition to the library so it fit nicely into the source regardless.
Cheers,
Greger.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2010-12-13
Hi Greger,
I was sure that you would fit a nice solution for the server since it was you who developed it, by the way, an excellent Job. I would really appreciate if you could send the JARs to me, but since i'm not a Coach Potato I will try to create then myself. And by the way I liked your solution, it not only permits to keep methods without a classname and yet you can create handlers for the ones who do so. My personal email is thiagomgc18@gmail.com, feel free to call(gtalk) anytime you want, in spice I been a engineer I am faded to produce codes a lot, LOL.
Thiago
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This post has been very helpful. Found it with a Google search. I ran into same issue.
I'm a novice Java developer, and luckily, it looks like the JARs are updated for download as well, it would have been more painful for me to manually create the JARs from source.
But Greger, it might be helpful to update the simple-xmlrpc JAR package as well and perhaps may want to update the website home page (and/or docs), etc. to mention this thread as well, in case others have the same issue. Less steps for users to go through when they encounter this issue.
To add some thoughts to the thread - I've just worked with XML-RPC so don't have much insight, but I would assume that if you're not working strictly in Java say for cross-platform usage, say the server is Java but the client is Perl, .NET, Flash, etc., one might run into this issue as well, as those platforms may not use the dot notation for methods.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
When using an XmlRpcProxy is it possible to omit the class name when calling a method on the XML-RPC server? For example:
Server server = ( Server) XmlRpcProxy.createProxy( "http://localhost/RPC2", new Class[] { Server.class } );
String serverTime = server.time();
If you look at the XML-RPC method call for this you would see "Server.login" for the method name. The service I am connecting to just expects the method name instead of class.methodname
Thanks,
--Mark
Hi Mark,
You can override the default behaviour of using the interface name as a prefix when constructing method names during invocation by using the following constructor:
public static Object createProxy(
URL url,
String objectName, // This will override the default handler name (Server in your case)
Class[] interfaces,
boolean streamMessages )
However, I just spotted that supplying an empty prefix/object name is not supported. The resulting method name would become ".login" for instance, which is not what you want. I fixed this in Subversion and I emailed a new build to your SF email address.
So for it to work for you you will have to construct the proxy like so:
Server server = ( Server) XmlRpcProxy.createProxy( "http://localhost/RPC2", "", new Class[] { Server.class } );
That is, you add a new argument to createProxy() stating that the handler name/prefix is "" and only the actual method names like "time" and "login" will be used. The new build is in the mail, and will be included in the next official release. Thanks for your input.
Best Regards,
Greger.
Hi there, Is there some way for me to do this using a Client instead of a Proxy???
I've got a project running that needs this changes but I don't know how to do this.
I thought about using a interceptor or add a handler with a class that implements XmlRpcInvocationHandler but I didn't solve this…
Thanks for your attention,
André.
Hi André,
Yes you can, the XmlRpcProxy is just a utility class for wrapping an XML-RPC interface with a Java interface. You can just as well use an XmlRpcClient directly (which is what XmlRpcProxy does behind the scenes).
This example is from the home page (http://xmlrpc.sf.net)
import redstone.xmlrpc.XmlRpcClient;
So the steos are to create an XmlRpcClient pointing to the service URL. And then use invoke() on it. The first argument is the name of the method to call which does not have to use dot-notation as in the example - it can be just "login". The second argument is an array of the arguments you want to pass to the service, for instance:
new Object { 1, "one", 1.0 }
Hope this helps,
Greger.
Hi Greger,
first of all, thanks for the quick response, me and my friend Andre are running tests on both server and clients, and we run into this problem. On the client side it wasn't much of a problem in the begging, the real pain was to receive only the method name and not the "classname.methodname" in the Request XML.
So when we POST a XML like:
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>request</methodName>
<params>
<param>
<value>
<i4>1</i4>
</value>
</param>
<param>
<value>
<i4>8300640</i4>
</value>
</param>
<param>
<value>
<string>get_vrms</string>
</value>
</param>
<param>
<value>
<array>
<data></data>
</array>
</value>
</param>
</params>
</methodCall>
the server would still be able do put some answer. The library we got from the sourceforge has two methods to addHandlers in the server side, one with the {String , Object (we put some class here)} and the {string, xmlrpcinvocationhandler (which I couldn't put to work)}. So we had to modify the XmlRpcDispatcher to duplicate the MethodName with the handlerName. This way in my server app. I have one class for each method with only this method being called by the handler. It works, but is not so nicely as I expected. Could you give some help on using the addInvocationHandler with the XmlRpcInvocationHandler as parameter. The dispatch method modifications can be seen as follows:
Thanks a lot.
Cya!
Hi,
OK, I think I know what you're after. When the Redstone library was designed we decided to use dot-notation in the service names since that would allow a single server to expose multiple namespaced services and it allowed the dispatcher to locate which object that should be invoked in a natural way. This seemed to align well with the examples in the spec:
So as you mention in your latest post, you see that the dispatcher is hard coded with this behavior;
The reasoning for not allowing non-namespaced, kind of "root" objects, to be published in the server was that we figured since the server defines the API that clients need to follow it wouldn't really matter if the method names were namespaced or not - the server defines the API.
In your case, I assume there's a reason for your service not to use a namespaced API and that you need to follow a pre-defined set of method names. I see you found the code in the XmlRpcDispatcher that needs to be commented out for this name test to be removed.
Since this is not the default behaviour of the library and you need to patch it to support this somehow, I would suggest the following, which may actually be something that we could include in the public release of the library:
1. If there is no "." in the method name we assume that the client wants to include the "default" handler.
2. The object that represents the default handler can be published under a special namespace called "__default" for instance.
3. If the method name invoked has no namespace, the dispatcher adds "__default" as the namespace.
The code changes for this would be:
Now, when an object is published in the server with for instance:
This would mean that the published HashMap would be the default handler and all its
methods can be invoked without a namespace (since the dispatcher will add "__default__."
to the method name if it is not included.
So the following would work:
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>put</methodName>
<params>
<param>
Since the HashMap exposes the put() method. And get(), and size() and the other methods would
also be available.
To make publishing easier in the server, developers should not need to know about the special
"__default__" handler name so we have two options;
1. Make addInvocationHandler(null, …) mean that we don't want a namespace but instead publish the
handler as the "default" or "root" or "non-namespaced" handler.
2. Overload an extra addInvocationHandler() that only accepts the handler argument and no name parameter.
Alternative 1. would look like this in XmlRpcServer:
I'm undecided which of 1. or 2. is best here. I'm leaning towards 2., but 1. would be fine as well.
What do you think?
BR,
Greger.
Support for default-namespaced invocation handlers are in the SVN repository now and will be included in the next public release. This means that when you add an invocation handler object to a server and you supply 'null' as its namespace the object will become the 'default' handler. All requests with a non-namespaced method name will target this default handler.
Example:
Server.java
Above a regular HashMap is published as the default invocation handler in an XmlRpcServer, since no namespace is given when the handler is published.
All methods in the HashMap are now exposed without a namespace and can be invoked directly by the client:
Client.java
As can be seen, an XmlRpcClient is used to invoke the plain "put" and "get" methods in the server's default handler, without namespacing it.
If you checkout the SVN source you can run 'ant' to build the JAR-files. If you don't have Ant installed I can send you the files.
If this functionality is not what you were after, please let me know. Either way it was actually a good addition to the library so it fit nicely into the source regardless.
Cheers,
Greger.
Hi Greger,
I was sure that you would fit a nice solution for the server since it was you who developed it, by the way, an excellent Job. I would really appreciate if you could send the JARs to me, but since i'm not a Coach Potato I will try to create then myself. And by the way I liked your solution, it not only permits to keep methods without a classname and yet you can create handlers for the ones who do so. My personal email is thiagomgc18@gmail.com, feel free to call(gtalk) anytime you want, in spice I been a engineer I am faded to produce codes a lot, LOL.
Thiago
This post has been very helpful. Found it with a Google search. I ran into same issue.
I'm a novice Java developer, and luckily, it looks like the JARs are updated for download as well, it would have been more painful for me to manually create the JARs from source.
But Greger, it might be helpful to update the simple-xmlrpc JAR package as well and perhaps may want to update the website home page (and/or docs), etc. to mention this thread as well, in case others have the same issue. Less steps for users to go through when they encounter this issue.
To add some thoughts to the thread - I've just worked with XML-RPC so don't have much insight, but I would assume that if you're not working strictly in Java say for cross-platform usage, say the server is Java but the client is Perl, .NET, Flash, etc., one might run into this issue as well, as those platforms may not use the dot notation for methods.