- What Is a Web Service?
- Crystal Ball Readings
- The ABCs of Web Services
- How to Use a Web Service
- Summary
How to Use a Web Service
Now that we have introduced Web services, let's play around and use one. To make life easy, let's go about this in a step-by-step process. These steps will be broken up between two sections.
"Using SOAP"The first example is all about getting SOAP installed on our machines. We will set up a SOAP server to work alongside the Tomcat JSP Web server. We're using the SOAP server component of the Apache SOAP 2.2 Java API. Once we have this server up, we will build a very simple Web service to run on the local machine.
"Roaming the Internet"The second example will show how to call up a Web service that isn't on the local machine.
Using SOAP
SOAP is really the core of Web services. In these examples, HTTP is the communication tier and Apache SOAP is the application handling the messages. We will use SOAP in two ways: firstly as a SOAP server to listen and process SOAP requests and secondly as a SOAP client to make requests. While many projects will only need to have a SOAP client, we will use both a client and a server to illustrate the full workings of SOAP.
Step 1: Installing a SOAP Server and Client
We need access to a Java implementation of SOAP. For this book, we will use the Apache SOAP API version 2.2. This software is open source and can be freely downloaded from http://xml.apache.org/soap/index.html. In this book we are using a nightly build of the SOAP application. The nightly builds can be found at http://xml.apache.org/dist/soap/nightly/. The nightly build has a few security features that are not found in the main 2.2 release. We recommend using either a recent nightly build or SOAP 2.3 when it is released in 2002.
Apache SOAP requires the following tools:
-
An XML ParserWe are using Xerces, which is currently included with the Tomcat server.
-
JAF (JavaBeans Activation Framework)Simply defined, JAF is a framework for handling the transfer and use of data. Since SOAP is all about moving data back and forth, it makes logical sense that Apache SOAP would use JAF to simplify the internal coding. Sun defines JAF as "a set of standard services to determine the type of an arbitrary piece of data, encapsulate access to it, discover the operations available on it, and to instantiate the appropriate bean to perform said operation(s)." Fortunately, we really don't have to know anything about how to use JAF ourselves as it's used behind the scenes by Apache SOAP.
-
JavaMailJavaMail is a high-level Java API used to simplify the coding of e-mail applications. JavaMail is used by Apache SOAP to enable SMTP as a transport mechanism for SOAP messages.
JAF can be found at http://java.sun.com/products/javabeans/glasgow/jaf.html.
To install JAF, all that you need to do is place activation.jar within your system's classpath so the Java Virtual Machine can find the JAF classes.
The JavaMail APIs can be found at http://java.sun.com/products/javamail/index.html.
To install JavaMail, place the mail.jar within your system's classpath.
Once we have these tools, we are ready to install Apache SOAP. To use SOAP, we need to set up the SOAP client. This is required to permit our JSP container to reach out and talk to SOAP servers. To do this, Tomcat will need access to the soap.jar file that comes along with Apache SOAP. Place the soap.jar file into your classpath. Besides writing the code for the client request, this is the only step required for installing a SOAP client.
For this book, we placed the activation.jar, mail.jar, and soap.jar all in the Tomcat lib directory.
We also need a SOAP server to be up and running to process Web service requests. Within the Apache SOAP installation, you will find a soap.war file. Place this WAR file into your Tomcat webapps directory. This WAR contains a simple but complete Web application that functions as a SOAP server.
In the interest of conserving space, we won't repeat the general installation and testing examples that come with Apache SOAP. However, instead of installing SOAP at the root classpath level, we are having SOAP work through Tomcat. This will work for the examples in this book since we are going to use Tomcat and JSP for all the SOAP access (this is a JSP and XML book, after all). This means that all we really need to do is place the soap.jar, activation.jar, and mail.jar files into the Tomcat lib directory and install the soap.war file in order to have Apache SOAP run through Tomcat. One disadvantage of doing this, of course, is that you will not be able to run the SOAP examples from the Java command line. However, this will make setting up your classpath simple.
Once these files are in place, stop Tomcat and then restart it. Tomcat will install the SOAP server for you.
Let's write a quick test file, shown in Listing 3.4. (Save this file as webapps\xmlbook\ chapter3\ShowClients.jsp.)
Listing 3.4 ShowClients.jsp
<%@page contentType="text/html" import="java.net.*, org.apache.soap.server.*" %> <html> <head><title>List Current Clients</title></head> <body> Listing Current Clients on Local Server:<br/> <% URL l_url = new URL ("http://localhost:8080/soap/servlet/rpcrouter"); ServiceManagerClient l_soap_client = new ServiceManagerClient(l_url); String l_test[] = l_soap_client.list(); for (int i=0; i < l_test.length; i++) { out.print(l_test[i] + "<br/>"); } %> </body> </html>
This file replaces the command-line client test that is in the Apache SOAP documentation. That example validates the services that are running on the server. It works by creating a ServiceManagerClient object with which we can query a SOAP server. In our case, we are using this object to query the status of our local SOAP server. In this example, it queries the URL http://localhost:8080/soap/servlet/rpcrouter.
If you have just installed the SOAP server, this page will only return an empty listing. After all, we haven't installed any Web services yet. We need to build a Web service so we can have something to test.
Step 2: Building a Simple Service
You will be amazed at how simple this will be. The first thing we need to do is create a JavaBean. After all, from our viewpoint a Web service is just a Java object (JavaBean) with a fancy front end (Apache SOAP server). This means we will create the Web service under the SOAP Web application we installed in the previous step. In our case, the JavaBean will look like Listing 3.5. (Save this file as webapps\soap\WEB-INF\classes\xmlbook\chapter3\firstservice.java.)
Listing 3.5 firstservice.java
package xmlbook.chapter3; import java.beans.*; public class firstservice extends Object implements java.io.Serializable { public firstservice() {} public String testService () { return("First Test Service");} }
The Web service is called firstservice and it has one method called testService. The only thing this service does is return a string. Not very exciting, but we intentionally kept it simple so we can test everything quickly. Let's compile the Java file and move on to creating the SOAP deployment descriptor. (After compiling, stop and restart Tomcat so the firstservice.class file is registered within the SOAP server classpath.)
Once we have a Java object to use as a service, we must register the object with the SOAP server. Apache SOAP server uses an XML file called DeploymentDescriptor.xml to track the information of a Web service. The SOAP deployment descriptor is just an initialization file containing the basic service information. Let's go ahead and create this file. It turns out that the Apache SOAP server has a tool that permits us to type in the information and Apache SOAP automatically creates the deployment descriptor file. Point your browser to http://localhost:8080/soap/admin/index.html.
Select the Deploy service option. This will bring up an empty data entry screen. For our example, we can fill it in as shown in Figure 3.2.
Figure 3.2 Deploying a Web service on Apache SOAP server.
Note that this screen extends on for a bit, but for this example, we only need to enter the information shown in the screenshot.
Click the Deploy button at the bottom of the data entry frame (not to be confused with the Deploy button on the sidebar!) when you are done.
To prove that everything is working so far, let's run the first test file, ShowClients.jsp. As shown in Figure 3.3, this will demonstrate that our new service is indeed up and running and that it's available for access from outside the SOAP server.
Figure 3.3 Running ShowClients.jsp.
Step 3: Using a Service
Now that we have a service, the next trick is to show how to invoke the Web service. We are going to write a client to access the service. To write this client we need to do the following:
Gather up the information about the Web service in question. We need the name, parameters, and various other details about the service to track it down.
Invoke the service.
Extract any response sent back from the service.
For our current Web service, the detailed information we need to know is listed here:
The Target Service URI (urn:xmlbook.chapter3)
The method to invoke (testService)
Any parameters to pass in to the method (there aren't any, since our first service doesn't have any parameters)
The URL of the SOAP server in question (for us it's http://localhost:8080/soap/servlet/rpcrouter)
Now back in our XML book Web site it's time to add in the client JSP page shown in Listing 3.6. (Save this file as webapps\xmlbook\chapter3\RunFirstService.jsp.)
Listing 3.6 RunFirstService.jsp
<%@page contentType="text/html" import="java.net.*, org.apache.soap.*, org.apache.soap.rpc.*" %> <% String ls_result = ""; Call call = new Call (); call.setTargetObjectURI("urn:xmlbook.chapter3"); call.setMethodName ("testService"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); URL url = new URL ("http://localhost:8080/soap/servlet/rpcrouter"); Response resp = call.invoke (url, ""); if (resp.generatedFault()) { Fault fault=resp.getFault(); ls_result = " Fault code: " + fault.getFaultCode(); ls_result = " Fault Description: " +fault.getFaultString(); } else { Parameter result = resp.getReturnValue(); ls_result = (String) result.getValue(); } %> <html><head><title>Running a Local Web Service</title></head> <body> The result of the Web service call is <br/> <%= ls_result %> </body> </html>
In this example, the JSP page is acting as the client. When it is executed, it can successfully invoke firstservice, the service we created in a previous example. The result will look like Figure 3.4.
Figure 3.4 Running RunFirstService.jsp.
Now it's time to figure out what is happening. To do this, let's review the important sections of the RunFirstService.jsp example.
In the first section, the code of interest is the import statement. The classes of java.net.* are required for access to the URL object. The org.apache.soap classes were imported to access the Apache SOAP client APIs.
<%@page contentType="text/html" import="java.net.*, org.apache.soap.*, org.apache.soap.rpc.*" %> <% String ls_result = "";
Next, we use the Call object within Apache SOAP to access a Web service. The Call object represents the actual RPC call that is occurring. I personally think of it as my SOAP client because it's the object that is used to call the Web service. In fact, the Call object is the representation of the message to be sent to a Web service:
Call call = new Call ();
Once we have the Call object we need to initialize it with the Web service data (the identification data we supplied when creating the Web service on our SOAP server). The interesting thing to note here is that we are using Constants.NS_URI_SOAP_ENC to tell Apache SOAP to use the standard SOAP encoding. Most of the time, this will be the encoding value you will need to use. The URL object is storing the address of the SOAP server to access for the service:
call.setTargetObjectURI("urn:xmlbook.chapter3"); call.setMethodName ("testService"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); URL url = new URL ("http://localhost:8080/soap/servlet/rpcrouter");
Once we have created our message (the Call object), the next step is to send the message. This is also known as invoking the service and we use the invoke method. The invoke method is a client-side only call to send a message to a service. The results of the call are placed in a Response object. The Response object represents the message sent back from an RPC call:
Response resp = call.invoke (url, "");
Once we have the Response object, we need to check the return message to see what has happened. First, we check for any errors. If something went wrong, we will query the response for the details of the error:
if (resp.generatedFault()) { Fault fault=resp.getFault(); ls_result = " Fault code: " + fault.getFaultCode(); ls_result = " Fault Description: " +fault.getFaultString(); }
If everything is fine, we read the return value embedded within the message. In our case, we know that the Web service is only returning a String object, so we immediately type the return object to a String. In some cases, the logic to parse out the return value would be more robust to handle a complicated object or multiple values:
else { Parameter result = resp.getReturnValue(); ls_result = (String) result.getValue(); }
The rest of the page is just an HTML document to display the results.
The code to access the Web service is relatively simple. Half the battle is getting the information of the Web service to call. The other half Apache SOAP takes care of for us in the sending and receiving of the message. All we are doing is creating a message object, receiving a message object, and querying the results.
Roaming the Internet
This section concentrates on using a remote Web service; we will build an example to access a publicly available Web service from the XMethods Web site. For a Web service, this example will use the TemperatureService service shown in Listing 3.3.
Choosing a Web Service
This example needs the parameters to call the service and that means it's time to go back to Listing 3.3 and the WSDL file. From this file, it is possible to get the information we need to access the Web service. The pieces of data we need are
-
The Target Service URIThis is read from the namespace attribute of the soap:operation element. For this example, it works out to be urn:xmethods-Temperature.
-
The Web service method being invoked by our programThis information is based on the operation element. For this service, we are using getTemp.
-
Any parameters needed for the Web service to run successfullyThese were stored in the message element. From this we find <part name="zipcode" type="xsd:string" />.
-
The URL of the SOAP server in questionFor us it's stored in the soap:address element, within the location attribute, which gets us a value of http://services.xmethods.net:80/soap/servlet/rpcrouter.
This translates into one input parameter called zipcode of type String.
Using these values, we can now write a quick JSP page to access this Web service. The code is shown in Listing 3.7. (Save this file as webapps\xmlbook\chapter3\ AccessService.jsp.)
Listing 3.7 Accessing the XMethods TemperatureService Web Service
<%@page contentType="text/html" import="java.net.*, java.util.*, org.apache.soap.*, org.apache.soap.rpc.*" %> <% String ls_result = ""; String ls_zipcode = (String) request.getParameter("zip"); if (ls_zipcode == null || ls_zipcode.length() == 0 || ls_zipcode.length() > 5) { ls_zipcode = "07931";} Call call = new Call (); call.setTargetObjectURI("urn:xmethods-Temperature"); call.setMethodName ("getTemp"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); /* Create the parameters to pass to the Web service */ Vector params = new Vector (); params.addElement (new Parameter("zipcode", String.class,ls_zipcode, null)); call.setParams (params); URL url = new URL ("http://services.xmethods.net:80/soap/servlet/rpcrouter"); Response resp = call.invoke (url, ""); if (resp.generatedFault()) { Fault fault=resp.getFault(); ls_result = " Fault code: " + fault.getFaultCode(); ls_result = " Fault Description: " +fault.getFaultString(); } else { Parameter result = resp.getReturnValue(); ls_result = result.getValue().toString(); } %> <html> <head><title>Accessing a Remote Service</title></head> <body> The result of the Web service call is <br/> The temperature at <%= ls_zipcode %> is currently: <%= ls_result %> <form method="post" action="AccessService.jsp"> <input type="text" name="zip" id="zip" value="<%= ls_zipcode %>" /> <input type="submit" value="Enter New Zip Code" /> </form> </body> </html>
When this JSP page is accessed, it will produce a page that looks like Figure 3.5.
Figure 3.5 Running AccessService.jsp.
Let's review the example. Most of the code in this example is identical to the RunFirstService.jsp example. The only difference is that this remote Web service is using parameters and our first example didn't need any parameters (because the service didn't use any). This shows that from a programming viewpoint the location of the Web service (local versus Internet) doesn't make much of a difference. From a practical viewpoint, running a remote service might incur additional overhead depending on the location of the Web service. However, those are design issues we will examine in a later chapter.
Let's look at the differences in the code.
While the JSP page is a little more complicated in that we use an HTML form on it (to submit a zip code back to ourselves), we only want to focus on the Web service differences. The only difference from a Web service point of view is the addition of parameters.
Usually, to use parameters we need to use a Vector object to place the parameter arguments:
Vector params = new Vector ();
Once we have the Vector, we place the arguments into our local copy of the Vector object:
params.addElement (new Parameter("zipcode", String.class,ls_zipcode, null));
Once we've finished adding parameters to the Vector, we append the Vector to the Call object.
call.setParams (params);
Everything else is as beforewe invoke our Call object and receive a response.
Calling a service isn't especially hardall the pain is in setting the service up and getting the tools together.