Java XML-RPC: Example

In this section, we shall develop a simple client-server application using XML-RPC. In this application, the server creates a factorial object on which a single method fact() can be invoked. The client invokes this method using the procedure described in XML-RPC specification.

1. Writing the server

Before setting up the server, let us develop a class for factorial object. The following is the source code of class (stored in Factimpl.java file):

public class Factlmpl {

public int fact(int n) {

System.out.println(”Received : ”+n);

int prod = 1;

for(int i = 2; i <= n;i++)

prod *= i;

System.out.println(”Sent : ”+prod);

return prod;

}

}

This class has only on method fact() that takes a single integer (should be non-negative) and returns the factorial of that integer.

Let us now develop a server program that is capable of handling a method invocation request coming from clients over HTTP as XML-RPC request message. The simplest way to do this is to create an instance of org.apache.xmlrpc.webserver.WebServer as follows:

Webserver webServer = new WebServer(6789);

A WebServer object is a minimal HTTP server that can handle only XML-RPC messages. It enables us to set up XML-RPC in hosts even if they have no web server installed in them previously. Note that the WebServer class does not implement full HTTP and is not capable of serving web pages. The above webServer listens for XML-RPC requests on the port 6789.

This webServer itself is not capable of calling a method on an object. This functionality is provided by org.apache.xmlrpc.server.XmlRpcServer class. So, internally, it maintains an XmlRpcServer object, a reference to which may be obtained as follows:

XmlRpcServer rpcServer = webServer.getXmlRpcServer();

The XmlRpcServer class has a method execute() ,which can invoke a method for a given XmlRpcRequest. This XmlRpcRequest class encapsulates an XML-RPC request. The functionality of a WebServer object is as follows:

  • Upon receiving an XML-RPC request message, it processes its header and XML body.
  • It then extracts method name and parameters from the given XML body.
  • It creates an XmlRpcRequest object with this information.
  • It then invokes the execute() method on its internal XmlRpcServer object passing XmlRpcRequest object and records the result
  • Finally, it creates an XML body with this result for the XML-RPC response message.
  • This XML response body is then embedded in an XML-RPC request message and sent back to the client.

The rpcServer object, on the other hand, maintains a list of named objects on which methods may be invoked. However, rpcServer does not so far have any such list. To create this list, we instantiate a org.apache.xmlrpc.server.PropertyHandlerMapping object as follows:

PropertyHandlerMapping mapping = new PropertyHandlerMapping();

This object basically maps objects to unique names. In other words, given a name, the underlying object may be obtained. The addHandler() method on this object is usually used to create named objects as follows:

mapping.addHandler(”Factorial”, FactImpl.class);

The addHandler() method takes two parameters. The second parameter is a Class (FactImpl. class in our case) of the target object and the first parameter is a String, which is the name (“Factorial” in our case) of the target object. This name “Factorial” is used by the clients to refer to the object during method invocation.

Note that no object is created at this time. The object is created when the method invocation request comes for the first time. A zero argument constructor is used to create this object. This implies that the object’s class must have such a constructor. In our FactImpl class, since we have not written any constructor explicitly, a zero argument constructor is present that will be used to create an instance of this class.

Our task is now to inform this mapping to the rpcServer as follows:

rpcServer.setHandlerMapping(mapping);

Finally, we start the web server so that it can listen for HTTP connection.

webServer.start();

The start() method spawns a new thread, which binds this server to the port, it was configured, to accept connections on. The webServer is now capable of receiving XML-RPC POST request messages. The complete source of our first server (Server1.java) is shown below:

//Serverl.java

import org.apache.xmlrpc.server.*;

import org.apache.xmlrpc.webserver.*;

public class Serverl {

public static void main(String args[]) {

try {

WebServer webServer = new WebServer(6789);

XmlRpcServer rpcServer = webServer.getXmlRpcServer();

PropertyHandlerMapping mapping = new PropertyHandlerMapping(); mapping.addHandler(”Factorial”, FactImpl.class); rpcServer.setHandlerMapping(mapping);

webServer.start();

System.out.println(”XML-RPC server ready…”);

}catch(Exception e) {e.printStackTrace();}

}

}

2. Writing the client

Writing XML-RPC client is relatively simple. The org.apache.xmlrpc.client package provides the necessary classes and interface for this. The basic steps are as follows:

  • We create an XmlRpcClient object and configure it so that it can contact the server.
  • We specify the name of the method to be invoked and necessary parameters.
  • The method invocation request is done using executed method on this object.
  • Finally, we display the result returned by executed

