ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Hangin with the JAX Pack, Part 4: JAX-RPC
Pages: 1, 2

Working with Clients

Let's look at a concrete example of how we might go about coding a JAX-RPC client. There are three steps in creating a JAX-RPC client (assuming we already have the client jar containing the stubs):

  1. Obtain an instance of the interface stub.
  2. Set the endpoint property of the stub to point to the service endpoint of the Web service.
  3. Call the method.

Let's look at an actual example, modified from the Web services tutorial provided by Sun.

Listing 1: HelloClient.java

00 public class HelloClient {
01    public static void main(String[] args) {
02        try {
03            HelloIF_stub stub =
04                (HelloIF_stub)(new HelloWorld_Impl().getHelloIF() );
05            stub._setProperty( javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,args[0] );
06            System.out.println(stub.sayHello("Duke!"));
07        } catch (Exception ex) {
08            ex.printStackTrace();
09        }
10    }    
11 }

The structure is actually quite simple, but bears some explanation. Every Web service exposed for us with JAX-RPC contains both an interface definition and an implementation. Lines 3 and 4 represent obtaining an instance of a stub and casting that stub to the correct format. Since the implementation of the service might contain many different interfaces, we need to specify which interface to use (HelloIF_stub, in this case).

Breaking down lines 3 and 4, we see that first we obtain a local instance of the HelloWorld_Impl class, which has, in addition to its inherited methods, a method for returning the stub class we require. Implementation classes simply extend the javax.xml.rpc.Service and behave in a fashion similar to home interfaces in EJB. We then cast the class to the appropriate interface it represents.

We now have a stub, but it's not linked to the provider service. Line 5 inserts a property that represents the service endpoint that the stub should use to perform the remote call. An example of a service endpoint might be http://somehost.somewhere.com:80/web-service-family/specific-service. Line 6 then shows how we might call the method defined on the interface represented by the stub.

Listing 1 unfortunately generates more questions then it answers. Where did HelloIF_stub come from? What about the implementation? Where did the service endpoint information come from? Examining the anatomy of a JAX-RPC service should clear up many of these questions.

Anatomy of a JAX-RPC Service

In order to answer some of the questions raised by the client code above, we need to understand a little bit more about how a JAX-RPC service is created. A number of files come into play that define, implement, and control the creation of a JAX-RPC-based Web service.

Listing 2 shows an example of the interface that describes the methods that can be called on the Hello class. The interface is relatively straightforward and follows traditional RMI rules, extending java.rmi.Remote, with all methods throwing java.rmi.RemoteException. The interface, however, becomes very interesting when we use it with the XML RPC compiler xrpcc. The XML RPC compiler takes an interface and then can generate the client stubs, the server-side skeletons, or both. Additionally, xrpcc can generate a set of WSDL for the provided interface. Before we move on, let's remember the RMI coding rules.

Specifically, the interface definition must follow RMI rules:

  1. The interface must extend java.rmi.Remote.
  2. All methods must throw java.rmi.RemoteException but can throw other business exceptions as well.
  3. No method can be declared static or private.
  4. Method parameters must be in the defined supported set, shown in Table 1 below.

Table 1: Supported JAX-RPC types

Primitive Types boolean, byte, double, float, int, and long

Arrays of supported types are allowed, as well as Java beans composed of supported types, and arrays of supported types. Custom types beyond those listed here can also be supported via custom marshal and unmarshal code. Custom-marshalling code is beyond the scope of this article. Developers interested in custom marshalling are referred to the JAX-RPC specification.

Examining Listing 2 against the rules above shows that it is a value RMI interface definition.

Listing 2: HelloIF.java

