Howard D'Souza

Subscribe to Howard D'Souza: eMailAlertsEmail Alerts
Get Howard D'Souza: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: Apache Web Server Journal

Apache Web Server: Article

Beyond SOAP: Optimized Web Services

Beyond SOAP: Optimized Web Services

To most people, the term "Web service" implies a remote server offering some functionality that can be invoked over an HTTP connection, through SOAP-based messages.

The ability to penetrate firewalls, as well as not having to install any code on the client side, makes it easy for service providers to quickly deploy and make their services available to a wide audience over a remote network. All that's needed is the service's definition, usually in the form of a WSDL file. While this remains a popular usage pattern for conventional SOAP-based Web services, an area that has been largely ignored is the use of Web services within a company's enterprise. One of SOAP's biggest criticisms has been that SOAP-based Web services don't perform as well as traditional distributed architectures like EJB or CORBA. There is some truth to this. If the client and server are colocated on a fast network, the overhead of pumping messages through SOAP over HTTP may be much more than a traditional remote call.

What is less commonly known is that the Web services standards do not mandate the use of either SOAP or HTTP. In fact, WSDL, which is commonly used to describe and publish Web services, is extensible and allows services to be implemented over virtually any protocol or transport. WSDL provides a language- and protocol-neutral way to describe a service, and allows extensions that can bind this neutral definition to any specific transport. In WSDL terms, the tie between the abstract service definition and its concrete endpoint is called a "binding." It is possible to have multiple bindings for a single service, allowing sophisticated clients running on a fast local network to use the alternate binding to get significantly improved performance. At the same time, the service can offer remote clients the same functionality over SOAP and HTTP. This scenario is depicted in Figure 1.

 

Overview of WSDL
To understand how multiple bindings may be defined and exposed for a Web service, let us first explore the Web Service Definition Language. WSDL is a W3C working draft for an XML format for describing network services. A service definition includes an abstract description of the operations and messages that are supported, and their bindings to a concrete protocol.

