Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

I like your type: Describe and invoke Web services based on service type

WSDL tools and techniques

My previous Web Services column focused on describing a Web service according to business classifications or geographic regions—categories meaningful to business professionals or administrators. In this article, I focus on describing a Web service according to categories meaningful to programmers.

Business professionals and administrators primarily deal in business categories or organizational entities—the nouns of their trade. By contrast, a developer's daily work centers on types. Everything that you manipulate through a programming language has a type. For instance, a variable might be an integer or a floating-point type, which both constitute primitive types. A variable can also be a string or a person—more complex object-type varieties. Each programming language presents a different type system that serves as the basic dictionary of your application's data.

Most languages also give you a way to define new types, built out of the language's basic types. When you create a person type in Java, it might consist of firstName and lastName fields, both of which would be strings—a type that Java already provides. Writing a Java program typically involves creating an increasingly sophisticated type system and defining operations (methods) on those types.

When you interact with a Web service from a Java program—whether that program is a servlet or standalone application—that Web service must be represented as a Java type or a series of types inside your program. Likewise, when you wish to advertise your Web service so that others can invoke it over the Web, you must define it with types that other programs across the network understand.

If you must consider only interaction between Java programs, you can just use the Java type system or the custom types you defined on top of the basic Java types, such as person. Java Remote Method Invocation (RMI) is a service-oriented framework that relies on the Java type system for service definition: if both programs are written in Java, they can just communicate on the Internet via RMI. XML-based Web services, on the other hand, require that you define a Web service in a type system not tied to any specific programming language; you must map types defined in a programming language to language-neutral types, and vice versa.

A service's type consists of the service's name, the names of the operations (methods) it offers, as well as the names and types of those methods' parameters and return types. Continuing my earlier example of a cruise reservation Web service, consider a programmer at the imaginary Theseus Cruise Lines. His company operates the Ship of Theseus, which travels between the island of Crete and the city of Athens in the Mediterranean Sea. The following simple Java interface describes a service's type—consisting of one method—that returns an array of strings with the cruise line's destinations. In the article's next section, we will convert this type definition to a non-Java-specific format.

public interface CruiseService {
    public String[] cruiseDestinations(); 
}


In addition to a service's type, when you want to invoke someone else's Web service, you also must know the technical details of locating and connecting to that service. That typically means that a service provider must advertise its service's access points, or endpoints, and the protocols supported by those access points. The URL http://www.javaworld.com, for instance, specifies the HTTP protocol, and www.javaworld.com is the address used to contact the service (the service's endpoint).

The W3C (World Wide Web Consortium) recommends an XML metalanguage, the Web Services Description Language, or WSDL, for describing a service's type and access information. A WSDL-based document can be associated with a Web service in Web service registries, such as UDDI (Universal Description, Discovery, and Integration) or ebXML, along with other information describing that service. Someone searching for your service can retrieve that WSDL document from a URL, convert the service-specific types to language-specific types, and then use the service's endpoint and protocol information to contact, or invoke, the service. Figure 1 illustrates the process of advertising a service's type, endpoints, and protocols:

Figure 1. Create and use a Web service description



Axis power

As a programmer at Theseus Cruise Lines, you can easily implement the above service interface with the following class:

public class CruiseServiceImpl implements CruiseService {
    public String[] cruiseDestinations() {  
        // Or get this info from a database, etc.
        return dests;
    }
    private static final String[] dests = 
        {
            "Athens",
            "Crete"
        };
}


In this example, we let a client invoke the cruiseDestintations() method via the Web using SOAP (Simple Object Access Protocol). Even if you are unfamiliar with SOAP, this example is simple to follow. Several toolkits exist to turn this short Java program into a Web service with no coding. For this example, we will use the latest version of the Apache SOAP toolkit, Axis. I list other tools in Resources below.

You can download the Axis distribution from http://xml.apache.org and install it in your favorite servlet container, such as Tomcat. Currently, that installation proves simple: once you've expanded the downloaded archive file, copy the axis subdirectory to Tomcat's webapps directory. (If you use another servlet container, copy that subdirectory to wherever your servlet tool expects Web applications.) At that point, you've SOAP-enabled your Web server.

Next, copy the CruiseServiceImpl.java file to the axis directory under the Web server, as CruiseServiceImpl.jws. That jws extension stands for Java Web service. If you've installed Tomcat as /usr/local/jakarta-tomcat, the Java source code file must be at /usr/local/jakarta-tomcat/axis/CruiseServiceImpl.jws. The Web server will dynamically compile that class when the service is first invoked (similarly to how JSPs (JavaServer Pages) compile). Since CruiseServiceImpl implements the CruiseService interface, the CruiseService class must be available to the Web server for that compilation to succeed. Therefore, compile CruiseService.java and place the resulting class file in Axis's WEB-INF/classes subdirectory. At that point, you now have a Web service that anyone capable of connecting to your Web server can invoke. If your Web server's URL is www.theseus-cruises.com and your server runs on port 8080 (the default for Tomcat), then the cruise destination Web service will be available at: http://www.theseus-cruises.com:8080/axis/CruiseServiceImpl.jws.

Using the Axis SOAP library, creating a client program is only slightly more involved. The following is that client's entire source code:

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.utils.Options;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import java.net.URL;
public class CruiseClient {
    public static void main(String [] args)
    {
        try {
           // Specify the service's endpoint
           // Substitute your machine's address here
           String endPoint = 
               "http://www.theseus-cruises.com:8080/axis/CruiseServiceImpl.jws";
           // Set up the remote method call
           Service  service = new Service();
           Call call = (Call) service.createCall();
           call.setTargetEndpointAddress( new java.net.URL(endPoint));
           call.setOperationName( new QName("CruiseServiceImpl", "cruiseDestinations") );
           // Perform the remote call
           String[] ret = (String[])call.invoke(new Object[0]);
           System.out.println("Destinations:");
           for (int i = 0; i < ret.length; i++) {
               String s = ret[i];
               System.out.println(s);
           }            
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
}


This Web service client sets up a remote call, performs that call, and prints the results. We first specify the service's endpoint address and the name of the Web service operation to invoke. That name is a qualified name, or QName: it qualifies the method name with a namespace, which is the Web service class name in this case. Compile and run this program. If your Web server is running and you've installed Axis and CruiseServiceImpl.jws, the client should print the strings Athens and Crete—the results returned from the Web service.

The Web service deployment descriptor

Our minimalist cruise destination Web service shows the level of simplicity the Axis/Apache SOAP APIs and tools bring to Web services development. But that example proves inflexible. For one, the client must explicitly reference the service's implementation class, CruiseServiceImpl. A better service would require the client to only know the service interface's name or any name that refers to the service. The Axis runtime would then map that service name to the implementation class. A Web service deployment descriptor (WSDD) will help achieve such flexibility.

A WSDD is an XML file that describes the Web service's deployment details. The following example is specific to Apache Axis, but most other SOAP tools similarly define a deployment descriptor. Below is a simple deployment descriptor for the cruise destination service:

Resources