import java.rmi.Remote; 
import java.rmi.RemoteException; 
public interface HelloIF extends Remote { 
    public String sayHello(String s) throws RemoteException;    

Listing 3 shows much of the implementation of the interface shown in Listing 2. Details of how the actual methods are implemented aren't important to this discussion; however, one important point to notice is that the HelloImpl class must implement the HelloIF interface.

Listing 3: HelloImpl.java

package hello;
public class HelloImpl implements HelloIF {
    public String sayHello(String s) {
        // whatever is appropriate

The syntax of the xrpcc is:

xrpcc[.bat | .sh] configuration_options 


  • configuration_options are from Table 2.
  • configurationfile.xml is any configuration file as described below.

Table 2: xrpcc Options

Option Description
-client Generate client artifacts (stubs, etc.)
-server Generate server artifacts (ties, etc.)
-both Generate both client and server artifacts
-d [clientdir] Specify where to place generated client output files.
-server Generate server artifacts (ties, WSDL, etc.)
-s [serverdir] Specify where to place generated server files.
-keepgenerated Retain the generated files.

When using xrpcc, you must specificy -client, -server, or -both. Also note that there are a number of other options; enter the xrpcc command without any parameters for a complete list.

Note that, as of this writing, the configuration of the various early-access software editions for the JAX Pack has changed several times. The download of JAX-RPC Early Access version 2 contains a complete description of how to install and configure xrpcc. See the Early Access documentation, packaged with the download, for installation and configuration information.

xrpcc works by reading a configuration file and then generating the service specified by the configuration. Of course, configurations are defined in XML. Listing 4 shows a sample config.xml file, which defines a service that builds off of an RMI interface and the provided implementation.

Listing 4: config.xml

00 <?xml version="1.0" encoding="UTF-8"?>
01 <configuration
02    xmlns="http://java.sun.com/jax-rpc-ri/xrpcc-config">
03   <rmi name="HelloWorldService"
04      targetNamespace="http://hello.org/wsdl"
05      typeNamespace="http://hello.org/types">
06      <service name="HelloWorld" packageName="hello">
07      <interface name="hello.HelloIF"
08         servantName="hello.HelloImpl"/>
09      </service>
10   </rmi>
11 </configuration>

The configuration file is supplied to xrpcc at compile time and then used to build the stubs and skeletons (called ties in JAX-RPC) based on the name of the service, as well as various interface and implementation stanzas. Line 3 shows the model name and is arbitrary; line 6 defines the service name and its associated package. For an unknown reason, you must place your class files in a package. Line 7 shows the fully qualified path to the implementation of the interface. Likewise, line 8 defines the name of the class that implements the interface.

Generating Clients From Existing Web Services

Up to now, xrpcc has been fairly generic and straightforward. We've been able to develop our own Web services and the call them via JAX-RPC. However, suppose you would rather access a Web service developed by someone else, one where you have access to the WSDL and the service at run time?

xrpcc allows you to do something very useful: develop the client-side stubs, etc., from the WSDL. For example, let's assume that you know a Web service exists and that its WSDL is available from http://localhost:7001/webservices/statelessservices/instantgratification.wsdl.

We could create a configuration file for xrpcc that looks like Listing 5 and use it to generate the actual client stubs required to access the Web service, regardless of how the Web service was implemented.

Listing 5: wsdltoclient.xml

00 <?xml version="1.0" encoding="UTF-8"?>
01 <configuration 
02    xmlns="http://java.sun.com/jax-rpc-ri/xrpcc-config">   
03    <wsdl name="WebServices"     
04          location="<http://localhost:7001/webservices/statelessservices/instantgratification.wsdl"
05          packageName="PackageForGeneratedClasses">                    
06    </wsdl>      
07 </configuration>

Assuming that the actual WSDL described on line 4 existed, you might enter a command such as:

xrpcc -keepgenerated -client   -d=clientclasses wsdltoclient.xm

which would generate the client code for the actual Web service in a package based on the package listed in line 5. You could have done the same thing using -server and generated skeleton classes that could be implemented to provide the service, as well. Note that I showed the use of the -keepgenerated option because I'm curious about what code will actually be produced. A very powerful tool!

A note to the wise: I tried generating code from a number of WSDL samples I had available. Some worked and some resulted in very cryptic error messages, or none at all. Given that it's an early access release, xrpcc works very well; but it still has some ways to go.


In this article, we saw the JAX-RPC specification from the perspective of a client. We discussed the architecture of Remote Procedure Calls and the tools JAX-RPC and the Early Access implementation provide. We looked at a variety of issues and saw the ease with which we could develop JAX-RPC client. It should be noted that I've specifically avoided discussion of the server side of JAX-RPC. This isn't an accident, by any means -- so many different mechanisms exist for developing Web services, of which JAX-RPC is only one, that JAX-RPC by itself pales somewhat when viewed as a way to develop the implementation of a service. JAX-RPC shines, not because it allows us to generate server-side skeletons, but because it allows us to develop client-side code quickly, easily, and with a minumum of fuss and bother.

Al Saganich is BEA Systems' senior developer and engineer for enterprise Java technologies, focused on Java integration and application with XML and Web services.

Previously in this series:

Hangin' with the JAX Pack, Part 3: Registries -- In Part 3 of our JAX Pack series, Al Saganich looks at JAXR, the Java API for XML Registries.

Hangin' with the JAX Pack, Part 1 -- In this three-part series, BEA Systems' Al Saginach takes a look at the JAX Pack, JAVA APIs for providing XML-based Web services handling XML. This week Al looks at JAXP (for XML processing) and JAXB (for XML binding). Next week: XML messaging with JAXM.

Hangin' with the JAX Pack, Part 2: JAXM -- Al Saganich examines JAXM, the Java API for XML Messaging, and shows how it provides support for accessing various messaging formats.

Return to ONJava.com.