A WSDL document may define types, messages, operations, and port types, which are abstract. It may also define services, ports, and bindings, which are specific to an implementation. Each of these corresponds to an XML element and is described below. Some of these sections are extensible, which allows WSDL to support future protocols and formats.

  • Types: Contains abstract type definitions for the data types used by the operations of the Web service. The most commonly used type system is XSD.
  • Message: Defines an abstract message that has a unique name and a set of parts. Each part refers to an intrinsic type, or a type defined in the types section.
  • PortType: Each portType element has a unique name and defines an abstract set of operations provided by the service. Each operation may define input, output, and fault messages.
  • Binding: Defines concrete message and protocol details for each abstract operation in a portType and can be extended to support new protocols.
  • Port: Each port definition section represents a single endpoint or address for a binding and can be extended to support new protocols.
  • Service: Defines a single service. It groups all the ports for that service together.

    JAX-RPC: A Higher-Level Web Service Interface
    By providing a means for clients to call Web services through a higher-level interface such as Java, we can bypass the use of SOAP and choose the binding that would be most appropriate. JAX-RPC addresses this need. Since the operations provided by a service are defined in the portType section of the WSDL definition, a client should theoretically be able to invoke operations on the service based on the service's abstract portType definition.

    In an effort to distance the user from the details of SOAP messages, a group of leading Java vendors, including Sun, IBM, and BEA, proposed a Java Specification Request (JSR101) that defines a Java API for making XML-based remote procedure calls. This API - called JAX-RPC - is an open standard for exposing and invoking Web services from Java. JAX-RPC enables a service endpoint to be developed using either a Java servlet or an Enterprise JavaBean, and can be extended to other implementations. JAX-RPC provides for mapping services between Java and WSDL. A service provider can run a conversion tool and generate WSDL for a Java interface. This WSDL can be published, and may be used by clients to invoke the service. A client may run a conversion tool on the WSDL for a service, and generate Java interfaces and client stubs for invoking that service. Thus, it is possible for both the service provider and the client to program exclusively to Java interfaces, and use JAX-RPC-compliant conversion tools to provide the plumbing between SOAP and Java. The Apache Foundation's Axis project (http://xml.apache.org/axis) provides a free implementation of WSDL2Java that can be used to generate JAX-RPC-compliant Java interfaces, as well as SOAP stubs for any WSDL document.

    For example, consider a WSDL document containing a portType for a stock quote service that had a single operation that took a symbol and returned its price. The WSDL fragment containing the abstract service definition is shown in Listing 1.

    If WSDL2Java were run on the service, it would generate a JAX-RPC-compliant Java interface that looked something like:

    package quote;

    public interface StockQuote extends
    java.rmi.Remote
    {
    public double getQuote(String symbol)
    throws java.rmi.RemoteException;
    }

    It would also generate a factory interface class for the service, which has methods that create an instance of StockQuote (backed by a SOAP implementation), as well a "locator" that implements this factory as interface (see Listing 2).

    A SOAP client stub that implements Stock Quote is also generated. The stub executes the getQuote method by making a SOAP call to the remote server.

    A client can use the service without dealing directly with SOAP as follows:

    StockQuoteServiceLocator locator = new
    StockQuoteServiceLocator();
    StockQuote quote = locator.getStock
    Quote();
    double price = quote.getQuote("CYSV");

    The getStockQuote method returns the "default" port, which in this case is SOAP.

    Optimized Web Services
    It is apparent from the code described previously that the client sees the remote SOAP service as a local Java object. This is great because we can replace the implementation with a more "optimal" protocol without impacting clients. For example, if we knew that the Web service was implemented as an EJB, we could use IIOP or RMI to directly invoke the service, without the overhead of converting to and from SOAP. This would be transparent to the client, but would result in a significant performance improvement.

    If the StockQuoteLocator class was enhanced, the getStockQuote method could be changed to return implementations of different endpoints. Consider a stateless session EJB implementation of the above StockQuote service. Its remote interface would look like:

    package ejbquote;
    public interface StockQuote extends EJBObject
    {
    public double getQuote(String symbol) throws RemoteException;
    }

    For simplicity, we define the signature of the getQuote method to be the same as that in the StockQuote interface. To locate the EJB, we must capture its location information in an address-like object. For this purpose, let's define an EJBAddressInfo class.

    public class EJBAddressInfo
    {
    public String jndiURL;
    public String homeName;
    public String homeClass;
    public String remoteClass;
    public Properties jndiProperties;
    }

    Now the StockQuoteLocator object can be modified to add an overloaded version of the getStockQuote method that takes an EJBAdd ressInfo instead of a URL:

    public quote.StockQuote getStockQuote(EJBAddressInfo portAddress)
    throws javax.xml.rpc.ServiceException;

    A client that wanted to use the EJB binding can be coded as shown in Listing 3. The locator returns an instance of Stock Quote backed by an EJB client that makes an EJB remote request to fulfill the getQuote operation.

    The WSDL Extension Mechanism
    This looks great except that the client has to create an EJBAddressInfo object and populate it with details about the EJB. This forces the client to know the specifics of the implementation, and defeats the purpose of using a pure Java interface. It would be nice if the address information could be specified in a way that didn't require the client to know about the service's implementation. That's what the WSDL extensibility mechanism is for. The port section that appears within a service definition in the WSDL document can be extended to describe any kind of address. In the case of EJB, the information that is needed to locate the EJB can be represented in the port section as shown below.

    First, let's define an XML namespace for our WSDL extension to the definitions element.

    <definitions xmlns:ejb="http://schemas.
    myextensions.org/wsdl/ejb" ... />

    Then, add the EJB location information to the port section in the service definition (see Listing 4).

    Next, add a binding section for the EJB Re-mote interface, referencing the StockQuote portType. Since we've kept things simple by assuming the method signatures of JAX-RPC StockQuote and the EJB remote interface are exactly the same, we really don't need any additional binding information. The EJB port's binding looks like:

    <wsdl:binding name="StockQuoteEJB
    Binding" type="impl:StockQuote">
    <ejb:binding/>
    </wsdl:binding>

    Any additional mapping of method names or parameters that is needed can be included in the binding section.

    Now we modify our locator implementation to extract all the information it needs from the WSDL. We could publish our WSDL through a UDDI directory or URL, and the client could retrieve and save it locally for better performance. The client code for both the SOAP and the EJB bindings is now the same, and looks like:

    File wsdlPath = new File("/services/StockQuote.wsdl");
    StockQuoteServiceLocator locator = new StockQuoteServiceLocator(wsdlPath);
    StockQuote quote = locator.getStockQuote();
    double price = quote.getQuote("CYSV");

    The locator parses the WSDL to extract the endpoint information, and creates the appropriate implementation of the StockQuote service. In the case of EJBs, the implementation retrieves the session bean's remote interface and delegates all calls to it.

    Invoking the Optimized Service
    For the locator to be able to extract destination information, it needs to parse the WSDL. While a JAXP-compliant XML parser can be used to parse the WSDL, it's easier to use a WSDL library to handle the low-level details-JSR110, which describes a Java API for WSDL parsing. There is an open-source implementation of this JSR called WSDL4J, which is referenced from the Apache Axis Web page.

    WSDL4J has built-in extensions for SOAP and provides an extensibility mechanism for defining other types. We can define extensibility elements for handling our EJB extensions, and register them with WSDL4J. When WSDL4J encounters our elements, it will invoke our extensions. Building a WSDL4J extension is beyond the scope of this article, but the source code is well documented.

    In the case of EJBs, the StockQuote implementation delegates incoming requests to the EJB's remote interface. This can be achieved with very little code by using Java's Dynamic Proxy feature. All that is required is to implement the InvocationHandler interface in Listing 5. The locator instantiates our dynamic proxy implementation of StockQuote (see Listing 6).

    Unlike the generated SOAP stub that is specific to the interface it was generated for, the use of dynamic proxies allows the EJBHandler class to be generic. The same technique could be used for building implementations for any service binding, including local and remote Java objects, JMS or .NET. The client always talks to a generic Java interface and doesn't know or care what the actual service implementation is. The preferred binding for a service can be made configurable, and an implementation could be switched to a more optimized transport, without the client knowing about it.

    Conclusion
    Using this strategy, a SOAP Web service can be exposed over alternate, more optimal transports without requiring the client code to change. The decision as to which transport is the most optimal is not an easy one. The service locator can be made as sophisticated as needed to decide which binding should be used for a given service. Often, this decision can be based on whether the client and server are on the same network, and an examination of the IP addresses is all that may be needed. An issue that I haven't addressed is the mapping of complex types. In most cases, types that are being passed over SOAP can be mapped directly to JAX-RPC-compliant JavaBean types. Serializers and deserializers may need to be written if the mapping is not straightforward. Most JAX-RPC implementations provide support for user-defined serializers and deserializers as well as generation of Java beans for complex types.

    Another issue that must be dealt with is exception handling. Depending on the binding transport that is being invoked, different kinds of exceptions may be thrown. JAX-RPC declares all methods as throwing RemoteException, which wraps the actual exception.

    There are also security and transactional implications when multiple bindings are provided. The Web services community is working on resolving and standardizing these issues for Web services in general. Open-source efforts like the WSIF project working toward standardizing multiple Web service bindings, but we have a long way to go before any standards emerge. We are still very early in the life cycle, but optimized Web services looks like something that can greatly enhance the usability of Web services within an enterprise.

    References

  • JSR-101 Java API for XML-Based RPC: http://java.sun.com/xml/downloads/jaxrpc.html
  • JSR-110 Java APIs for WSDL: http://jcp.org/en/jsr/detail?id=110
  • Web Services Description Language (WSDL): http://www.w3.org/TR/wsdl
  • Apache Axis Project: http://xml.apache.org/axis
  • Java Dynamic Proxy Classes: http://java.sun.com/j2se/1.3/docs/guide/ reflection/proxy.html
  • Web Services Invocation Framework (WSIF): www.alphaworks.ibm.com/tech/wsif
  • More Stories By Howard D'Souza

    Howard D'Souza has more than 10 years’ experience in software development and is a software architect at Cysive, Inc., where he works on the Cymbio Interaction Server. Howard is a Sun Certified Java Programmer and Developer with a post-graduate diploma in software technology and a bachelor's degree in Engineering.

    Comments (0)

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.