One of those topics is Web Services. Lots of people have been talking about Web Services for awhile now. If you are looking for yet another article on how Web Services are going to change the world, then this article is not for you. If, however, you are interested in the fastest way to create a Web Service so that you can start playing with this great new technology, then read on. Sun's Java Web Services Developer Pack (Java WSDP) is a Swiss army knife of tools that you can use to quickly and easily create Java Web Services. As of WSDP Version 1.1, it contains the following:
- Java Architecture for XML Binding (JAXB) V1.0
- Java API for XML Messaging (JAXM) V1.1.1
- Java API for XML Processing (JAXP) V1.2.2 (with XML Schema support)
- Java API for XML Registries (JAXR) V1.0_03
- Java API for XML-based RPC (JAX-RPC) V1.0.3
- SOAP with Attachments API for Java (SAAJ) V1.1.1
- JavaServer Pages Standard Tag Library (JSTL) V1.0.3
- Java WSDP Registry Server V1.0_04
- Ant Build Tool 1.5.1
- Apache Tomcat 4.1.2 dev container (plus fixes)
You can download the Java WSDP here. There are currently two versions of the kit, one for Windows 2000/XP and one for Solaris 8 and 9 and Red Hat 7.2. You should be able to run it in other environments, but these are the only ones that Sun specifically tests. For the Windows version, you can read the installation instructions here. However, all you really need to know is that to install it you should first have a 1.3.1 or higher version of the Java 2 SDK (J2SE SDK) and about 70 MB of space in addition to the 34 MB that the installation package itself occupies. Double-click on the installer and follow the directions for a typical install. Note that, if you are using the J2SE SDK Version 1.4, you will have to manually move some files as directed by the installer.
You can download a very comprehensive tutorial on using the Java WSDP from here, and the source code from the examples is also available for download from here. The examples are packaged as a zip file that you should unzip to
So let's create our own Web Service and Web Service client, but we'll just focus on the code that you actually have to write, and we will cookbook most of the configuration. One of my favorite Arthur C. Clarke quotes is "Any sufficiently advanced technology is indistinguishable from magic," so, for now, let's just assume that what's going on behind the scenes in our example is magic. For those of you who don't believe in magic, I would direct you back to Sun's 928-page tutorial on Web Services. For the rest of you, download and install the Java WSDP. Then, download the Web Services example page and unzip it to the documents directory so that we can nab a few choice configuration files. Now, we are ready to create our Web Service and client.
Example Overview
We are going to build a simple inventory checking Web Service that looks up the quantity of parts in inventory for a particular part number. We will build our Web Service using JAX-RPC. JAX-RPC is in the alphabet soup of acronyms included as part of the Java WSDP. Essentially, it is an XML-based Java API for making remote procedure calls. The XML is wrapped as SOAP messages and sent over HTTP.
First, we will develop and deploy the Web Service itself. Then, we can create a client to test out the Web Service.
Web Service
Our Web Service will simply wait for SOAP messages (requests); then, JAX-RPC will perform the magic of decoding the message into a method invocation on a particular object--in this case, a call to check inventory for a particular part number. The results of the request are returned, and once again, through the magic of JAX-RPC, the results are encoded into a SOAP message and returned to the requestor.
So let's start by cranking up Tomcat and all the other WSDP services. You can do this by going to
- build.properties--This file is read by the generic build.xml file that we borrowed from the Java Web Services Tutorial and will be provisioned with the files from our example. It will be used for both the Web Service and the Web Service client.
- InventoryIF.java--This is the service definition interface Java source file.
- InventoryImpl.java--This is the service definition implementation Java source file.
- jaxrpc-ri.xml--This configuration file generates ties.
- web.xml--This file is the deployment descriptor.
What follows is the contents of the files listed above, which should reside in
build.properties
context-path=inventory-jaxrpc
client-class=inventory.InventoryClient
client-jar=${example}-client.jar
portable-war=${example}-portable.war
deployable-war=${context-path}.war
war-path=${tut-root}/tutorial/examples/jaxrpc/${example}/dist/${deployable-war}
username=mike
password=panda
InventoryIF.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface InventoryIF extends Remote
{
public String checkInventory(String s) throws RemoteException;
}
InventoryImpl.java
public class InventoryImpl implements InventoryIF
{
public String message = "Inventory ";
public String checkInventory(String s)
{
String results = "0";
// In a real world Web Service you would
// probably have a call to the database here
if (s.equals("AAA"))
{
results = "100";
}
else if (s.equals("BBB"))
{
results = "200";
}
else
{
results = "0";
}
return results;
}
}
jaxrpc-ri.xml
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd"
version="1.0"
targetNamespaceBase="http://com.test/wsdl"
typeNamespaceBase="http://com.test/types"
urlPatternBase="/ws">
name="MyInventory"
displayName="Inventory Service"
description="A web service to check inventory"
interface="inventory.InventoryIF"
implementation="inventory.InventoryImpl"/>
endpointName="MyInventory"
urlPattern="/inventory"/>
web.xml
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
To create and deploy our Web Service, we will do the following:
1. Compile the service definition (InventoryIF.java and InventoryImpl.java)
2. Create the WAR file
3. Generate ties and WSDL
4. Deploy and verify the service
The service definition is composed of two Java source files, InventoryIF.java and InventoryImpl.java. We'll compile them by issuing the following Ant command at the command prompt while in the
Next, we will package the class files we just generated along with jaxrpc-ri.xml and web.xml into a WAR file with the following commands:
ant package
These commands create the inventory-portable.war file. Next, we need to generate the tie classes and WSDL file. Tie classes sit between JAX-RPC and the classes that implement a service. WSDL files describe services. We will also need the WSDL file later when we build our client. The following command will generate our ties and WSDL file:
We are now ready to deploy and test our Web Service. The service can be deployed using this command:
Once you have deployed a service, you will need to use this command to redeploy it:
To test that the service was deployed correctly, launch your favorite Web browser and go to the following URL:
This location is known as the "service endpoint URL." It will report back such information as the PortName, status (active or inactive), the remote interface, and the implementation class.
Congratulations! You have deployed your Web Service! Now, let's make a client to consume it.
Web Service Client
To create a client for our Web Service, we will reuse a couple of the source and configuration files from our Web Service. Additionally, we will want to use the WSDL file that we generated previously. We will need the following files:
- build.properties--Same as the one from above
- config.xml--Configuration file for generating Web Service stub
- InventoryClient.java--The client code class containing main() and a call to the Web Service stub
We will do the following to generate our client:
1. Build the client stubs
2. Compile the client source files
3. Jar the client stubs and class files
Client stubs are the reciprocal of tie classes. As the name implies, a stub is just a local interface that represents a remote service. To build the client stubs, we again use the build.xml file that we liberated from the Web Services tutorial. We can issue the following command to generate the stubs:
Our only new files for the client are InventoryClient.java and config.xml, which look like this:
InventoryClient.java
import javax.xml.rpc.Stub;
public class InventoryClient
{
public static void main(String[] args)
{
try
{
Stub stub = (Stub)(new MyInventory_Impl().getInventoryIFPort());
InventoryIF inventory = (InventoryIF )stub;
String partNumber = "AAA";
System.out.println(inventory.checkInventory(partNumber));
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
config.xml
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
packageName="inventory"/>
Compile InventoryClient with this command:
Then, jar it up:
Now, we can test our Web Service by invoking the client:
Our expected result is that the client will look up partNumber AAA, find that there are 100 available, and echo that back out to the command line. Of course, to check for other partNumbers, you will need to modify the client source code, recompile, and re-jar.
And that's all there is to it! There are some log files in
Summary
In order to create Web Services, you don't have to become an XML guru or understand all the gory details of XML parsing or namespaces. Instead, it is possible to create some simple examples and rely on the tools to provide a little magic. We simply made a Java client that makes requests to a stub and defined a serve- side Java interface and implementation to handle requests. Everything in between was handled by the generated stubs and tie classes that in turn talk to the underlying JAX-RPC infrastructure. When you are ready to look under the hood and see how all the magic is done, the Web Services tutorial has all the details.
Where We Have Been
Over the past year, we have explored our way through the Java Jungle together. We started, ironically enough, with how to use Java Web Start to make sure your users are always running the latest version of your software. We explored how to use JavaMail to send email from within your Java applications and how to use SQLJ instead of JDBC to connect to your relational database. We then spent awhile doing some Web programming with servlets and JavaServer Pages (JSPs). We also spent some time on Design Patterns and learned that, even though object-oriented languages like Java are great at code reuse, you get even more benefit from design patterns, which give you design reuse. Then, we delved into how to counteract the Laws of Thermodynamics and software entropy though Refactoring. Armed with a background in design patterns and refactoring, we took a look at the oddly named Extreme Programming methodology of software development. A cross-platform language like Java deserves a cross-platform build tool, but since Sun didn't make one as part of Java itself, we took a look at Ant, the tool the gurus at Apache developed. With all these new concepts that we are learning, it is becoming increasingly more important for developers to be able to communicate at an abstract level, so we spent some time with UML (Unified Modeling Language) and learned how a picture can be worth a thousand lines of code. Next, we examined how you can use JBoss as a free alternative to costly application server.
As I like to say, "Java Journal is not my column; it is your column." What do I mean by that? Well, it's simple. I let you, the reader, help select my topics. So drop me an email at
Finally, I would like to say thanks for all the suggestions and feedback you've provided over the last year. You have been critical in making this column a success. I would also like to thank my wife, Kimberly Floyd, for putting up with all the late nights and my editor, Victoria Mack, for her superb wordsmithing. I look forward to being your guide through the Java Jungle for another year.
Michael J. Floyd is an extreme programmer and the Software Engineering Technical Lead for DivXNetworks. He is also a consultant for San Diego State University and can be reached at
LATEST COMMENTS
MC Press Online