Development Techniques


We’re ready to start looking at the details of the Apache XML-RPC library. One of the design goals for the XML-RPC library is to be as simple as possible for developers to use—and, as you’ll see, the XML-RPC API is straightforward to use. You’ll write a series of XML-RPC clients and servers that implement a service that allows you to create books. You won’t use your book schema directly, but you’ll use it as a guide to help you design the service. When you create a book, you need the author, title, ISBN number, month, year, publisher, and publisher’s address. This information will be passed to the XML-RPC client-side libraries as RPC arguments, and the information will also be extracted from the RPC arguments delivered on the server side. We’ll cover the latest stable release, Apache XML-RPC 1.1. Let’s begin by looking at a client program for calling the book service.

A Simple Client

Apache XML-RPC provides two classes you can use to invoke a remote procedure: org.apache.xmlrpc .XmlRpcClient and org.apache.xmlrpc.XmlRpcClientLite. Let’s start with XmlRpcClientLite, just to keep thing simple. It doesn’t really make things much simpler from the point of view of writing an application, because XmlRpcClient and XmlRpcClientLite share the same API:

  1: /*   2:  *    3:  * BasicClient.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.IOException;  11: import java.net.MalformedURLException;  12: import java.util.Vector;  13:   14: import org.apache.xmlrpc.XmlRpcClientLite;  15: import org.apache.xmlrpc.XmlRpcException;  16:   17: public class BasicClient {  18:   19:     public static void main(String[] args) {

Because you’re just calling a method to demonstrate the API, you do it from the class’s main method.

The first thing you need is a class that lets you invoke the procedure. In this case, that’s an instance of XmlRpcClientLite. The instance serves as a proxy for the remote server you want to use. When you’re creating an instance of XmlRpcClientLite, you need to pass the information about the server to the constructor. This information can be specified as a String, as a hostname and port number, or as a java.net.URL. In this example, you’re talking to a server that’s running on the same machine as the client, and the server is listening on port 8080. Because XML-RPC leverages the HTTP infrastructure, you can expect to see HTTP and HTTPS URLs frequently:

 20:         XmlRpcClientLite s = null;  21:           22:         try {  23:             s = new XmlRpcClientLite("http://localhost:8080");

The key to keeping the client-side API simple is right here. XmlRpcClientLite uses a java.util.Vector to create a vector of the arguments to the RPC. Note that the contents of the Vector can be any types necessary for the RPC. In particular, they don’t all have to be the same type:

 24:         } catch (MalformedURLException mue) {  25:             mue.printStackTrace();  26:         }  27:           28:         Vector params = new Vector();  29:         params.addElement("Theodore W. Leung");  30:         params.addElement(  31:             "Professional XML Development with Apache Tools");  32:         params.addElement("0-7645-4355-5");  33:         params.addElement("December");  34:         params.addElement(new Integer(2003));  35:         params.addElement("Wrox");  36:         params.addElement("Indianapolis, Indiana");

You invoke the RPC by calling the execute method on XmlRpcClientLite. This method takes a String argument containing the name of the procedure and the Vector of arguments. When you make an XML-RPC call that talks to the Apache XML-RPC library, you have to prefix the method name with the name of the handler registered with the Apache XML-RPC server. In this example, you’re invoking the function createBook that’s defined by the handler registered under the name books. If you were using XML-RPC to call a procedure being exposed by a different XML-RPC runtime, then you’d need to obey whatever conventions that system had for method names:

 37:           38:         try {  39:             Boolean result = (Boolean)  40:                 s.execute("books.createBook", params);

The result of calling execute is an Object representing the XML-RPC result. The createBook function returns a Boolean value, so you need to cast the return value to the correct type before you display it (line 41):

 41:             System.out.println(result);  42:         } catch (XmlRpcException xre) {  43:             xre.printStackTrace();  44:         } catch (IOException ioe) {  45:             ioe.printStackTrace();  46:         }  47:     }  48: }

Those are the basics of using the Apache XML-RPC client APIs to invoke an XML-RPC procedure.

Mapping to Java Types

One of the big issues in using XML-RPC is understanding how the XML-RPC types are represented by the language and XML-RPC runtime library you’re using. Recall that XML-RPC defines a limited set of types that can be passed as arguments or returned as results. The right column in the following table shows which Java types correspond to the various XML-RPC types when you’re making an RPC. These are the types you can put into the Vector of parameters. Putting some other type into the Vector will cause an error.

XML-RPC Type

RPC Handler Argument Type

<i4> or <int>

Int

<boolean>

Boolean

<string>

java.lang.String

<double>

Double

<dateTime.iso8601>

java.util.Date

<struct>

java.util.Hashtable

<array>

java.util.Vector

<base64>

byte[]

The next table shows the values returned from the execute method. Note that all the Java primitive types have been replaced with their Object wrappers.

XML-RPC Type

RPC Result Type

<i4> or <int>

java.lang.Integer

<boolean>

java.lang.Boolean

<string>

java.lang.String

<double>

java.lang.Double

<dateTime.iso8601>

java.util.Date

<struct>

java.util.Hashtable

<array>

java.util.Vector

<base64>

byte[]

A Simple Server

Next, let’s look at a simple implementation of a server using the Apache XML-RPC APIs:

  1: /*   2:  *    3:  * BasicServer.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.FileWriter;  11: import java.io.IOException;  12: import java.io.PrintWriter;  13:   14: import org.apache.xmlrpc.WebServer;  15:   16: public class BasicServer {  17:   18:     public Boolean createBook(String author, String title,   19:                               String isbn, String month,   20:                               int year, String publisher,   21:                               String address) {  22:         try {  23:             PrintWriter w =   24:                 new PrintWriter(new FileWriter(isbn+".txt"));  25:             w.println(author);  26:             w.println(title);  27:             w.println(isbn);  28:             w.println(month);  29:             w.println(year);  30:             w.println(publisher);  31:             w.println(address);  32:             w.close();  33:         } catch (IOException e) {  34:             e.printStackTrace();  35:             return Boolean.FALSE;  36:         }  37:         return Boolean.TRUE;  38:     }

The createBook method is the procedure you want to make available remotely. Note that XML-RPC has no notion of objects—only calling procedures. When you make a procedure available to remote callers, you should keep this in mind. Remote procedures are exposed via XML-RPC more like the doGet or doPost methods in a servlet. Your procedure shouldn’t rely on instance variables except for things like statistics. The types of the arguments to the procedure and the type of the return value must be taken from the lists in the tables in the previous section.

The Apache XML-RPC library provides a few classes to make it easy to implement an XML-RPC server. The simplest is org.apache.xmlrpc.WebServer, which includes a simple HTTP server that does just what’s needed for XML-RPC. You create a WebServer that listens on port 8080 on the current machine:

 39:   40:     public static void main(String[] args) {  41:         BasicServer handler = new BasicServer();  42:           43:         WebServer s = null;  44:           45:         try {  46:             s = new WebServer(8080);

Once the WebServer instance is running (it starts up when it’s constructed), all you need to do is tell it how to handle RPC requests. This is easily accomplished using the addHandler method. This method takes a String that’s the handler name and a Java object:

 47:         } catch (IOException ioe) {  48:             ioe.printStackTrace();  49:         }  50:   51:         s.addHandler("books", handler);  52:     }  53: }

As we mentioned earlier, to call a procedure on the handler object, you must prefix the method name with the handler name and a period. Here you use the BasicServer class as the handler, so the name you supply to invoke createBook is books.createBook. When a client invokes an RPC on the WebServer, the Apache XML-RPC runtime takes the handler class and looks for a method with the right name on the right handler (you can register multiple handlers). It then looks at the method’s argument list and tries to match the types of the parameters in the XML-RPC document with the types of the parameters in the method. It uses the rules from the earlier table to do this. If the types match up, then the runtime calls the method and returns the result.

Asynchronous Clients

Let’s go back to the client side and look at some of the other options you have for writing XML-RPC clients. In the next example, we’ll explore the full XmlRpcClient as well as writing an asynchronous client using AsyncCallback.

The full XmlRpcClient provides the same API as the lighter XmlRpcClientLite class. The major difference is that XmlRpcClient uses the built-in java.net.URLConnection class, whereas XmlRpcClientLite implements its own, less functional HTTP support. In particular, if you need support for HTTP proxies, cookies, or HTTP redirection, you need to use XmlRpcClient. The advantage of using XmlRpcClientLite is that it can be much faster than XmlRpcClient, particularly if HTTP keep-alive support is turned on (you’ll see this in the example).

The other approach we’ll demonstrate in this example is the use of an asynchronous processing model in the client. Instead of the client code waiting for the RPC return, you’ll allow that client code to proceed after invoking the RPC. When the RPC returns, processing is handled by a callback function that’s been registered for that RPC invocation. This event-driven style of programming should be familiar from SAX programming or AWT/Swing programming. The major benefit of the asynchronous style is that it allows the application to continue processing while a (potentially) long-running RPC executes.

In order to use asynchronous processing, you need a callback class that implements the org.apache.xmlrpc.AsyncCallback interface. Here you use the client class as the client callback handler:

  1: /*   2:  *    3:  * AsyncClient.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.net.MalformedURLException;  11: import java.net.URL;  12: import java.util.Vector;  13:   14: import org.apache.xmlrpc.AsyncCallback;  15: import org.apache.xmlrpc.XmlRpc;  16: import org.apache.xmlrpc.XmlRpcClient;  17:   18: public class AsyncClient implements AsyncCallback {

You must implement two methods from the AsyncCallback interface: handleResult and handleError. The handleResult method is called if the RPC returned a good result. The arguments are an Object representing the result of the RPC, a URL representing the URL for the XML-RPC, and a String containing the method that was invoked. The url and method arguments are necessary because a handler can provide more than one method, so you may need to use the value of method to determine how to process the results. Here you display the values of the RPC. The AsyncCallbackHandler methods run in a separate thread from the main application, so depending on your application, you may need to perform some thread synchronization in this method:

 19:   20:     public void handleResult(Object result, URL url,   21:                               String method) {  22:         System.out.println(result);  23:         System.out.println(url);  24:         System.out.println(method);  25:     }

The handleError method is called if the RPC fails. The url and string arguments are the same as for handleResult and serve the same purpose. The difference is that the first argument is an Exception that represents the XML-RPC fault:

 26:   27:     public void handleError(Exception exc, URL url,   28:                              String method) {  29:         System.out.println(exc);  30:         System.out.println(url);  31:         System.out.println(method);  32:     }

The XmlRpc class contains a pair of static methods that control the configuration of XmlRpcClient (and XmlRpcClientLite) instances. The setDebug method turns on debug logging that displays the name of the procedure being called and its arguments. It also prints the names of the XML elements in the XML-RPC response as it receives them. HTTP’s keep-alive feature can improve the performance of repeated XML-RPC calls to the same handler. Calling setKeepAlive turns this feature on (true) and off (false):

 33:   34:     public static void main(String[] args) {  35:         XmlRpc.setDebug(true);  36:         XmlRpc.setKeepAlive(true);

Creating an instance of XmlRpcClient (line 40) is the same as creating an instance of XmlRpcClientLite, and so is preparing the Vector of parameters:

 37:           38:         XmlRpcClient s = null;  39:         try {  40:             s = new XmlRpcClient("http://localhost:8080");  41:         } catch (MalformedURLException mue) {  42:             mue.printStackTrace();  43:         }  44:           45:         Vector params = new Vector();  46:         params.addElement("Theodore W. Leung");  47:         params.addElement(  48:             "Professional XML Development with Apache Tools");  49:         params.addElement("0-7645-4355-5");  50:         params.addElement("December");  51:         params.addElement(new Integer(2003));  52:         params.addElement("Wrox");  53:         params.addElement("Indianapolis, Indiana");

Apache XML-RPC also provides support for HTTP BASIC authentication, which requires a username and password. The setBasicAuthentication method allows you to specify the username and password that are presented to the XML-RPC server:

 54:           55:         s.setBasicAuthentication("twl","password");

Making an asynchronous call is a little harder than making a synchronous call. You need an instance of AsyncCallback (line 57) that you can pass as the last argument of the executeAsync method (line 58). The first and second arguments to executeAsync are the same as for execute. The call returns immediately, and when the XML-RPC returns, the handler specified in the executeAsync call is used to process the results. The executeAsync method is also available on the XmlRpcClientLite class:

 56:           57:         AsyncCallback handler = new AsyncClient();  58:         s.executeAsync("books.createBook", params, handler);  59:           60:         System.out.println("finished.");  61:     }  62: }

Getting More Control Over Server Processing

The Apache XML-RPC library gives you a way to write a server that has complete control over how to process an XML-RPC call. It does this by providing an interface called org.apache.xmlrpc .XmlRpcHandler. Your handler then implements XmlRpcHandler to get control of the RPC processing. This is a big change from the way you implemented the basic server earlier—in that case, an RPC handler was just a class that had a method with the right name and signature.

The HandlerServer class implements XmlRpcHandler so you can keep everything in a single class, in the interest of brevity:

  1: /*   2:  *    3:  * HandlerServer.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.FileWriter;  11: import java.io.IOException;  12: import java.io.PrintWriter;  13: import java.util.Vector;  14:   15: import org.apache.xmlrpc.WebServer;  16: import org.apache.xmlrpc.XmlRpcHandler;  17:   18: public class HandlerServer implements XmlRpcHandler {

The XmlRpcHandler interface defines only a single method: execute. Execute takes the name of the method the client wants to invoke and a Vector containing the arguments after they’ve been parsed out of the XML-RPC document, according to the rules from the earlier table. If you were hoping to get your hands on the actual XML for the XML-RPC call, you’re out of luck. You can put any code you like in the body of execute. Your handler’s don’t have to be methods on an object. You’re free to implement the XML-RPC processing any way you like.

 19:   20:     public Object execute(String method, Vector params)   21:         throws Exception {  22:         try {  23:             PrintWriter w =   24:                 new PrintWriter(  25:                     new FileWriter(params.elementAt(2)+".txt"));  26:               27:             for (int i = 0; i < params.size(); i++) {  28:                 w.println(params.elementAt(i));  29:             }  30:             w.close();  31:         } catch (IOException e) {  32:             e.printStackTrace();  33:             return Boolean.FALSE;  34:         }  35:         return Boolean.TRUE;          36:     }

Creating the server and registering the handler proceed the same as before; you just change the handler to implement the XmlRpcHandler interface:

 37:   38:     public static void main(String[] args) {  39:         HandlerServer handler = new HandlerServer();  40:           41:         WebServer s = null;  42:         try {  43:             s = new WebServer(8080);  44:         } catch (IOException ioe) {  45:             ioe.printStackTrace();  46:         }  47:         s.addHandler("books", handler);  48:     }  49: }

Handling BASIC Authentication on the Server

The most common (albeit not the safest) method of performing authentication at the HTTP level is to use HTTP’s BASIC authentication method. It involves providing the HTTP server with a base64-encoded username and password. You’ve already seen how Apache XML-RPC client libraries provide support for specifying the username and password via the setBasicAuthentication method. On the server side, you get support for BASIC authentication by implementing the org.apache.xmlrpc.AuthenticatedXMLRpcHandler interface.

Using AuthenticatedXmlRpcHandler is very similar to using XmlRpcHandler, except the signature of the execute method is different. In addition to the method name and Vector of parameters, execute also expects a pair of Strings containing the username and password supplied to the BASIC authentication method. You can then check these values in the body of the execute method:

  1: /*   2:  *    3:  * AuthHandlerServer.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.FileWriter;  11: import java.io.IOException;  12: import java.io.PrintWriter;  13: import java.util.Vector;  14:   15: import org.apache.xmlrpc.AuthenticatedXmlRpcHandler;  16: import org.apache.xmlrpc.WebServer;  17:   18: public class AuthHandlerServer   19:     implements AuthenticatedXmlRpcHandler {  20:   21:     public Object execute(String method, Vector params,   22:                            String user, String password)   23:                            throws Exception {  24:         if (!user.equals("user") || !password.equals("password"))  25:             throw   26:                 new IllegalArgumentException(  27:                     "Authentication failed");  28:   29:         try {  30:             PrintWriter w =  31:                 new PrintWriter(  32:                   new FileWriter(params.elementAt(2) + ".txt"));  33:   34:             for (int i = 0; i < params.size(); i++) {  35:                 w.println(params.elementAt(i));  36:             }  37:             w.close();  38:         } catch (IOException e) {  39:             e.printStackTrace();  40:             return Boolean.FALSE;  41:         }  42:         return Boolean.TRUE;  43:     }  44:   45:     public static void main(String[] args) {  46:         AuthHandlerServer handler = new AuthHandlerServer();  47:           48:         WebServer s = null;  49:   50:         try {  51:             s = new WebServer(8080);  52:         } catch (IOException ioe) {  53:             ioe.printStackTrace();  54:         }  55:   56:         s.addHandler("books", handler);  57:     }  58: }

XML-RPC in Existing Servers

Up to now you’ve been working with the Apache XML-RPC library’s stand-alone Web server. But what do you do when you need to provide services via XML-RPC and you already have a Web server? One answer would be to use the stand-alone Web server but have it listen on a different port. This approach may work in some situations but may not work in others. Firewall administrators will probably be unwilling to open a new port to allow XML-RPC services. In these cases, you need a way to provide XML-RPC services using your existing Web server. If you’re using a Java-based Web server like Tomcat, Jetty, or the Web container of a J2EE application server, then the Apache XML-RPC libraries provide a way for you to offer XML-RPC services without using the stand-alone server.

This capability is provided by the class org.apache.xmlrpc.XmlRpcServer, which operates on a java.io.InputStream that’s assumed to contain an XML-RPC request. Let’s examine how to use this class in the context of a servlet:

  1: /*   2:  *    3:  * XMLRPCServlet.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.IOException;  11: import java.io.OutputStream;  12:   13: import javax.servlet.ServletException;  14: import javax.servlet.http.HttpServlet;  15: import javax.servlet.http.HttpServletRequest;  16: import javax.servlet.http.HttpServletResponse;  17:   18: import org.apache.xmlrpc.XmlRpcServer;  19:   20: public class XMLRPCServlet extends HttpServlet {  21:     XmlRpcServer s = null;  22:   23:     public void init() throws ServletException {  24:         s = new XmlRpcServer();  25:           26:         s.addHandler("books", new BasicServer());

You use the init method to avoid creating instances of XmlRpcServer over and over. After you create an instance of XmlRpcServer (line 24), you set it up by registering handlers for the procedures you want to expose via XML-RPC. You can use any of the handler implementations you’ve seen so far. You can supply a Java object and let Apache XML-RPC find the right method to call (as you do here in line 26), or you can supply an object that implements either XmlRpcHandler or AuthenticatedXmlRpcHandler. Once all the handlers are registered, you’re ready to open the servlet for business.

Because XML-RPC is defined to use the HTTP POST method for its transport, you only have to implement the doPost method in your servlet:

 27:     }  28:  29:     protected void doPost(HttpServletRequest req,   30:                            HttpServletResponse res)  31:         throws ServletException, IOException {  32:         byte[] result = s.execute(req.getInputStream());

Line 32 does all the work. XmlRpcServer provides two methods for executing XML-RPC calls. The version you see here takes an InputStream containing the XML-RPC request document. This request is processed according to the handlers registered with the server instance, and the response XML-RPC document is returned as a byte array. The other execute method takes an additional pair of string arguments that should contain a username and password for authentication purposes. If you’re using XML-RPC inside a J2EE Web container, you’re probably better off using the J2EE declarative security mechanisms, especially if they’re used in other parts of your application. For this purpose, treat the XML-RPC code like any other servlet that needs protection.

The rest of the code in the servlet is devoted to setting up the servlet response. You have to set the response’s content type to "text/xml" (line 34) and provide the correct value for the HTTP Content-Length header (line 35). After you’ve done this, you can take the byte array you obtained from the execute method and send its contents to the servlet’s response stream:

 33:           34:         res.setContentType("text/xml");  35:         res.setContentLength(result.length);  36:           37:         OutputStream out = res.getOutputStream();  38:         out.write(result);  39:         out.flush();  40:     }  41: }

The following listing shows the web.xml file you need to provide to a servlet container in order to make the servlet available to the world. Note that clients need to use the full URL for the servlet, which typically contains the name of the Web application. For example, on our test server, clients need to specify the URL http://localhost:8080/apache-xml-book-web-xmlrpc/RPC2/ as the URL of the XML-RPC server:

  1: <?xml version="1.0" encoding="ISO-8859-1"?>   2:    3: <!DOCTYPE web-app   4:   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   5:   "http://java.sun.com/dtd/web-app_2_3.dtd">   6:    7: <web-app>   8:   <display-name>Professional XML Development with Apache Tools Examples   9:   </display-name>  10:   <description>  11:     Examples from Professional XML Development with Apache Tools.  12:   </description>  13:   14:   <servlet>  15:     <servlet-name>XMLServlet</servlet-name>  16:     <servlet-class>  17:       com.sauria.apachexml.ch8.XMLRPCServlet  18:     </servlet-class>  19:   </servlet>  20:         21:   <servlet-mapping>  22:     <servlet-name>XMLServlet</servlet-name>  23:     <url-pattern>/RPC2/*</url-pattern>  24:   </servlet-mapping>  25:       26: </web-app>

Using SSL

XML-RPC is wonderful because it lets you invoke functionality over the Internet. This is also potentially a problem from a security point of view. Fortunately, many of the same techniques that apply to secure Web applications also apply to XML-RPC applications. You’ve already seen that the Apache XML-RPC libraries provide support for HTTP BASIC authentication. Unfortunately, BASIC authentication is weak because it encrypts the username and password pair using base64 encoding. If you combine BASIC authentication with Secure Sockets Layer (SSL) encryption, you get something that’s a little more workable. You also need SSL because the XML payload of XML-RPC is much more approachable by human beings, which increases the need to protect the data via encryption. Binary RPC protocols make a little work necessary to dig out the contents of an RPC payload; doing RPC with XML makes doing so downright easy.

The developers of the Apache XML-RPC libraries have built classes to make it easier to implement an SSL-based XML-RPC solution. By creating secure versions of the WebServer and XmlRpcClient classes, they’ve taken some of the pain out of dealing with SSL—at least within the Java code for your application.

We won’t give a tutorial on SSL here, so we assume you already know what SSL is for and basically how it works. We’ll cover enough of the setup that you can use SSL with your XML-RPC applications. The first thing you need in order to use SSL is an SSL certificate for the server that’s providing XML-RPC procedures. Throughout this example, we’ll assume that you’re using Java 1.4.x (we’re using JDK 1.4.2) SSL implementation and tools. This is the easiest way to demonstrate SSL capability because the Java Secure Sockets Extension (JSSE) is built into JDK 1.4 (it’s a separate download and jar for earlier versions). You use the JDK keytool program to generate a private key and self-signed certificate (signed public key) for your XML-RPC server:

keytool -genkey -dname "cn=localhost, ou=Book, o=Sauria, c=US"    -alias server -keypass password -keystore keystore    -storepass password -validity 90

This keytool command generates a private key for the server. The key is stored in the file keystore with password password. It uses the alias server and is valid for 90 days. The arguments to the -dname flag provide the organization information needed by the certificate.

Next you use keytool to export the certificate for the key whose alias is server into server.cer:

keytool -export -alias server -keystore keystore -keypass password    -storepass password -rfc -file server.cer

You need to provide the keystore and keystore password to get access to the key you created in the previous step. You also need to export the certificate in RFC 1421 format (the -rfc flag).

The last thing that you need to do is import the certificate into a file that a client JSSE program can use as a truststore. The truststore is a list of certificates that the application should trust. Once again, keytool does the job. You import the certificate from the server.cer file you created earlier into a keystore file called truststore. As usual, you supply the necessary password:

keytool -import -alias server -file server.cer -keystore truststore    -storepass password 

When keytool asks you

Trust this certificate? [no]:

you answer yes. Now a client can use this truststore and know that the certificate you generated is trustworthy.

Now let’s look at an XML-RPC server that uses SSL. This server is a modification of the earlier BasicServer example. The createBook procedure is the same as in BasicServer:

  1: /*   2:  *    3:  * BasicSecureServer.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.FileWriter;  11: import java.io.IOException;  12: import java.io.PrintWriter;  13:   14: import org.apache.xmlrpc.secure.SecureWebServer;  15: import org.apache.xmlrpc.secure.SecurityTool;  16:   17: public class BasicSecureServer {  18:   19:     public Boolean createBook(String author, String title,   20:                               String isbn, String month,   21:                               int year, String publisher,   22:                               String address) {  23:         try {  24:             PrintWriter w =   25:                 new PrintWriter(new FileWriter(isbn+".txt"));  26:             w.println(author);  27:             w.println(title);  28:             w.println(isbn);  29:             w.println(month);  30:             w.println(year);  31:             w.println(publisher);  32:             w.println(address);  33:             w.close();  34:         } catch (IOException e) {  35:             e.printStackTrace();  36:             return Boolean.FALSE;  37:         }  38:         return Boolean.TRUE;  39:     }

Here you use the new server class as the handler:

 40:   41:     public static void main(String[] args) {  42:         BasicSecureServer handler = new BasicSecureServer();

The big task is using the org.xml.apache.xmlrpc.secure.SecurityTool class to set up the parameters for using SSL. The server needs to be told which security protocol it’s using, where to find the server keystore, and what the password for that keystore is. This information is used to set up SSL for the server’s connection:

 43:   44:         SecurityTool.setSecurityProtocol("SSL");  45:         SecurityTool.setKeyStore("./keystore");  46:         SecurityTool.setKeyStorePassword("password");

You replace the use of the org.apache.xmlrpc.WebServer class with org.apache.xmlrpc.SecureWebServer, and everything looks as it did before:

 47:          48:         SecureWebServer s = null;  49:           50:         try {  51:             s = new SecureWebServer(8080);  52:         } catch (IOException ioe) {  53:             ioe.printStackTrace();  54:         }  55:   56:         s.addHandler("books", handler);  57:     }  58: }

To use SSL, you use the org.apache.xmlrpc.secure.SecureXmlRpcClient:

  1: /*   2:  *    3:  * BasicSecureClient.java   4:  *    5:  * Example from "Professional XML Development with Apache Tools"   6:  *   7:  */   8: package com.sauria.apachexml.ch8;   9:   10: import java.io.IOException;  11: import java.net.MalformedURLException;  12: import java.util.Vector;  13:   14: import org.apache.xmlrpc.XmlRpcException;  15: import org.apache.xmlrpc.secure.SecureXmlRpcClient;  16: import org.apache.xmlrpc.secure.SecurityTool;  17:   18: public class BasicSecureClient {  19:   20:     public static void main(String[] args) {  21:         SecureXmlRpcClient s = null;

Before you create the SecureXmlRpcClient instance, you use SecurityTool to tell the client to use SSL, as well as the location and password for the keystore and truststore. The truststore is the important piece here, because it determines whether the client decides to trust the certificate presented by the server. The SecurityTool setup method wants values for the keystore as well, so you supply the empty string to keep SecurityTool happy:

 22:           23:         try {  24:             SecurityTool.setSecurityProtocol("SSL");  25:             SecurityTool.setKeyStore("");  26:             SecurityTool.setKeyStorePassword("");  27:             SecurityTool.setTrustStore("./truststore");  28:             SecurityTool.setTrustStorePassword("password");

After you instantiate the SecureXmlRpcClient, you need to call its setup method to set everything up for using SSL. After that, the rest of the code is identical to what you saw in BasicClient:

 29:             s = new SecureXmlRpcClient("https://localhost:8080");  30:             try {  31:                 s.setup();  32:             } catch (Exception e) {  33:                 e.printStackTrace();  34:             }  35:         } catch (MalformedURLException mue) {  36:             mue.printStackTrace();  37:         }   38:           39:         Vector params = new Vector();  40:         params.addElement("Theodore W. Leung");  41:         params.addElement(  42:             "Professional XML Development with Apache Tools");  43:         params.addElement("0-7645-4355-5");  44:         params.addElement("December");  45:         params.addElement(new Integer(2003));  46:         params.addElement("Wrox");  47:         params.addElement("Indianapolis, Indiana");  48:           49:         try {  50:             Boolean result = (Boolean)  51:                 s.execute("books.createBook", params);  52:             System.out.println(result);  53:         } catch (XmlRpcException xre) {  54:             xre.printStackTrace();  55:         } catch (IOException ioe) {  56:             ioe.printStackTrace();  57:         }  58:     }  59: }

Using the JSSE isn’t the only option you have on the server side. If you’re running XML-RPC services via a servlet inside a J2EE Web container, you may be able to benefit from the container’s handling of SSL. If you’re using something like Tomcat, Jetty, or Resin, this probably won’t help much, because more likely than not they’re using JSSE to do their SSL processing—although we’ve seen Tomcat installations that sat behind hardware SSL accelerators. If you’re using Tomcat with an Apache Web connector, WebSphere, or WebLogic, then you may benefit from a C implementation of SSL. In this case, the SSL-encrypted content will already be decrypted by the time it reaches your XML-RPC servlet, and you won’t have to worry about dealing with SSL.




Professional XML Development with Apache Tools. Xerces, Xalan, FOP, Cocoon, Axis, Xindice
Professional XML Development with Apache Tools: Xerces, Xalan, FOP, Cocoon, Axis, Xindice (Wrox Professional Guides)
ISBN: 0764543555
EAN: 2147483647
Year: 2003
Pages: 95

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net