First, we create an XmlRpcClient object as follows:

XmlRpcClient client = new XmlRpcClient();

This client does not have any information about the XML-RPC server. So, it has to be configured properly. This is done by creating an XmlRpcClientConfigimpl object as follows:

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();

The URL of the XML-RPC server is specified in the setServerURL() as follows:

config.setServerURL(new URL(“http://”+args[0]+”:6789/”));

We are assuming that during the execution of the client, the IP address of the server is supplied as an argument. Note that the port number 6789, on which the web server listens, is used here. This configuration information is then passed to the client.

client.setConfig(config);

At this point, the client knows the URL of the server. Now, we have to specify the name method name and its parameters. Since, the fact() method takes only one integer as parameter, we create an array of one Integer object as follows:

int n = 6;

Object[] params = new Object[]{ new Integer(n)};

Note that, parameters must always be passed as an array of Object elements. So, primitive values may be converted to the Object type using their respective wrapper classes. In this case, we have used Integer class which is the wrapper class for primitive type int. Finally, to invoke the method fact() on the server object (known as “Factorial”), the following piece of code is used:

Integer result = (Integer)client.execute(“Factorial.fact”, params);

The string Factorial.fact refers to the method fact() on an object whose name is Factorial. Note that, in the server program this name was assigned to the factorial object. The executed method creates XML-RPC request message and forwards it to the server. A sample message is shown below:

POST / HTTP/1.1

Content-Type: text/xml

User-Agent: Apache XML RPC 3.1.3 (Sun HTTP Transport)

Cache-Control: no-cache Pragma: no-cache Host: 172.16.5.81:6789

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive Content-Length: 187

<?xml version=”1.0” encoding=”UTF-8”?>

<methodCall>

<methodName>Factorial.fact</methodName>

<params>

<param>

<value><i4>6</i4></value>

</param>

</params>

</methodCall>

Note that the method invocation information is encoded in XML and is included in the body of the request message. The server in turn responds with an XML-RPC message as follows:

HTTP/1.1 200 OK Server: Apache XML-RPC 1.0 Connection: close Content-Type: text/xml Content-Length: 155

<?xml version=”1.0″ encoding=”UTF-8″?>

<methodResponse>

<params>

<param>

<value><i4>720</i4></value>

</param>

</params>

</methodResponse>

Here, method’s return value is also encoded in XML and is included in the body of the response message. The result is then displayed as follows:

System.out.println(“Received : “+result);

The complete source of our first client (clienti.java) is shown below:

//Clientl.java

import org.apache.xmlrpc.client.*;

import java.net.URL;

public class Client1 {

public static void main (String [] args) {

try {

XmlRpcClient client = new XmlRpcClient();

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL(new URL(“http://”+args[0]+”:6789/”)); client.setConfig(config); int n = 6;

Object[] params = new Object[]{ new Integer(n)};

System.out.println(“Sent : ”+n);

Integer result = (Integer)client.execute(“Factorial.fact”, params);

System.out.println(”Received : ”+result);

} catch (Exception e) {

e.printStackTrace();

}

}

}

3. Running the application

Create the following directory structure in the XML-RPC server computer. Now, place all Apache XML-RPC .jar files in lib directory and place FactImpl.java and Server1.java in server directory. Open a terminal and go to the server directory. Use the following command to compile Java files.

javac -cp ..\lib\*;. FactImpl.java Server1.java

This generates two class files: Server1.class and FactImpl. class. The XML-RPC server can be started using the following command:

java -cp ..\lib\*;. Server1

This generates an output as follows:

To run our client program, create the following directory structure in another computer. If you do not have another computer, then create this client sub­directory under xmlrpc directory where you created lib and server sub-directories previously. Now, place all Apache XML-RPC .jar files in lib directory and place Clienti.java in client directory. Open a terminal and go to the client directory. Use the following command to compile Java files.

javac -cp ..\lib\*;. Clienti.java

This generates one class files: Clienti.class. Make sure that the directory containing javac compiler is included in the path environment variable. We assume that the XML-RPC server is running in a computer having IP address 172.16.5.81. The XML-RPC client can be started using the following command: java -cp ..\lib\*;. Clienti 172.16.5.81

If the computer running your server has a different IP address, use that address in place of the above mentioned IP address. A sample result for both server and client is shown in Figure 17.6:

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *