Build an RPC service and client using JAX-RPC Using the Java for building RPC-based Web services

Skill Level: Introductory

Brett McLaughlin ([email protected]) Author/editor O'Reilly Media

15 Jul 2008

Remote procedure calls (RPCs) are the precursors to modern Web services that are based on the Simple Object Access Protocol (SOAP) or Representational State Transfer (REST). Because all of the Java™ platform's Web service APIs are built on the concepts introduced in RPC, understanding the Java APIs for XML-Based RPC (JAX-RPC) is an almost mandatory step for writing efficient and effective Web services in the Java language. This tutorial takes you through getting and installing JAX-RPC, configuring it, and building a server-side RPC receiver and a simple client-side application.

Section 1. Before you start

About this tutorial

This tutorial is a complete guide to installing, configuring, building, and exercising (running) Web services that are based on remote procedure calls (RPCs). You'll download and install an implementation of the Java APIs for XML-Based RPC (JAX-RPC), learn how JAX-RPC is represented in Java classes and packages, and build both a client and server to allow for RPC-based interactions. Configuration options are covered, and you'll become comfortable deploying your own RPC-based applications.

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 1 of 47 developerWorks® ibm.com/developerWorks

Objectives

This tutorial walks you through the construction of JAX-RPC Web services, from start to finish. More important, you'll see how all Web services are constructed. This tutorial covers the basics of client-server interactions in a service-based architecture and explores RPC simply as one implementation of those principles.

You'll also gain a thorough understanding of the JAX-RPC APIs, all in the context of practical use. Although you won't use every method of every class, you'll know which classes and methods are essential in a real-world context, and why some methods are not useful. All of these concepts are presented in the context of building one working RPC-based client and server.

Because service-based architectures are less direct — and somewhat harder to manage — than a typical client-server Web interaction (such as an HTML front-end making POST requests to a Java servlet), they're harder to implement well. This tutorial explores some of the best practices for building Web services, as well as common mistakes.

You'll also:

• Understand the basics of JAX-RPC as they relate to the wider scope of Web services • See how RPC-based services are different from SOAP- and REST-based services • Understand when RPC services are still a good choice, despite some of the more "modern" approaches to Web services

Prerequisites

This tutorial is written for Java programmers. You should be comfortable coding Java applications and working with standard and third-party Java APIs and toolkits.

You'll also need a Web server that's capable of hosting server-side Java applications (servlets). You can use any Java-capable Web servlet container, application server, or hosting provider. One of the most popular solutions is , which is both free and well-documented. It's also up to you whether you test out your programs on a remote server (at your company or an ISP), or on your local machine. You just need to have the server installed and running on an accessible machine. Details about how to configure JAX-RPC on those servers are included in the tutorial, so you don't need to understand the relationship between JAX-RPC's servlets and your Web server yet.

Build an RPC service and client using JAX-RPC Page 2 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Knowledge of Java servlets and Apache Tomcat (particularly the servlet-hosting facilities and the web. deployment descriptor file) is helpful, although not strictly required.

See Resources for pointers to additional information on these topics.

This tutorial focuses on JAX-RPC and the open source implementation of JAX-RPC, but no previous knowledge of RPC, JAX-RPC, or Apache Axis is required. Details regarding their download, installation, and configuration are covered in the tutorial.

Section 2. Download and install Apache Axis

Because JAX-RPC isn't part of a standard Java distribution, you'll need to do a little work to get it installed and configured. (As I'll explain in a moment, you won't actually install JAX-RPC itself; rather, you'll install a particular JAX-RPC implementation.) Don't worry now about what RPCs are; you'll know a lot more than just the basics of RPC before you get much further. For now, just follow these instructions to make JAX-RPC usable, so you can learn as you experiment with both the API and programs that use the API.

Check your servlet engine

Confirm that you've got a servlet engine running and accessible, and that you know both the hostname and port for accessing that server via a Web browser. If you've installed Apache Tomcat on your local machine, you can access the server's Web page at http://localhost:8080, and you should see something like Figure 1:

Figure 1. Confirming a working Tomcat installation

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 3 of 47 developerWorks® ibm.com/developerWorks

Obviously, you'll see something different if you've installed a different servlet engine or if you've got content set up in Tomcat already. Still, as long as you have a servlet engine that you can get to, you're ready to proceed.

You don't need to install JAX-RPC

Like the Java API for XML Binding (JAXB) or the Java API for XML Processing (JAXP), and even standard APIs like JDBC, JAX-RPC is really an API specification.

Build an RPC service and client using JAX-RPC Page 4 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

In other words, it is as much a document as it is a set of Java classes and interfaces. That document describes how JAX-RPC classes and interfaces behave; it doesn't describe how to build a JAX-RPC application, but it does detail the components involved and how they're represented by Java constructs.

The API also includes a set of classes and interfaces, also referred to as JAX-RPC. (It's a little confusing that several things are referred to colloquially as "JAX-RPC.") These classes and interfaces are sometimes called language bindings (especially when XML specifications are involved), but in short, they're just the constructs defined by the specification. There's no sample class, no example code, no dummy services to test things out.

The classes and interfaces included with JAX-RPC are all in the javax.xml.rpc package and several subpackages:

• javax.xml.rpc.encoding • javax.xml.rpc.handler • javax.xml.rpc.handler.soap • javax.xml.rpc.holders • javax.xml.rpc.server • javax.xml.rpc.soap Three interfaces in the base javax.xml.rpc package are its core components:

• javax.xml.rpc.Call • javax.xml.rpc.Service • javax.xml.rpc.Stub You'll learn more about each of these interfaces and the other JAX-RPC packages throughout this tutorial. For now, notice that the three core components are interfaces, and not classes. In fact, the core JAX-RPC package includes only a few concrete classes, and two of them — NamespaceConstants and ParameterMode — are really utility classes. So where are the classes, the code to instantiate with new?

JAX-RPC separates API from implementation

The designers of JAX-RPC defined a specification and then wrote lots of interfaces. These interfaces define class names and behavior, but they don't implement that behavior. Instead, vendors can write their own APIs that implement JAX-RPC's standardized interfaces.

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 5 of 47 developerWorks® ibm.com/developerWorks

For you, this boils down to one simple fact: JAX-RPC, on its own, isn't very useful. It's lots of methods and interfaces, without anything to support and implement them. As a result, there's really no such thing as "installing JAX-RPC." What you want, instead, is an implementation of JAX-RPC. Conveniently, all the available implementations come with the JAX-RPC interfaces, packaged nicely. So although you might choose to download the JAX-RPC specification document (see Resources), you don't need to do anything to install JAX-RPC other than install a particular implementation of the API.

Install Apache Axis

The implementation of JAX-RPC used in this tutorial is Apache Axis. Axis is free, open source, well-known, and well-supported. The tutorial uses Apache Axis 1.4 rather than the somewhat bleeding-edge Axis 2.0, a retooling of the API that is not as useful for RPC applications. Axis 1.4 is still current and supported.

Download Apache Axis 1.x

First, go to the Apache Axis 1.x Web site's Releases page. You'll see a long list of releases you can download, organized by version number (see Figure 2):

Figure 2. Choose the latest version of Apache Axis that starts with a "1"

Build an RPC service and client using JAX-RPC Page 6 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Select the latest version; I'm using version 1.4 in this tutorial. Once you've selected a version, you can choose a mirror. Finally, select the binary download for your platform. Windows® users should select the file ending in .zip. Mac OS X or Linux® users should choose the .tar.gz version. So for a Mac OS X platform, you would select axis-bi-1_4.tar.gz; a Windows user would choose axis-bin-1_4.zip.

Expand and locate Apache Axis

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 7 of 47 developerWorks® ibm.com/developerWorks

Expand the package you've downloaded. You'll get a directory named something like axis-1_4. Move this directory and all of its contents to a long-term location, preferably where you keep all your other Java programs. On my system, for example, I moved the Axis directory to /usr/local/java, listed here:

[bdm0509:/usr/local/java] ls apache-tomcat-6.0.16 axis-1_4 xalan-j_2_7_1

You can select any location you like; C:/Java or a subdirectory of your home directory are just as useful. Just make sure the files are somewhere you can easily access them and where they won't be deleted.

Now you need to create a Web application, do some basic configuration, and start up your first Axis service. That's the next step in this tutorial; first, though, some basic concerns about JAX-RPC need to be addressed.

Is JAX-RPC (and this tutorial) outdated?

As you're installing Axis 1.x and working through this tutorial, you'll see several references to JAX-WS and repeated indications that JAX-WS is replacing JAX-RPC. It's true that a movement is underway to replace JAX-RPC with JAX-WS; however, that should not lead you to think that JAX-RPC is useless or even outdated. RPCs have been around for a long time and are one of the clearest examples of a Web service: a long-running server-side program provides a service, as needed and when needed, to a client. The service provides some sort of description of itself, including the parameters that it expects and accepts, and the data it returns.

Although JAX-WS is the future of Java-based Web services, it uses the same concepts as JAX-RPC. So although the syntax will change, the principles you pick up in this tutorial will be immensely helpful when you move to JAX-WS. Even better, Axis 2.x has JAX-WS support; so as you move to JAX-WS, even the Axis framework detailed in this article will still be useful.

Section 3. Validate your Axis installation

Before you build your own RPC-based application, you'll deploy the sample service that Axis ships with. This provides a fairly simple way to test your Axis and JAX-RPC installation without worrying about your own custom programming being the cause of any problems that develop. As a side effect of this testing, you'll get a first look at how RPC works, how services are run, and how clients access those services.

Build an RPC service and client using JAX-RPC Page 8 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Install the Apache Axis Web application

Apache Axis comes with a sample Web application that can be deployed on any servlet container. You simply need to copy the Axis Web application into the location in your servlet container where Web applications reside, and test out Axis.

Copy the Axis Web application

Locate the directory in your servlet engine where Web applications are deployed. This is typically a folder or directory called webapps/. It's often nested directly underneath your servlet engine's root folder. If you're using Tomcat, this directory is directly underneath the root Tomcat folder; for example, in my installation, I have an apache-tomcat-6.0.16/webapps/ folder.

Now copy the Axis directory in your Axis installation's webapps/ directory right into your servlet engine's webapps/ directory. Be sure to copy the directory, rather than move it. This ensures you have the original Web application in your Axis installation, in case you change things in your servlet engine's version. The original becomes a backup that you can easily revert to. So you might issue a command like that shown in Listing 1:

Listing 1. Copy the Axis Web application into your servlet engine's webapps/ directory

[bdm0509:/usr/local/java/apache-tomcat-6.0.16/webapps] cp -rp /usr/local/java/axis-1_4/webapps/axis . [bdm0509:/usr/local/java/apache-tomcat-6.0.16/webapps] ls ROOT docs host-manager axis examples manager

Start your servlet engine

Now start (or restart) your servlet engine. You can use a command-line or Web interface. For Tomcat, you'd just issue the commands to shut down the engine, and then start it up again:

[bdm0509:/usr/local/java/apache-tomcat-6.0.16/bin] sh shutdown.sh Using CATALINA_BASE: /usr/local/java/apache-tomcat-6.0.16 Using CATALINA_HOME: /usr/local/java/apache-tomcat-6.0.16 Using CATALINA_TMPDIR: /usr/local/java/apache-tomcat-6.0.16/temp Using JRE_HOME: /Library/Java/Home [bdm0509:/usr/local/java/apache-tomcat-6.0.16/bin] sh startup.sh Using CATALINA_BASE: /usr/local/java/apache-tomcat-6.0.16 Using CATALINA_HOME: /usr/local/java/apache-tomcat-6.0.16 Using CATALINA_TMPDIR: /usr/local/java/apache-tomcat-6.0.16/temp Using JRE_HOME: /Library/Java/Home

As long as you don't see any errors reported, the Axis Web application should be

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 9 of 47 developerWorks® ibm.com/developerWorks

installed and ready to go.

Test and validate your installation

Some servlet engines hot-deploy Web applications You may not need to restart your servlet engine. Many servlet engines are configured to deploy automatically any WAR (Web archive) files or applications that are dropped into the engine's webapps/ directory. It's still a good idea to stop and start your engine, though, just to be sure this feature isn't required for you to get things working. It also allows your servlet engine to report any errors or warnings when starting up with Axis installed, another precautionary step that can help you spot potential problems.

Navigate to the newly installed Axis Web application. Usually, you'll just enter the URL of your servlet engine, a forward slash (/), and then the name of the Web app: in this case, axis. So if your servlet engine is hosted at http://localhost:8080, the complete URL to the Axis installation is http://localhost:8080/axis/. You should see a screen similar to Figure 3:

Figure 3. Default Web page for an Axis 1.x installation

Build an RPC service and client using JAX-RPC Page 10 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

This lets you know that the Web application is running but doesn't confirm that everything Axis needs to work is installed. That's part of validation. To validate your Axis installation, click the first link on the home page, labeled "Validation." You'll get a screen something like Figure 4:

Figure 4. Validation page for Apache Axis (with several errors)

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 11 of 47 developerWorks® ibm.com/developerWorks

Build an RPC service and client using JAX-RPC Page 12 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

This page is a JavaServer Page (JSP) that validates your installation and reports on any missing components. The sample shown in Figure 4 has three problems:

• The required javax.activation.DataHandler class is missing. • The javax.mail.internet.MimeMessage helper class is missing. • The org.apache.xml.security.Init helper class is missing. The great thing about this page, though, is that you don't need a tutorial to figure out what to do. Each error reports a missing class and the Java Archive (JAR) or library that class is packaged with, and it even gives you a handy link to download the missing components from.

Download any missing components

Use the Axis links to each library This tutorial's Resources includes no links to the libraries that Axis requires. Axis is constantly changing (even in its 1.x form), so the validation application is a better source for the current libraries and links to get Axis working. Use that page as your online resources page, and you'll get Axis working quickly and cleanly.

Now that you've got a comprehensive list of missing components, you should download each of them. Begin by following the links to all the missing required components. Download each referenced library, expand the library as needed, and locate the specific JAR file listed on the Axis validation page.

For instance, for the Java Activation Framework, follow the link on the Axis page and click the download links on java.sun.com. You'll eventually download a ZIP file that you can expand into a directory: jaf-1.0.2. Within this directory is the JAR file you need, called activation.jar. Copy this file into your servlet engine's lib/ directory, as shown here:

[bdm0509:/usr/local/java/apache-tomcat-6.0.16/lib] cp ~/Downloads/jaf-1.0.2/activation.jar .

Repeat this process for any other missing libraries. You may need to search each referenced page to find the right download link, but in each case, the download you want is just a click or two (and often a software license agreement) away.

Once you've got all the libraries downloaded, restart your servlet engine. Servlet engines cannot dynamically load libraries, so a restart is required. Then, navigate back to the Axis home page, click the Validation link, and see if you've taken care of any problems.

Getting (or ignoring) XML Security

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 13 of 47 developerWorks® ibm.com/developerWorks

One optional component of Axis that turns out to be quite a hassle to deal with is XML Security (listed under Optional Components in Figure 4). XML Security actually requires a third-party library of its own, and when you download XML Security, you will not get this library in your download. Worse, though, simply downloading the file manually doesn't solve the problem. Essentially, you'll need to build XML Security from source, which involves getting Ant, JUnit, and several other third-party tools set up and running. More to the point, you'll do a lot of work not related to RCP to get a library that you'll probably not often use.

If you're an experienced developer, feel free to stop at this point and spend some time downloading the XML Security source code. Read the INSTALL file included with XML Security, download all the third-party libraries, and build JAR files from source. Then you can copy those JARs into your Tomcat or servlet engine installation.

If you're not a Java guru, or just want to get on with using JAX-RPC and Axis, it's okay to skip this step. You'll get a result on your validation page similar to Figure 5:

Figure 5. The Axis validation page without XML Security

Build an RPC service and client using JAX-RPC Page 14 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

XML Security isn't required for this tutorial, so consider your Axis installation "complete" if you're getting a result that looks like Figure 5.

Test a simple Java Web service

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 15 of 47 developerWorks® ibm.com/developerWorks

Before building your own Web service, there's one more confirmation step you should take. So far, you've validated your installation but not tested an actual Web service call. Revisit the Axis home page (shown back in Figure 3), and click the link labeled "Call." This runs a Web service and ensures that the client- and server-side components are all working properly. You should see a result that looks like Figure 6:

Figure 6. Axis comes with a sample Java Web service

This doesn't look like much. That's because the browser (Safari, in the case of Figure 6), in an attempt to "help," tries to render the output from this call into something more browser-friendly. You can click View > Source to see the raw output. (Depending on the browser you use, you may not need this step.) Listing 2 shows the source, which is XML:

Listing 2. The sample Web service returns an XML-formatted version of the request headers

user-agent:Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_2; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18 referer:http://localhost:8080/axis/ accept:text/xml,application/xml, application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,

Build an RPC service and client using JAX-RPC Page 16 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

*/*;q=0.5 accept-language:en-us accept-encoding:gzip, deflate cookie:JSESSIONID= 42A37ED6763ECC773D5FEB70484D57B1 connection:keep-alive host:localhost:8080

These headers are still a bit of a mess. (There's a lot of SOAP-specific XML, and Listing 2 is actually formatted a bit for readability, believe it or not). But the point here is to get a response that's XML and not an error. If you got something like Listing 2, then you're ready to continue. You've got a working Axis installation, and simple Java Web service calls are working.

Section 4. Build a program to publish as a service

One of the best features of JAX-RPC — and any other good Web service framework — is that you don't need to write the programs you'll publish as a Web service with RPC or Web services in mind. Most Web services don't start as Web services at all; instead, they begin their life as normal programs containing methods that are called and that return values. If that sounds a bit boring, you've understood the crux of Web services: they're just programs available through a Web medium, rather than through a virtual machine.

So before you have to worry about the RPC semantics, or what Web Services Description Language (WSDL) is, you just need a class you want to make available to Web clients.

Build your Java class

Suppose you want a simple book-search tool. The program stores a library of books related to cognitive science, learning theory, and user interface design. But because these are esoteric books, often with titles that say nothing about the books' contents, a requirement for your program is that it search through the library based on a supplied keyword and return books related to the keyword. For example, a search for the keyword presentation might return Presentation Zen by Garr Reynolds and The Back of the Napkin by Dan Roam. The first title is a natural fit, but your program is smart enough to find the second book, which ostensibly a normal search might not find.

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 17 of 47 developerWorks® ibm.com/developerWorks

For now, don't worry about Web services or JAX-RPC. We just need a search program, and we'll dummy up the inventory to get on to the interesting Web service bits more quickly.

Define your class and method calls

Start with a simple class skeleton, defining the methods you want to provide to the program's users. Listing 3 shows a Java class that takes in a search term and returns a list of titles:

Listing 3. Skeleton of a complete program for returning book titles

package dw.ibm; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class BookSearcher { private Map books; public BookSearcher() { books = new HashMap(); } public void setBooks(Map books) { this.books = books; } public void addBook(String title, List keywords) { books.put(title, keywords); } public List getKeywords(String title) { return (List)books.get(title); } public void addKeyword(String title, String keyword) { List keywords = (List)books.get(title); if (keywords != null) { keywords.add(keyword); // No need to manually "re-put" the list } else { keywords = new LinkedList(); keywords.add(keyword); books.put(title, keywords); } } public List search(String keyword) { List results = new LinkedList(); // logic to be implemented return results; } }

This is pretty simple. Each book is stored as an entry in a map. The key to the map is the book title, which makes retrieving the keywords for a title trivial. And each

Build an RPC service and client using JAX-RPC Page 18 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

book has an associated list of keywords. It's not indicated in Listing 3, but those keywords will just be string values such as "presentation" or "cognitive science" or "marketing."

The program has methods for:

• Adding a book via a title and list of keywords • Adding a keyword for a given book • Getting the keywords for a book These methods have both utility (are useful for an administrator) and functionality (are useful for someone using the program to get information about books). The program also has a search method, which is the key functionality: given a keyword, all the matching book titles are returned. All that's left is to implement the search logic and load some books for demonstration value.

Where are the parameterized lists and generic types?

Type in or download (see Download) the code in Listing 3 and compile it. If you're still on Java 1.4, this code will work as is. If you compile it on Java 5 or later, you'll get several warnings because the Lists are unchecked and untyped. It's easy enough to add the types, and it's worth doing. In particular, the list of keywords would benefit from being typed: you can make the program's use safer by ensuring that only string keywords are added to the lists. That said, the program is still pretty unambiguous and easy to understand, which is the important consideration here.

Write the search functionality

Searching for titles via keyword is just a matter of looping over the map of books and checking each book's list for the desired keyword. Again, there's no Web service magic here; it's just basic programming logic. Listing 4 shows the completed search() method for BookSearcher:

Listing 4. Completed search() method for finding books by keyword

public List search(String keyword) { List results = new LinkedList(); for (Iterator i = books.keySet().iterator(); i.hasNext(); ) { String title = (String)i.next(); List keywords = (List)books.get(title); if (keywords.contains(keyword)) { results.add(title); } } return results; }

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 19 of 47 developerWorks® ibm.com/developerWorks

This method loops through all the books in inventory and pulls out the list of keywords for each. That list is checked to see if it contains an entry that matches the supplied keyword. Matching books are returned via another list.

Add some sample data

Finally, you need some sample data. Normally this data would be created, and probably stored, in a database. But for the sake of example and keeping on point with JAX-RPC, you'll simulate it with a simple addBooks() method, shown in Listing 5, that adds a bunch of books and keywords:

Listing 5. An addBooks() method to seed the book data

private void addBooks() { List keywords = new LinkedList(); keywords.add("presentation"); keywords.add("Keynote"); keywords.add("PowerPoint"); keywords.add("design"); addBook("Presentation Zen", keywords); List keywords2 = new LinkedList(); keywords2.add("presentation"); keywords2.add("user interface design"); keywords2.add("pictures"); keywords2.add("visuals"); addBook("The Back of the Napkin", keywords2); List keywords3 = new LinkedList(); keywords3.add("marketing"); keywords3.add("business"); keywords3.add("commercials"); keywords3.add("consumers"); addBook("Purple Cow", keywords3); List keywords4 = new LinkedList(); keywords4.add("marketing"); keywords4.add("business"); keywords4.add("notecards"); keywords4.add("design"); keywords4.add("visuals"); keywords4.add("pictures"); keywords4.add("humor"); addBook("Indexed", keywords4); List keywords5 = new LinkedList(); keywords5.add("marketing"); keywords5.add("business"); keywords5.add("design"); keywords5.add("emotion"); keywords5.add("functionality"); keywords5.add("consumers"); addBook("Emotional Design", keywords5); keywords.clear(); }

There's nothing remarkable here; now you just need to call the addBooks() method. Listing 6 shows a completed version of BookSearcher, in which addBooks() is called in the constructor to autopopulate some initial books and keywords:

Listing 6. Completed BookSearcher class

import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; public class BookSearcher {

Build an RPC service and client using JAX-RPC Page 20 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

private Map books; public BookSearcher() { books = new HashMap(); // for example purposes addBooks(); } public void setBooks(Map books) { this.books = books; } public void addBook(String title, List keywords) { books.put(title, keywords); } public void addKeyword(String title, String keyword) { List keywords = (List)books.get(title); if (keywords != null) { keywords.add(keyword); // No need to manually "re-put" the list } else { keywords = new LinkedList(); keywords.add(keyword); books.put(title, keywords); } } public List getKeywords(String title) { return (List)books.get(title); } public List search(String keyword) { List results = new LinkedList(); for (Iterator i = books.keySet().iterator(); i.hasNext(); ) { String title = (String)i.next(); List keywords = (List)books.get(title); if (keywords.contains(keyword)) { results.add(title); } } return results; } private void addBooks() { List keywords = new LinkedList(); keywords.add("presentation"); keywords.add("Keynote"); keywords.add("PowerPoint"); keywords.add("design"); addBook("Presentation Zen", keywords); List keywords2 = new LinkedList(); keywords2.add("presentation"); keywords2.add("user interface design"); keywords2.add("pictures"); keywords2.add("visuals"); addBook("The Back of the Napkin", keywords2); List keywords3 = new LinkedList(); keywords3.add("marketing"); keywords3.add("business"); keywords3.add("commercials"); keywords3.add("consumers"); addBook("Purple Cow", keywords3); List keywords4 = new LinkedList(); keywords4.add("marketing"); keywords4.add("business"); keywords4.add("notecards"); keywords4.add("design"); keywords4.add("visuals"); keywords4.add("pictures"); keywords4.add("humor"); addBook("Indexed", keywords4);

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 21 of 47 developerWorks® ibm.com/developerWorks

List keywords5 = new LinkedList(); keywords5.add("marketing"); keywords5.add("business"); keywords5.add("design"); keywords5.add("emotion"); keywords5.add("functionality"); keywords5.add("consumers"); addBook("Emotional Design", keywords5); keywords.clear(); } }

At this point, you've got a working program without any JAX-RPC code. That's the beauty of using an API like JAX-RPC compared to, say, writing a Java servlet or JSP. With a servlet or JSP, you write code that's server-side specific from the start (or, perhaps you write a class that your servlet then has to know the details of to pass through calls to and from). With JAX-RPC, you write a normal Java class, without server-side or Web service-specific calls, and apply the JAX-RPC later.

Test your code (before turning it into a service)

When you integrate JAX-RPC into your programs, you add a significant level of complexity: calls from a client, the JAX-RPC API itself, a servlet engine, and more. By testing your code now, before taking that step, you can ensure that your business and application logic are all functioning as they should. Then, if you have trouble later, you've isolated the problem to (in most cases) the RPC components, rather than your class's logic.

Listing 7 is a simple test case that you can run from the command line; it simply calls a few methods and prints the results so you can verify they're correct:

Listing 7. Test class for BookSearcher

import java.util.Iterator; import java.util.List; public class BookSearchTester { public static void main(String[] args) { BookSearcher searcher = new BookSearcher(); List keywords = searcher.getKeywords("Purple Cow"); System.out.println("Keywords for 'Purple Cow':"); for (Iterator i = keywords.iterator(); i.hasNext(); ) { System.out.println(" " + (String)i.next()); } List books = searcher.search("design"); System.out.println("Books that match the keyword 'design':"); for (Iterator i = books.iterator(); i.hasNext(); ) { System.out.println(" " + (String)i.next()); } } }

Compile the code in Listing 7 and then run it. You should get a result set that looks like the one shown in Listing 8:

Build an RPC service and client using JAX-RPC Page 22 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Listing 8. Testing basic functionality of the BookSearcher class

[bdm0509:~/Documents/developerworks/jax-rpc] java BookSearchTester Keywords for 'Purple Cow': marketing business commercials consumers Books that match the keyword 'design': Emotional Design Indexed

Section 5. Turn your class into an RPC service

With a working Java class (or classes), and a servlet engine with Axis set up and configured, you've got everything you need to build a consumable RPC-based service.

But what is RPC?

An RPC is simply a remote (as in from another machine) procedure (as in a method; more on this in a moment) call (as in invocation). In other words, making an RPC means to call a method on another machine somewhere. That's really as complex as it gets; you write a call, and make one or more of its methods available for programs to call, without those programs needing to be in the same virtual or even physical machine.

In the case of the BookSearcher, that means that you could put the BookSearcher class on a Web server somewhere and run a program that uses that class on your local machine. Although some RPC-specific activity must occur, especially on the client, your programs can interact just like any other two classes. You can invoke a method, send it parameters, and get back a response.

Why not remote method calls?

RPC is a technology that predates the dominance of object-oriented languages such as C# and the Java language. In fact, RPC was originally developed and used largely with C-style applications, in which functions were the primary approach for exposing behavior. When RPC-like services began to appear in Java, C++, and C# programs, it made more sense to use the term RPC — which lots of developers already understood — than to try and come up with a new term and acronym such as remote method calls, or RMC.

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 23 of 47 developerWorks® ibm.com/developerWorks

So just think of a function and method as analogous in the RPC world, and don't worry about the semantic differences between the two terms.

A server-side class is a service in RPC

Right now, you have a class (BookSearcher) that will be on the server side of your RPC setup. It's just an ordinary Java class now, but once you make certain methods available via RPC, your class is referred to as a service. It serves clients by providing them functions (methods) that can be called. The calling code is referred to as the client or caller.

The methods you make available for remote calling are considered exposed. So you'll eventually choose which methods to expose via RPC. You can expose one method, all of them, or any number in between. A client can call exposed methods, and only exposed methods. The entire process of making a class into a service, and then exposing some of that service's methods, is called publishing the service. So you expose methods of a published service.

But I only have one machine!

You can continue with this tutorial's exercise even if you don't have access to a Web server. As soon as your class is exposed as a service via Axis, you're requiring a network call to access the class. So running another class on your local machine that accesses the service is a great test case, and you're not missing any steps. The network call is routed right back to your own machine and never gets out to the Internet at large — but a network call is still being made, and that's what's important. Even if you don't have a separate machine to test on, you'll get the full benefit of this tutorial with everything running on one local machine.

That said, if you can put your service class on another machine running a servlet engine, it's nice to see RPC in a full-fledged, remote environment. You can get an idea of the time it takes to make and receive responses (which turns out to be negligible compared to the time it takes to make the network connection). You'll also get a feel for a real-world RPC environment.

Use Java Web Service (JWS) to publish your service

On the client, it takes a little work to connect to an RPC-enabled service. However, actually deploying your service is trivial. That's because each RPC package or toolkit, such as Axis, has toolkit-specific details to maintain. Rather than forcing you to learn an API on top of JAX-RPC, you can take advantage of the toolkit's tools to handle exposing a service.

Build an RPC service and client using JAX-RPC Page 24 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Copy your .java file to a .jws file

In the case of Axis, the easiest and fastest way to publish your service is to use JWS files. All you need to do is copy your Java source file (ending with .java) to a file with the same name but a .jws extension. Then, that .jws file goes into the Axis Web application, which should be in your servlet engine's webapps/axis directory. So to publish BookSearcher, you'd issue a command like the one shown in Listing 9:

Listing 9. Convert your Java class to a JWS file

[bdm0509:/usr/local/java/apache-tomcat-6.0.16] cp ~/Documents/developerworks/jax-rpc/BookSearcher.java webapps/axis/BookSearcher.jws

This looks pretty odd; it's usually a bad idea to change a file's extension and hope anything good comes of it. However, that's exactly what Axis wants. As soon as the Axis Web application "sees" a .jws file in its directory, it compiles the file into a Java Web Service and builds all the SOAP access code needed to allow a client to access the class. Axis even deploys the service right away.

Access your service with a Web browser

Start up your servlet engine if it's not already running. The Axis Web application is available at http://hostname:port/axis. If you're using a default installation of Tomcat on your local machine, this would translate to http://localhost:8080/axis. Simply append to that a forward slash, the name of your class, and the .jws extension. So to access the example service, type in the URL http://localhost:8080/axis/BookSearcher.jws. Your Web browser should report that a Web service is indeed running at that address, as shown in Figure 7:

Figure 7. Axis deploys your service and makes it Web accessible

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 25 of 47 developerWorks® ibm.com/developerWorks

You'll also see a link, labeled "Click to see the WSDL." That's a new term, but a pretty important one.

WSDL describes your service

Web Services Description Language (WSDL) is an XML vocabulary that is used to tell client code that wants to access a service about that service. WSDL describes:

• The methods available • The parameters each of those methods takes • The return values for each method In essence, a WSDL file is a specification of the ins and outs of interacting with your Web service.

Click the "Click to see the WSDL" link on the BookSearcher Web service and take a look at the WSDL for this service. If your browser tries to render the XML, you can select View > Source to see the raw WSDL without any browser-imposed formatting. The WSDL for the BookSearcher service is shown in Listing 10:

Listing 10. WSDL for BookSearcher describes its available methods

Build an RPC service and client using JAX-RPC Page 26 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

xmlns:impl="http://localhost:8080/axis/BookSearcher.jws" xmlns:intf="http://localhost:8080/axis/BookSearcher.jws" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 27 of 47 developerWorks® ibm.com/developerWorks

Build an RPC service and client using JAX-RPC Page 28 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

WSDL is pretty lengthy and detailed. But it's also the key to understanding a Web service and your code connecting to a Web service. The next section of this tutorial looks at this WSDL in detail, in preparation for writing code to search for books remotely.

Section 6. Analyze WSDL to understand a service

If you took more than a passing look at the WSDL in the preceding section, you've probably got some good ideas about exactly what the WSDL describes. But keep in mind that in many cases, you won't have the source code for a service you want to use. All you'll have is the WSDL to get by with. At those times, your understanding of

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 29 of 47 developerWorks® ibm.com/developerWorks

WSDL is critical to using an RPC service (or any other type of Web service) correctly and effectively.

WSDL is namespace-heavy

Most of the time, programmers and even document authors quickly scan through — or outright skip over — the root element declaration in a WSDL file. In WSDL, though, that declaration contains a lot of information, as shown in Listing 11:

Listing 11. Root element declaration

Each of the xmlns: attributes defines a namespace and associated prefix. So there's an Apache SOAP namespace, a SOAP encoding namespace, both a WSDL and WSDL SOAP namespace, the XML Schema namespace ... and the list goes on. The target namespace is also set, and its Uniform Resource Identifier (URI) is the JWS file representing your published service.

The good news is that although these namespaces are important to SOAP, RPC, Axis, XML parsers, and almost every other technology used in Web services, you needn't worry much about them. It's enough to know that most of the elements in the WSDL are defined by a WSDL specification and associated with the wsdl prefix, and that the XML Schema namespace (and its associated types, which will become important soon) is associated with the xsd prefix. The rest is useful, but not something you'll need to write effective Web service clients.

WSDL defines object-based types

The next key section of the WSDL is contained within the element, shown in Listing 12:

Listing 12. The element

Build an RPC service and client using JAX-RPC Page 30 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

WSDL and Web services know about some basic types, such as string and int and float, but aren't very smart about types more complex than what amount to Java primitives. However, the BookSearcher class has methods that take in or return both lists and maps. To handle these complex, object-based types, the WSDL must define them in terms of XML Schema types. This section of the document defines all of those types. For example, Listing 13 shows the definition of a map that RPC clients and services can understand:

Listing 13. Definition of a map RPC clients and services can understand

The Vector type is used to represent lists in the same fashion, providing upper and lower bounds for the lists. These are of limited use, because once you've written a few services and clients, you'll become familiar with the basic mappings between Java objects and custom WSDL types. Still, if you see a method that takes in a

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 31 of 47 developerWorks® ibm.com/developerWorks

Vector, you'll know to look for the element to find out more about that type, including any constraints it might have for the values it can contain.

Every send and return is a message

The next elements are represented by . Here's where things deviate from Java terms and focus instead on network- and SOAP-specific concepts. When you send a request to a method on a service, you're sending a message. If the method you're requesting has no parameters, your message doesn't have any data within it for the method to operate on. If the method does require parameter data, you must send that data as part of the message.

The same is true when the service returns from a method: it either contains no data from the method or one piece of data. But the key is that the send and the receive are separate messages. One is a message from a client to a service, and the other is a message from a service back to a client. The two are logically related, but they're not connected in a programming or technological sense.

So each of these messages must be declared and defined. Take the getKeywords() method of BookSearcher. It takes as a parameter a string title, and it returns a list. Each of these two messages must be represented in the WSDL:

Listing 14. Messages in WSDL

The name of each message is simply the method name, plus either Request or Response. Each has a nested element that defines a parameter name and a type (a string title for the request, and a generically named array for the response). This enables you or a code-generation tool to figure out what a request to getKeywords() looks like, as well as what to expect in return.

If no parameter is sent, or if there's no return value, then there's no child element:

Listing 15. No child element

The addKeyword() method has no return value, so it is represented by an empty

Build an RPC service and client using JAX-RPC Page 32 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

addKeywordResponse() element.

A service is represented by a port type

With the possible messages delineated, the WSDL can now describe the entire Web service, via the element, shown in Listing 16:

Listing 16. The element

Each operation maps to a method, and the various input and output messages are connected to each operation. The ordering of parameters is also supplied. These completely describe an exposed method, and when laid out like this, should make perfect sense to you.

WSDL provides some lower-level SOAP-specific information

As a programmer, you have everything you need, but some encoding and SOAP-specific details still need to be handled. These are wrapped into the element, which maps to the port type already defined. Most of is concerned with encodings and namespaces. For example, Listing 17 shows further SOAP-specific information related to how the getKeywords() method and operation is to be handled:

Listing 17. SOAP-specific information on handling getKeywords()

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 33 of 47 developerWorks® ibm.com/developerWorks

namespace="http://DefaultNamespace" use="encoded"/>

Who is the WSDL for?

WSDL serves a dual role:

• WSDL lets Web service and code-generation tools know the semantics and SOAP specifics that are required to connect to a service. • WSDL lets programmers know what methods are available and the data those methods expect and provide in return. As you'll see shortly, JAX-RPC and the Axis framework provide tools for reading WSDL and then handling the building and connectivity of code that consumes (uses) an RPC service. So the WSDL is integral for that support code, and it allows you to avoid hours of menial SOAP-encoding semantics. But the WSDL is also essential for you, particularly when you don't have the source code for the service you're connecting to. You'll use the WSDL to find out what to send, and what you'll get back.

You've probably already gotten a strong sense of how WSDL could tell you what you need to know about almost any set of methods and those methods' return types. Now it's time to put this knowledge to use and connect and interact with a Web service.

Section 7. Build a client to access your Web service

So far, you've spent a lot of time learning about JAX-RPC, but no time actually using the API. Even when you autodeployed the BookSearcher class, Axis did the work. Now, though, it's time to put JAX-RPC to work. When you've got a Web service that you want to access, you need to write a client to use that code.

Update your classpath

Before you start writing any code, you need to make some additions to your

Build an RPC service and client using JAX-RPC Page 34 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

classpath. Earlier, you dropped several JAR files into your servlet engine's lib/ directory and used the Axis validation JSP to ensure all those JARs were correctly located. That's because your servlet engine needs JAX-RPC and Axis classes, as well as their dependencies, to serve your Web service.

The same is true of your Web service client. Of course, you could repeat the same process and drop all those same JAR files into your JDK or JRE's ext/lib directory. But that's a great way to make your Java setup confusing and subject to versioning problems, and generally confuse anyone else who ever runs Java on your machine. A much better approach is to update a CLASSPATH variable and set up your profile or environment, keeping your changes local to your personal user setup.

Add the JAX-RPC and Axis JARs

First, navigate back to your Axis installation and take a look at the lib directory. You should see something like Listing 18:

Listing 18. JARs in Apache Axis' lib/ directory

[bdm0509:/usr/local/java/axis-1_4] ls lib/ axis-ant.jar -1.2.8.jar axis.jar log4j.properties commons-discovery-0.2.jar saaj.jar commons-logging-1.0.4.jar wsdl4j-1.5.1.jar jaxrpc.jar

It's easiest to add all of these JAR files to your classpath. The only one that's truly optional is axis-ant.jar, and you should add that JAR if you plan to use Ant to build your projects; it contains Ant-specific extensions that allow you to incorporate Axis tasks into your Ant build file.

One of the best ways to handle adding these JARs is to set an environment variable in your Windows system, or use a .profile (or .bashrc) in a Mac OS X or Linux environment. Listing 19 shows a section of my own .profile, which locates the Axis installation and then adds several JARs from that installation to my classpath:

Listing 19. This .profile adds the Axis JARs to a CLASSPATH environment variable

export JAVA_BASE=/usr/local/java export JAVA_HOME=/Library/Java/Home export XALAN_HOME=$JAVA_BASE/xalan-j_2_7_1 export AXIS_HOME=$JAVA_BASE/axis-1_4 export EDITOR=vi export CVS_RSH=ssh export PS1="['whoami':\w] " export CLASSPATH=$XALAN_HOME/xalan.jar: $XALAN_HOME/xml-apis.jar: $XALAN_HOME/xercesImpl.jar: $XALAN_HOME/xalan.jar:

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 35 of 47 developerWorks® ibm.com/developerWorks

$XALAN_HOME/xsltc.jar: $XALAN_HOME/serializer.jar: $AXIS_HOME/lib/axis.jar: $AXIS_HOME/lib/jaxrpc.jar: $AXIS_HOME/lib/commons-logging-1.0.4.jar: $AXIS_HOME/lib/commons-discovery-0.2.jar: $AXIS_HOME/lib/saaj.jar: $AXIS_HOME/lib/wsdl4j-1.5.1.jar: .

The hard line endings in Listing 19 are for formatting only. In the actual .profile file, all of the classpath entries are on a single line.

Add optional JARs

Before you finish with your environment variables, you may want to make a couple of other additions. Recall that Axis reported on a few optional extras when you ran the validation JSP, specifically activation.jar and mail.jar. If you've been following the tutorial, you probably downloaded those two JARs and added them into your servlet engine's lib/ directory. You should add these to your classpath also. A server that supports those utilities can interact only with a client that has them available as well, so this is a key step.

You can either reference the JARs in your servlet engine's installation (if you're running your client code on the same machine as your servlet engine) or redownload or copy the two JARs to your client machine and add them to your classpath. Listing 20 shows the needed additions:

Listing 20. Adding mail and activation JARs to your classpath

export JAVA_BASE=/usr/local/java export JAVA_HOME=/Library/Java/Home export XALAN_HOME=$JAVA_BASE/xalan-j_2_7_1 export AXIS_HOME=$JAVA_BASE/axis-1_4 export TOMCAT_HOME=$JAVA_BASE/apache-tomcat-6.0.16 export EDITOR=vi export CVS_RSH=ssh export PS1="['whoami':\w] " export CLASSPATH=$XALAN_HOME/xalan.jar: $XALAN_HOME/xml-apis.jar: $XALAN_HOME/xercesImpl.jar: $XALAN_HOME/xalan.jar: $XALAN_HOME/xsltc.jar: $XALAN_HOME/serializer.jar: $AXIS_HOME/lib/axis.jar: $AXIS_HOME/lib/jaxrpc.jar: $AXIS_HOME/lib/commons-logging-1.0.4.jar: $AXIS_HOME/lib/commons-discovery-0.2.jar: $AXIS_HOME/lib/saaj.jar: $AXIS_HOME/lib/wsdl4j-1.5.1.jar: $TOMCAT_HOME/lib/activation.jar: $TOMCAT_HOME/lib/mail.jar: .

Be sure to apply your changes, or source your .profile, or restart your terminal

Build an RPC service and client using JAX-RPC Page 36 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

application to get these changes. You can verify them by checking your classpath variable with the command echo $CLASSPATH. You should see all the JARs you just added.

Build a client class

Now you're ready to build an actual class to connect to your Web service. Start out with a simple skeleton; this should be a Java class, and it doesn't need to implement any particular interface or extend another class. In fact, there's little that's RPC-specific about the basics of a client class.

For this example, Listing 21 shows a BookSearcherClient sample skeleton. The class takes in a keyword over the command line and goes through the motions of calling methods on the Web service. Of course, these methods are just placeholders now; you'll build the logic for them shortly.

Listing 21. A Web service client class skeleton

import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.ServiceException; import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class BookSearcherClient { public static final String SERVICE_URL = "http://localhost:8080/axis/BookSearcher.jws"; public BookSearcherClient() { } public Object[] search(String keyword) throws IOException { // placeholder return new Object[]; } public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java BookSearcherClient [search keyword]"); return; } String keyword = args[0]; BookSearcherClient client = new BookSearcherClient(); Object[] results = client.search(keyword); System.out.println("Returned books for keyword '" + keyword + "':"); for (int i = 0; i

All the classes you'll need are imported in Listing 21. This takes care of having to add them in as you go, something that's tedious and prone to creating errors. A few

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 37 of 47 developerWorks® ibm.com/developerWorks

of the classes are specific to URL connections, something you'll need when it's time to connect to the Web service. The other four classes — the two in javax.xml and the two in org.apache.axis.client — are specific to RPC. I'll talk more about each class as it's used in the sample.

Listing 21 also included a constant that's the URL of the Web service to connect to. If you're using a different host name or port, you'll want to change this URL to match your servlet engine's installation, and the path to the BookSearcher Web service. So you might have a URL like http://dev.myDomain.com/apps/BookSearcher.jws. It's fine to use a different URL, as long as you can type that URL in your browser and get a response like the one shown back in Figure 7.

Next is an empty constructor and a method for searching, based on keyword. I'll talk more about this method soon, so if you've got questions about why this method returns Object[] — an array of objects — then hold on; I'll get to that shortly. Right now, this method just returns null, though, so you can compile the class. This method is where most of the RPC client code will go.

The last bit of code — the class's main() method — creates a new object, grabs a keyword from the command line, and sends it to the search() method, which will in turn make a request to the Web service. All that's left, then, is to build the client code to make a request to the Web service.

Create a Service and a Call object

The fundamental two objects for JAX-RPC client code are org.apache.axis.client.Call and org.apache.axis.client.Service. These two key objects are implementations of the JAX-RPC javax.xml.rpc.Call and javax.xml.rpc.Service classes. Apache Axis provides them in the classes used here, just as other RPC frameworks provide their own implementations.

The first step in any RPC client is to create a new instance of a Service implementation. Then, from that, you can create a new instance of Call, which lets you make a call to a service. Listing 22 shows the code you should add to the BookSearcherClient class: several new member variables and several lines in search():

Listing 22. Creating a Service and Call implementation

import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.ServiceException; import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class BookSearcherClient {

Build an RPC service and client using JAX-RPC Page 38 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

public static final String SERVICE_URL = "http://localhost:8080/axis/BookSearcher.jws"; private Service service; private Call call; private URL serviceUrl; public BookSearcherClient() { } public Object[] search(String keyword) throws IOException { try { if (service == null) { service = new Service(); } if (call == null) { call = (Call)service.createCall(); } // placeholder return new Object[]; } catch (ServiceException e) { throw new IOException("Error creating service call: " + e.getMessage()); } } public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java BookSearcherClient [search keyword]"); return; } String keyword = args[0]; BookSearcherClient client = new BookSearcherClient(); Object[] results = client.search(keyword); System.out.println("Returned books for keyword '" + keyword + "':"); for (int i = 0; i

The code in Listing 22 creates a new Service implementation and then uses that class as a factory to create a new instance of a Call implementation. (This is pretty similar to the type of code you'd write to use a framework such as JAXP, so this might look somewhat familiar to you.)

In a more robust implementation, you'd probably have a factory class to create the Service implementation, keeping the Apache Axis code out of this class altogether (at least directly by reference). The same is true for the Apache Axis implementation of Call. However, for clarity in the example, it's okay to use these Axis classes directly.

With a Call object, you're ready to do some real RPC work.

Specify what you're connecting to

Before you can make a call to a service, you need to configure your Call object. Each Call typically connects to a particular service URL (the target endpoint in SOAP and RPC talk) and operation. If you want to change the endpoint URL or the

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 39 of 47 developerWorks® ibm.com/developerWorks

operation, you reconfigure the Call (or create a new instance).

First, create a Java URL object to store the target endpoint — the Web-accessible URL where your Web service is published:

serviceUrl = new URL(SERVICE_URL);

Next, use the resulting serviceURL as the input parameter to the setTargetEndpointAddress() method on your Call object:

call.setTargetEndpointAddress(serviceUrl);

At this point, your Call knows which service to connect to. However, you also need to indicate the specific operation you want to invoke. You use the setOperationName() method for that, and you can't just pass in a simple string. Instead, you must pass that method a QName. But, happily, you can create a QName on the fly, indicate that you're working with SOAP encoding, and then provide the string name of the operation you want to call:

call.setOperationName(new QName("http://soapinterop.org/", "search"));

This is one of those rare cases in which the code is simpler to write than to understand. A QName is simply a way to represent a qualified name, allowing you to provide XML-like data to the Java platform and let the Java platform do some behind-the-scenes processing for you. In the case of an operation, remember that WSDL — a variant of XML — was used to represent each operation. That's because SOAP, the transport protocol used in Web services, likes XML as its data format of choice. So you can't just use a Java string name for an operation; you need a QName. But, with the help of the javax.xml.namespace.QName class, this is trivial. Listing 23 shows all this code put in context within the search() method (remember, all the import statements were added initially):

Listing 23. Setting the endpoint and operation for your service call

public Object[] search(String keyword) throws IOException { try { if (service == null) { service = new Service(); } if (call == null) { call = (Call)service.createCall(); } if (serviceUrl == null) { serviceUrl = new URL(SERVICE_URL); } call.setTargetEndpointAddress(serviceUrl); // Select operation to call call.setOperationName(new QName("http://soapinterop.org/", "search"));

Build an RPC service and client using JAX-RPC Page 40 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

// placeholder return new Object[]; } catch (MalformedURLException e) { throw new IOException("Error creating service URL at " + SERVICE_URL); } catch (ServiceException e) { throw new IOException("Error creating service call: " + e.getMessage()); } }

Get the results

All that's left is to make the actual call (using, unsurprisingly, the Call object) and get the results. You do this in a single step, using the invoke() method, which takes an object array as a single argument: (Object[]). You stuff your parameters into the array, in the order they're needed. In the case of the search() method, there's just one parameter — the keyword — so you'd create the object array like this:

Object[] params = new Object[] { keyword };

If you had multiple parameters to pass in, as in the addBook() method, you might use something like this:

Object[] params = new Object[] { bookTitle, keywordList };

You then pass these parameters to the invoke() method. Remember, you do not need to specify the operation name (the method name) of the service you want to call; that was done already via the setOperationName() method. All you need to do is take the results and deal with them.

The invoke() method returns an Object, but of course that's just a wrapper for the actual return type. For methods that return strings, the object wraps a String; you'd just cast the returned object to the correct type:

Object[] results = (Object[])call.invoke(new Object[] { keyword });

In this case, the method on the server returns a List. SOAP doesn't understand lists, though, so it defaults to a much more generic type: an array of objects. That puts more of a burden on you, the programmer, because you've got to do something useful with these generic objects and enforce type safety yourself. It's also part of why generics and parameterized aren't very useful in Web services right now; the type safety you gain is lost as information is passed from client to server.

Let's put this line of code into the search() method; Listing 24 shows the additions you need to make:

Listing 24. Making a call and returning the results

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 41 of 47 developerWorks® ibm.com/developerWorks

public Object[] search(String keyword) throws IOException { try { if (service == null) { service = new Service(); } if (call == null) { call = (Call)service.createCall(); } if (serviceUrl == null) { serviceUrl = new URL(SERVICE_URL); } call.setTargetEndpointAddress(serviceUrl); // Select operation to call call.setOperationName(new QName("http://soapinterop.org/", "search")); // Make call and get result Object[] results = (Object[])call.invoke(new Object[] { keyword }); return results; } catch (MalformedURLException e) { throw new IOException("Error creating service URL at " + SERVICE_URL); } catch (ServiceException e) { throw new IOException("Error creating service call: " + e.getMessage()); } }

As was the case with setting the endpoint and operation, the actual code is pretty simple, but a lot is happening:

1. The Call instance looks up the URL endpoint to send requests to.

2. The Call instance sees which operation to invoke.

3. A new SOAP request is constructed, using the target endpoint and request name, along with the argument you supplied. This request is formatted as XML.

4. The XML-formatted SOAP request is sent to the Web service.

5. The Web service replies with an XML-formatted request of its own.

6. The resulting XML is converted back into Java objects — in this case, into an array of objects — and returned to the program.

Of course, as a programmer, all you had to do was call the invoke() method. Pretty nice!

Now that the program is complete, recompile it and make sure your Web service and servlet engine are up and running. Then, run the client program; you should get results similar to Listing 25:

Listing 25. Running the BookSearcher Web service client program

Build an RPC service and client using JAX-RPC Page 42 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

[bdm0509:~/Documents/developerworks/jax-rpc] java BookSearcherClient design Returned books for keyword 'design': Emotional Design Indexed

In many ways, this isn't very exciting; in fact, it's pretty close to the results you got from the test program shown in Listing 7 and demonstrated in Listing 8. The big difference that's not so apparent is that this entire request and response cycle is using SOAP, XML-formatted requests and responses, and the RPC model. And all you've done is write pretty simple, straightforward Java code.

Section 8. Conclusion

The best use you can make of this tutorial is to apply what you've learned to a problem you're working on. Tutorial examples are, at their best, a bit contrived and calculated to teach you several key pieces of functionality. Come up with a problem and apply JAX-RPC to it. Maybe you can build an RPC-based service to respond to an Ajax request from one of your Web pages. You might have a Java program that would benefit from getting information from a server, and RPC would be a great way to field requests from that program. Or you may have existing code that uses SOAP, and you can convert that code to JAX-RPC. Whatever the application, putting JAX-RPC into place in an application or two that isn't the sample from this tutorial is invaluable. You'll inevitably run into problems not detailed here, and when you work through those problems, you'll cement what you've learned here.

One of the best things about JAX-RPC — and some of the best Web service toolkits and APIs — is that the API is largely plumbing. In other words, JAX-RPC doesn't dictate too much about what data you send or receive. As long as you use the language-specific formats and set up your client and server properly, JAX-RPC gets out of the way. That makes programming a much more focused task; you can take care of the JAX-RPC components and then get on with programming your business logic, application logic, and so on. You don't have to worry about how JAX-RPC will change your code.

For these reasons, JAX-RPC is best seen as an enabling technology. It allows you to make a certain type of call to a certain type of server-side program. When you need that particular type of client-server relationship, you use JAX-RPC. When you don't ... you don't. In other words, using JAX-RPC isn't like choosing the Java language as your programming language or Eclipse as your development environment. You're not locked into JAX-RPC or forced to change your coding standards or practices. In fact, JAX-RPC is best suited as one of several options for

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 43 of 47 developerWorks® ibm.com/developerWorks

Web services and client-server interactions.

So use JAX-RPC, build some samples and programs with it, and then add it to your list of toolkits. When you need a simple Web service to distribute to consumers outside your department, organization, or company, JAX-RPC is a great option. It's SOAP- and WSDL-friendly, meaning most Web service consumers can work with it. If you're not in that sort of situation, you're free to use other options, including the newer JAX-WS. The point is to have one more tool so you can make the best decisions about your applications and never feel locked into bad or unwieldy choices.

Build an RPC service and client using JAX-RPC Page 44 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

Downloads

Description Name Size Download method Sample code j-jaxrpc_code.zip 4KB HTTP

Information about download methods

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 45 of 47 developerWorks® ibm.com/developerWorks

Resources

Learn • JAX-RPC 1.1 Project: The JAX-RPC Project hosted on java.net and part of Project GlassFish contains the JAX-RPC reference implementation. •"Web services hints and tips: JAX-RPC versus JAX-WS" (Russell Butek and Nicholas Gallardo, developerWorks, 2006-2007): This five-part article series compares the JAX-RPC and JAX-WS Web services programming models. • Web Services Reference: This Sun page has links to JAX-RPC and lots of related specifications, as well as links to earlier versions of JAX-WS. • Metro Web Services Reference: This Sun site no longer includes JAX-RPC but does have lots of links for JAX-WS and related APIs and documentation. • Metro Web Service Technologies: Read an overview of Web services technology for the Java platform and see how the various JAX-* APIs interrelate. • Web Services Description Language: The World Wide Web Consortium (W3C) maintains the WSDL specification. • JAX-WS Users Guide: Get a taste of the next generation of Java Web services. • Browse the technology bookstore for books on these and other technical topics. • developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming. • developerWorks SOA and Web services zone: Find hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications. Get products and technologies • Apache Axis: Axis 1.x, the toolkit used in this tutorial, is probably the simplest JAX-RPC project available. • Apache Tomcat: You need a Web server to host your JAX-RPC applications, and one of the best — and easiest to get running — is Tomcat. • Project GlassFish: GlassFish, a full-featured engine that allows for RPC-based Web services in the Java language, includes a reference implementation for JAX-RPC. • Java and XML, Third Edition (Brett McLaughlin and Justin Edelson, O'Reilly Media, 2006): This book covers XML from start to finish, including extensive information on Java-based Web services. Discuss

Build an RPC service and client using JAX-RPC Page 46 of 47 © Copyright IBM Corporation 1994, 2008. All rights reserved. ibm.com/developerWorks developerWorks®

• Check out developerWorks blogs and get involved in the developerWorks community.

About the author

Brett McLaughlin Brett McLaughlin is a best-selling and award-winning nonfiction author. His books on computer programming, home theater, and analysis and design have sold in excess of 100,000 copies. He has been writing, editing, and producing technical books for nearly a decade, and is as comfortable in front of a word processor as he is behind a guitar, chasing his two sons around the house, or laughing at reruns of Arrested Development with his wife. His most recent book, Head First Object Oriented Analysis and Design , won the 2007 Jolt Technical Book award. His classic Java and XML remains one of the definitive works on using XML technologies in the Java language.

Trademarks

Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both. Java and all Java-based trademarks are trademarks of , Inc. in the United States, other countries, or both. Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both.

Build an RPC service and client using JAX-RPC © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 47 of 47