Remember that, in the previous client application, we have invoked a method using execute() method of xmlRpcClient object passing method name and parameters. This way of method invocation is neither straightforward nor matches the usual method call syntax. For example, it would have been convenient if we could have invoked a method as follows:
int result = obj.fact(6);
Apache XML-RPC dynamic proxy allows us to invoke remote methods using traditional method invocation syntax. However, to use this facility, remote object’s class is implemented in a slightly different way. First, we write an interface which is used by both server and client. The following is a simple interface (stored in Fact.java file) for our factorial object.
//Fact.java
public interface Fact {
public int fact(int n);
}
The Factimpi class should implement this interface. So, modify the Factimpl.java file as follows:
public class Factimpi implements Fact {
The added portion is shown with bold font. Now, use the name of interface during the object mapping as follows:
mapping.addHandler(Fact.class.getName(), Factimpl.class);
Note that Fact.class.getName() method returns the name of the interface (i.e. Fact). This is necessary because clients using dynamic proxy always use object’s interface name during method invocation. Alternatively, the name may be hardcoded as follows:
mapping.addHandler(”Fact”, FactImpl.class);
The modified code is stored in a separate file (Server2.java) as follows:
//Server2.java
import org.apache.xmlrpc.server.*;
import org.apache.xmlrpc.webserver.*;
public class Server2 {
public static void main(String args[]) {
try {
WebServer webServer = new WebServer(6789);
XmlRpcServer rpcServer = webServer.getXmlRpcServer();
PropertyHandlerMapping mapping = new PropertyHandlerMapping();
mapping.addHandler(Fact.class.getName(), FactImpl.class);
rpcServer.setHandlerMapping(mapping);
webServer.start();
System.out.println(”XML-RPC server ready…”);
}catch(Exception e) {e.printStackTrace();}
}
}
The modified portion is shown with bold font. The client, on the other hand, does not use executed method XmlRpcClient object to invoke methods. Instead, it creates a ClientFactory with a specified XmlRpcClient object as follows:
XmlRpcClient client = new XmlRpcClient();
//configure this object
ClientFactory factory = new ClientFactory(client);
The newInstance() method of factory is then used to create a proxy dynamically for a given interface.
Fact dProxy = (Fact) factory.newInstance(Fact.class);
This dProxy can then be used to invoke methods using the usual method invocation syntax.
int result = dProxy.fact(n);
The dynamic proxy internally calls the server by using the XmlRpcClient. The modified code is stored in a separate file (Client2.java) as follows:
//Client2.java
import org.apache.xmlrpc.client.*; import java.net.URL;
import org.apache.xmlrpc.client.util.ClientFactory;
public class Client2 {
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);
ClientFactory factory = new ClientFactory(client);
Fact dProxy = (Fact) factory.newInstance(Fact.class);
int result = dProxy.fact(n);
System.out.println(“Received : “+result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The added portion is shown with bold font and unnecessary code used in Clienti.java is placed under the comment lines.
Compile and start this application as described previously. Note that the class file for Fact interface (i.e. Fact.ciass) in needed by both client and server. A sample result is shown in Figure 17.7:
Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.