Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example

Introduction

A common use case for an xml-rpc based application server would be one which involves the use of one or more persistent objects. Without any kind of persistence a server handling xml-rpc requests will either be ineffective or inefficient.

Accessing Persistent objects in an exposed method/user handler with Apache xml-rpc 3.0 is a process involving several layers of redirection. This can be difficult for anyone who is not familiar with the ws-xmlrpc 3.0 code base. The purpose of this document is to provide a working example using the standalone servlet server which can assist people new to ws-xmlrpc 3.0.

Before We Begin

For those of you who are just interested in the source code to this example, that can be found here: ws-xmlrpc-3.0-buttermountain-example.zip

This document and the code has been created with the help of the ws-xmlrpc FAQ examples and the help of the Apache ws-xmlrpc mailing list.

It is assume that you have read the examples on the Apache ws-xmlrpc website and are familiar with the Java programming language.

Finally, I recommend that you open up the source code and read through the sample code with this document.

In The Beginning There Was Nothing

Before you even begin starting to write your handler methods (the methods which will be exposed via xml-rpc), you must first collect the required libraries and setup the correct directory structure. The directory structure I have opted for looks something like this:

org/buttermountain/xmlrpc/server
org/buttermountain/xmlrpc/client
org/buttermountain/pobject
javax
lib

The javax directory contains all of the Sun servlet classes and the lib directory contains all of the Apache ws-xmlrpc 3.0 jar’s and the Apache ws jar’s that they depend upon.

As for the other directories, xmlrpc/server contains all of our server files, xmlrpc/client contains a sample java ws-xmlrpc client. Finally, the pobject directory contains our very simple persistent object class.

User Handler Methods

When creating an xml-rpc server you will need to create a class which has its methods exposed via xml-rpc. With Apache ws-xmlrpc 3.0 this is done by creating two classes, one which is your interface (ExposedMethodsInterface.java) and one which is the implementation of this interface (ExposedMethodsImplementation.java).

The interface will merely define the methods, their inputs and return data types. For a method to be exposed via xml-rpc it must be public and have a return type that is not void, here is the example interface code

public interface ExposedMethodsInterface {
public void init(Pobject pobject);
public boolean setString(String string);
public String getString();
}

Three methods have been defined, firstly the init() method is a non exposed method which we will call from one of our extended classes to pass our persistent object in (much more on this later). The ‘get and set’ methods are public and will be exposed via xml-rpc, hopefully you can imagine what is going on in the underlying implementation, if not take a look at the ‘ExposedMethodsImplementation.java’
file provided in the example code.

A Sample Persistent Object

The persistent object for this example is incredibly simple, it exists solely to keep this example simple. The code is so short that I will include it here:

public class Pobject {
private String storedString = “”;
public synchronized void setString(String string){
storedString = string;
}
public synchronized String getString(){
return storedString;
}
}

As you can see, all it does is store a string and then allows the programmer the ability to ‘get and set’ the string.

Here lies the problem

Someone who is not familiar with the ws-xmlrpc 3.0 tool-kit may be thinking:

“Why do I even need an object like this? surely something as simple as a string could be stored in my handler class?”

This is where the problem begins, the user handler classes are completely stateless, up-to the point that a new instance of the handler class is created to handle each individual xml-rpc request. After the request is completed the handler instance is disposed of - never to be used again.

A solution to the problem

To get around this problem, one can call methods of the handler class after it has been initialised and just before it handles an xml-rpc request. Once one has the required knowledge this is a relatively simple task. However, judging by my experience and messages on the Apache xml-rpc mailing list, there is some confusion regarding how one can do this.

To access methods of the handler class in this way, three of the ws-xmlrpc classes must be extended and the correct methods within them must be overridden / extended. In the sample code there is another class which has been extended (AuthenticationHandler by BmAuthHandler.java) This includes another example from the ws-xmlrpc FAQ which explains how to enable basic HTTP authentication. I have left this in to provide a more complete example.

The classes call each other in the following Hierarchy:

ServletServer

|____> XmlRpcServlet
|____> RequestSpecificProcessorFactoryFactory
|____> Can make calls to user handler methods.\

We will be extending the XmlRpcServlet class and the RequestSpecificProcessorFactoryFactory class. It is within the XmlRpcServlet that your persistent objects will be initialised, it is within the RequestSpecificProcessorFactoryFactory class that you will make calls to your handler methods.

Your very own ‘ServletServer’

Making use of the ServletWebServer class is very simple and is the starting point of your standalone Apache ws-xmlrpc 3.0 server. The ServeletServer class merely initialises your servlet (in this case one that we have extended ourselves) and then starts up the servlet web server on the specified port. See the file:
‘org/buttermountain/xmlrpc/server/ServletServer.java’ for details.

Extending the XmlRpcServlet

The XmlRpcServlet is persistent, it is only initialised once (when using ServletServer, I have not tested this with anything else (such as TomCat)). This class is extended within ‘org/buttermountain/xmlrpc/server/BmXmlRpcServlet.java’. It is here that the example persistent
object (Pobject) class is initialised:

private Pobject pobject = new Pobject();

Within BmXmlRpcServlet The methods ‘isAuthenticated’ and ‘XmlRpcHandlerMapping’ are used to handle basic HTML authentication, you may ignore those for the purposes of this example. The method that we are interested in is the newPropertyHandlerMapping method. Is is
within this method that we initialise our next (and final) extended class the BmProcessorFactory which extends the RequestSpecificProcessorFactoryFactory class.

Extending the RequestSpecificProcessorFactoryFactory

The RequestSpecificProcessorFactoryFactory is an incredibly long variable name, my extended version of this class uses a much shortened name ‘BmProcessorFactory’ it can be found here ‘org/buttermountain/xmlrpc/server/BmProcessorFactory.java’. It is within this class
that you can actually call methods on your handler class.

I have implemented the ProcessorFactory in the following way, the initialisation method for this class takes in our persistent object from the XmlRpcServlet. The getRequestProcessor() method is then overridden, it is in this method that we make calls to our handler methods.

If you remember the ExposedMethodsInterface class had a method called ‘init()’ which took an object of type Pobject. The implementation for this method looks like this:

public void init(Pobject pobject){
this.pobject = pobject;
}

The variable ‘pobject’ is declared in the main body of the class allowing it to be accessible from all of the methods. This method is called from the BmProcessorFactory in the following way:
ExposedMethodsInterface proc = (ExposedMethodsInterface)
super.getRequestProcessor(pClass, pRequest);
proc.init(pobject);
return proc;

Finally in that one line ‘proc.init(pobject)’ you can pass the persistent object to your handler class. It would be here that you could call any other methods you may want to on your handler method, one thing you must make sure is that all of your handler classes implement an init() method in the same way. Any handler classes which do not will throw an XmlRpcException and refuse to work.

Pulling it all together

Before the xml-rpc server can be run you must create a mapping file, this file creates a mapping between exposed method names and method names local to java. The included file to handle this is called ‘XmlRpcServlet.properties’ and looks like this:

ExposedMethodsInterface=org.buttermountain.xmlrpc.server.ExposedMethodsImplementation
org.buttermountain.xmlrpc.server.ExposedMethodsInterface=org.buttermountain.xmlrpc.server.ExposedMethodsImplementation

The default location of this file is ‘org/apache/xmlrpc/webserver/XmlRpcServlet.properties’, However, I have overridden this location in the newXmlRpcHandlerMapping method of our BmXmlRpcServlet class.

Starting the xmlrpc server

The source I’ve included has a file listing the relative classpath (./classpath) and another file listing all of the source files (./sourcefiles).

Under Linux the following steps can be taken to compile and execute the code (assuming that java/javac are in your $PATH)

user@host $ ~/xmlrpc-example> export CLASSPATH=`cat classpath`
user@host $ ~/xmlrpc-example> javac @sourcefiles
user@host $ ~/xmlrpc-example> java org/buttermountain/xmlrpc/server/ServletServer
04-Nov-2006 21:16:06 org.apache.xmlrpc.webserver.XmlRpcServlet log
INFO: init

If you’ve not changed anything the Apache ws-xmlrpc server should now be running on localhost port 5555

Testing the example server

To make things even easier I’ve included two clients, one written in Java (ProxyClient.java) which is code taken from the Apache ws-xmlrpc client FAQ and one written in Python. Both clients perform the same operations but set a different string. These two clients should prove to you that the xml-rpc server is working as intended.

Under Linux (again) make sure you have started the server (as mentioned above), now in another terminal:

user@host $ ~/xmlrpc-example> export CLASSPATH=`cat classpath`
user@host $ ~/xmlrpc-example> python python_client/client.py
The oldstring was: <<< note: the default string is ""
setting string to: python xmlrpc client
The string is now: python xmlrpc client

user@host $ ~/xmlrpc-example> java org/buttermountain/xmlrpc/client/ProxyClient
The oldstring was: python xmlrpc client
setting string to: java xmlrpc client
The string is now: java xmlrpc client

Take a look at the source code of both those examples if you wish to see how they work in more detail, the output should look something like the above.

Note: The client and server code should work under any operating system where Java & Apache ws-xmlrpc 3.0 are supported. The Python client should work under any operating system which supports Python.
i.e the code should run on systems other than Linux.

Conclusion

I hope that this example will be useful to people attempting to use the Apache ws-xmlrpc 3.0 tools. If you have any questions / comments etc, please drop me an email.

Thank you to the kind people of the Apache ws-xmlrpc mailing list who helped me get to a working solution and to the Apache ws-xmlrpc developers who have created a fantastic (although sometimes complicated) tool kit.