Previous Section Next Section

The Larger Web Services Landscape

Throughout the book, we've been focusing on Apache Axis, which has made sense because SkatesTown is an Axis-based enterprise. Now it's time to take a brief spin through some of the other technologies and packages that are helping to shape the Web services landscape.

Who are all these vendors with SOAP implementations? The remainder of this chapter will cover a brief overview of the breadth of the space, and then we'll dive into a few of the more popular SOAP implementations and see if we can get them to interoperate with SkatesTown.


We've mentioned it before, but one point deserves to be stressed again—Web services are an emerging technology, and things in the space are moving fast. The list of implementations we put forth here is incomplete and will be out of date a few days after it's been typed! One of the best ways to keep track of all the activity is to use the very medium in which the technology is growing—the Web. A large and vibrant community of developers, thinkers, and users are all working together to shape the evolution of the emerging Web service-enabled net. At the end of the chapter, you'll find a list of some of our recommended Internet resources for finding out more and getting involved in the evolution of Web services.

Who's Building SOAP Systems?

If you ask the current crop of pundits to predict the major forces in the enterprise computing space over the next few years, you will find a remarkable consistency to their answers. Pretty much all of them agree that the platforms to watch are J2EE and .NET. Both platforms provide a solid infrastructure for doing distributed application development. So, what's going on in these two worlds with Web services?

The J2EE World

More and more vendors in the J2EE space are integrating Web services into their application server offerings, including:

  • BEA— WebLogic Server, BEA's J2EE offering, now integrates support for SOAP, WSDL, and UDDI as of version 6.1.

  • IBM— WebSphere began including a SOAP toolkit based on Apache SOAP version 2.1 in May 2001. IBM's strong commitment to Web services hasn't flagged since then, and they are continually pushing the space further along.

  • Iona— Iona's XMLBus technology looks extremely promising. It includes both the ability to integrate with their J2EE environment (iPortal) and also a standalone Web service container.

  • Macromedia— JRun is a lean, fast, and inexpensive J2EE server that was distributed by Allaire and has, as of 2001, been brought into Macromedia's product suite. Macromedia has released a Web service technology preview that runs on top of JRun 3.1 and plans to fully integrate Web services into JRun in version 4.0.

Other Java packages don't strictly fall under the J2EE umbrella, such as:

  • GLUE— Produced by The Mind Electric, GLUE is a neat little package. We'll delve into it a bit deeper later in the chapter.

  • SOAP-RMI— A team at the University of Indiana built this slot-in RMI replacement which uses SOAP as its underlying transport for remote invocation. The work they've done on making things fast (with a custom pull-based XML parser) and transparent is quite impressive.

Got .NET?

No survey of the Web services landscape would be complete without mentioning Microsoft's .NET initiative, perhaps the most sweeping Web services story out there.

We'll go into a lot more detail a bit later in the chapter, when we demonstrate how to integrate .NET Web services with our running examples. For now, suffice it to say .NET is Microsoft's attempt to fully internet-enable application development on the Windows platform.

Other Languages and Environments

Of course, plenty of other SOAP implementations are out there as well, written in everything from straight C to high-level scripting environments.


Several C/C++ implementations are available, including Scott Seely's SimpleSOAP, eSOAP by Rosimildo da Silva, and SOAP packages from SQLData and Idoox.


Developmentor, one of the original SOAP instigators, built an early package in Perl. ActiveState has another in their PerlEx product.

One of the more popular SOAP libraries is SOAP::Lite, a Perl package by Paul Kulchenko. We'll cover this comprehensive and easy-to-use package in some detail also.


The popular scripting language Python has a few SOAP packages available—they include by Cayce Ullman, the Zolera Soap Infrastructure (ZSI) by Rich Salz, and Adam Elman's SOAPy.

And That Ain't All, Folks…

Frontier, a popular scripting environment developed by Userland software (one of the originators of SOAP), has a SOAP implementation built in, along with support for XML-RPC, a somewhat simpler XML-based RPC protocol.

There are a couple of PHP implementations (PHP is an HTML scripting environment similar in some ways to Active Server Pages), two in Smalltalk, and several JavaScript clients.

There are also SOAP implementations designed for the PocketPC, and even a couple written in XSLT!

As you can see, there's a lot of SOAP out there! Although we can't cover all these implementations in detail, let's take some time to dig a little deeper into just a few of the more popular Web service toolkits available at the time of this writing. We'll see how easy it is for SkatesTown to connect their services and clients to partners who use completely different platforms. Note that though we've only selected a few of the available packages due to space constraints, many of those mentioned here (and on the sites you'll find at the end of the chapter) are equally powerful and easy to use.

SOAP::Lite—Web Services in Perl

In case you are not familiar with Perl (the Practical Extraction and Report Language), it is a very popular interpreted language designed by Larry Wall back in the late 1980s. Perl is in some ways like a cross between a scripting language and a 3GL.

The Perl motto is "there's more than one way to do it," and in keeping with that idea the language is extremely flexible in terms of its syntax and semantics. We're not going to describe the language itself here, so you might not get much by looking at the examples unless you already speak Perl. If you don't, you might consider spending a little time to learn it from one of the many books or Web sites penned by Perl devotees—it's always good to learn new things, and Perl is almost guaranteed to get you thinking in new and interesting ways about programming. For now, we're going to focus on showing you some SOAP examples using SOAP::Lite, a Perl package written by Paul Kulchenko.

OK—let's dive right in and take a look at a simple client written with SOAP::Lite for the PriceCheck service we built back in Chapter 6. This is the kind of thing that an online store built with Perl might use to access SkatesTown's pricing information via SOAP:

use SOAP::Lite;

print SOAP::Lite ->
        uri('urn:X-SkatesTown') ->
        proxy('http://localhost:8080/axis/services/PriceCheckService') ->
        checkPrice('SKU-NUMBER') ->

Looks pretty simple, no? The first line is just like a Java import statement; it loads the SOAP::Lite package so we can use it. The rest of the code is one virtual line calling into SOAP::Lite to perform a SOAP call. The uri() sets the body URI on the resulting SOAP message—this is identical to setting the namespace argument in the Axis client API. The proxy() tells SOAP::Lite where to actually send the message—this is equivalent to Axis' concept of endpoint. Clearly, checkPrice() is the method we're calling, and result gets us the result value.

Using WSDL with SOAP::Lite

The previous example included knowledge of the network endpoint for the service, and the namespace URI of the SOAP RPC element. This is a fine, and very dynamic, way to access services, but you might not want to specify this stuff every time you make a SOAP request. As you know, WSDL can help us out by encapsulating all that sort of service metadata into one package. SOAP::Lite has a very simple syntax for using WSDL to access a service:

use SOAP::Lite;
print SOAP::Lite ->
       service('PriceCheck.wsdl') ->
       checkPrice('SKU-NUMBER') ->

SOAP::Lite will dynamically generate a virtual proxy object for your service by parsing the WSDL file, and then allow you to call any of the operations using the standard -> syntax. This demonstrates some of the flexibility of the Perl language—because of Perl's dynamic nature, you don't have to know the available method signatures of the service up front in order to write calls like this one, or the previous one. Whereas in Java, the compiler would have to confirm that checkPrice() is a valid method on the service object, and that it indeed takes a single string argument, you have no such restriction in Perl. At runtime, the language interpreter will look for a checkPrice() method in the service after the WSDL file has been parsed.


Another way to use the library to make SOAP calls is to activate the autodispatch feature. To do this, you register a package as an autodispatch handler. Once you've done that, any time Perl encounters an unknown function call, it will attempt to resolve it using the autodispatch handler you defined. In this case, we set it up so that for any such function, we attempt to call a SOAP method on a designated server. Let's take a look:

use SOAP::Lite +autodispatch =>
  proxy => 'http://localhost:8100/axis/Calculator.jws';

print "2 + 7 = " . add(2, 7) . "\n";

Because there's no add() function defined in the Perl code, the SOAP::Lite autodispatch handler is called, which results in a SOAP call to our specified endpoint, invoking the Calculator service automatically.

We feel a lot of kudos are due to Paul, who built a very comprehensive and easy to use package that fits very cleanly with the Perl style. Not only does SOAP::Lite speak SOAP, but also XML-RPC and Jabber (two other simple XML protocols). It also works across multiple transports (including SMTP and raw TCP), handles MIME attachments, and can deal with basic security. If you're a Perl developer interested in Web services, you owe it to yourself to learn more about SOAP::Lite. (Incidentally, a copy of SOAP::Lite is included with every copy of the ActivePerl distribution of Perl for Windows.)

The .NET Web Service World: A Brief Primer

What is .NET, exactly? Well, for all the details, you'll have to go and get one of the many .NET books or surf to—it's a big package. But we can skim the surface, and in particular, show you a few examples of using .NET to build and consume Web services that work alongside SkatesTown.

The .NET framework consists of three major components: a common runtime environment for managed code, a set of core class libraries to provide common features, and a Web-oriented infrastructure called ASP.NET. These work together to provide a unified developer experience that Microsoft hopes will be compelling enough to make it the premier platform for application development. Let's explore what the package holds.

Common Language Runtime

Most of the code you'll deal with in .NET exists in something called the Common Language Runtime (CLR). The CLR is very much like Java's virtual machine—CLR components are implemented as bytecode that runs in a managed environment. This means that the runtime will automatically handle such tasks as garbage collection, threading, security, and loading classes. The really cool thing about the CLR in relation to Web services is that any CLR component can be exposed as a Web service. That means that classes/objects written in C++, Visual Basic, C#, or even COBOL can be easily exported for use across the intranet or the Internet.

C#, incidentally, is Microsoft's new C++-derived object oriented programming language. It has a lot in common with Java, as we'll see when looking at some sample code.

Core classes

The .NET framework class library is akin to the Java class libraries—the classes therein provide services related to the following:

  • Data types, structures and collections

  • I/O, including files, network access, and streams

  • XML manipulation

  • GUI programming

  • Security


The final major component of the .NET framework is ASP.NET, the .NET foundation for building Web applications. ASP.NET is both the natural evolution of Active Server Pages and also a new set of tools and infrastructure for building Web UI and Web services.

A PriceCheck Client in .NET

Let's take a look at building a simple Web service client in the .NET framework. Note that we're using the .NET framework beta 2, which is the current version as of August 2001. By the time this book is in your hands, a later .NET release will probably be available.

A lot of this process is even easier using Visual Studio .Net, but for the client examples, we'll use the command line tools; these are all you'll have available if you're a Windows 98 user, and we want to maximize the potential that you'll be able to run these examples on your machine.

Because the .NET Web service tools are all deeply integrated with WSDL, we'll start by building a client for the SkatesTown price check service that we built WSDL for back in Chapter 6.

To begin, we want to build a proxy class to access the service based on the WSDL file, so to do, so we'll use the wsdl.exe tool that is provided in the Bin/ directory of the .NET framework SDK installation. (You should have this directory on your path as a result of the .NET SDK setup.) The command and its results are as follows:

C:\MyServices> wsdl PriceCheck.wsdl
Microsoft (R) Web services Description Language Utility
[Microsoft (R) .NET Framework, Version 1.0.2914.16]
Copyright (C) Microsoft Corp. 1998-2001. All rights reserved.

Writing file 'C:\MyServices\PriceCheckService.cs'.

Now you'll notice a PriceCheckService.cs file in the current directory. This is the C# source code which was generated by the tool—take a look at it if you're interested; it's pretty straightforward. You'll notice that this class has exactly the same methods we exposed in the Java backend class—it is a proxy for our Web service, and can now be used by any .NET application to get at our price check functionality. The file also contains a C# version of our AvailabilityType class.

We could have also chosen to generate the code in other languages, such as Visual Basic, but we'll stick with C# for our purposes, because it's very comprehensible to Java developers.

To invoke the service, we'll need to wrap the service proxy class in a small bit of user interface so that we can use it. We open our favorite text editor and build the following C# code:

using System;

class PriceCheckClient {
    public static void Main(string [] args)
        PriceCheckService stub = new PriceCheckService();
        availabilityType avail = stub.checkPrice("947-TI");
        Console.WriteLine("There are " + avail.quantityAvailable + " items available, ");
        Console.WriteLine("at a price of $" + avail.price.ToString() + " each. ");

Clearly, this is an extremely basic little demonstration, with a hard-coded SKU argument. The point is simply to show you how using stubs in C#/.NET is similar to the same activity in Java/Axis.

We compile the application like so:

C:\MyServices> csc /r:System.Web.Services.dll /r:System.Xml.dll /r:System.dll 
graphics/ccc.gifPriceCheckClient.cs PriceCheckService.cs
Microsoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]
Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

csc is the C# compiler/linker. The /r flag tells the compiler to reference the indicated assemblies (an assembly in .NET is a packaged set of components, in a DLL or an EXE) and make their contents available during the build process. This command should result in creating a PriceCheckClient.exe in your current directory. If you run that program, you'll be able to make priceCheck requests from our SkatesTown database (see Figure 8.1).

Figure 8.1. PriceCheck with a .NET client.


Exposing .NET Web Services: Package Tracking for SkatesTown

OK, so building clients in .NET is pretty simple. What about exposing services? Luckily, with ASP.NET, it's even easier. (For you Windows 98 folks out there, sorry; this section won't work for you. .NET's server-side components are strictly for Windows 2000 or later. If you want to try the example, please make sure you install the .NET server side components plus all prerequisites.)

Let's bring our attention back to SkatesTown for a minute for this example. For some months now, SkatesTown has been using ShipIt, Inc. to send their packages. All the shipping has happened behind the scenes, but some customers have (quite reasonably) been asking for the ability to get tracking numbers for their shipments. We'll walk you through a simple version of what ShipIt might do on its .NET-based system to provide this feature to SkatesTown.

We'll simulate the package-tracking application in .NET by building an .asmx file. As you'll see, ASMX files are a lot like JWS files—they allow you to drop source code into a regular old text file, and have the ASP.NET framework automatically compile and execute the code for you on demand. There are some differences, though.

For one thing, all ASMX files require a WebService directive at the beginning of the file, which tells the infrastructure what language the source code is expressed in and the name of the class which implements the actual service. ASMX files can use any of the supported .NET languages for Web services (right now that's C#, Visual Basic, and Jscript).

Another difference is that ASMX files automatically support an HTTP GET and POST binding as well as access via SOAP. This means you can call an ASMX-based Web service with just a browser, passing arguments as query string parameters or form fields. Of course, this doesn't allow for the kind of rich data mapping you can do with XML, but it is handy for services that only deal in simple types.

Let's take a look at a simple service implemented as an ASMX file; see Listing 8.1. This service does two things. First, it will generate new tracking numbers, which tie to instances of a PackageInfo class. Second, it will return a tracking report for an existing tracking number. (This example is not a real simulation of the situation—it has been vastly simplified to let us focus more on the Web service infrastructure and less on the application logic.)

Listing 8.1 C# Package Tracking Service in .NET
<%@ WebService Language="C#" Class="ShipIt.PackageService" %>

using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace ShipIt {
    // Here's the "PackageInfo" class which represents
    // a package in transit.
    public class PackageInfo {
        static int maxHops = 4;
        int hop = 1;

        int trackingNumber;

        string currentReport;

        public PackageInfo(int id)
            trackingNumber = id;
            currentReport = "<h2>Tracking Report<h2> <ul>";

         // Move a package one hop and update its
         // tracking log. Don't bother if it has
         // reached its destination.
        public void movePackage() {
            if (hop < maxHops) {
                currentReport += "<li>Arrived at hop #" + hop + "\n";
            } else if (hop == maxHops) {
                currentReport += "<li>Delivered!\n";

        public string getTrackingReport() {
            return currentReport + "</ul>";

     // This is a SOAP RPC service
    public class PackageService : WebService {

       static int lastTrackingNumber = 1;
       static Hashtable trackedPackages = new Hashtable();

       public int getTrackingNumber() {
           PackageInfo pi = new PackageInfo(lastTrackingNumber);
           trackedPackages.Add(lastTrackingNumber, pi);
           return lastTrackingNumber++;

       public string getTrackingReport(int trackingNumber) {
           PackageInfo pi =
           if (pi != null) {
                 // For the sake of example, we move the package
                 // one "step" each time this is called.
               return pi.getTrackingReport();
           return "No such tracking number!";

We have a C# class; this is nothing new. But the text in the square brackets ([]) is different; these directives tell the runtime any meta-information we need to convey. In this case, we're marking each method that we would like to publish as a [WebMethod]. This tells the runtime that the marked methods are accessible via Web service interfaces from outside and should be included in a WSDL description of the service. There is also a [SoapRPCService] directive at the top of the class. It indicates that our class is a SOAP service that uses section-5 encoded payloads and the SOAP RPC style. By default, all .NET services are document-oriented and use literal encoding (see Chapter 3 for an explanation of the difference between literal and section-5 encoding). The [WebService] directive just above that one allows us to specify the namespace of the service (this will be the namespace of the body elements for the service requests and responses).

The getTrackingNumber() method creates a PackageInfo object and inserts that PackageInfo into a hashtable, indexed by an integer tracking number that we return to the user.

When generateTrackingReport() is called, we first look up the PackageInfo that was previously stored. Then, for the purposes of this simple example, we call movePackage() to move the package one hop along the path to its destination. Clearly, in the real world, getting a tracking report for a package does not actually move it closer to its destination (much as we might wish otherwise), but this is a quick and easy way for us to simulate movement. Once the PackageInfo has been moved, we simply return the tracking report generated by the PackageInfo class.

To deploy this service, just drop it into your Web hierarchy. For our purposes, we've put it in Inetpub\wwwroot\shipit\PackageService.asmx. Figure 8.2 shows what happens if we hit it with a browser.

Figure 8.2. Browser view of .NET Package service URL.


This page is automatically generated for us by .NET, and it allows us to not only see what methods are available, but actually test the methods in the browser as well. You can try this out by clicking the method names to get a page that looks like Figure 8.3.

Figure 8.3. Expanded view of the getTrackingReport method.


You'll find the source code to this service in the dotnet/ directory of the examples. If you deploy this service to the location shipIt/PackageService.asmx on your machine (in other words, drop the file in IIS under wwwroot/shipIt/packageService.asmx), you'll be able to try an example that integrates this service into SkatesTown's order processing system. You'll find the example in Chapter 8 under the examples directory in the bws webapp. Just bring up the modified order page, submit the request, and you'll get a package tracking number along with your invoice (see Figure 8.4). Clicking the tracking link will get you a package tracking report.

Figure 8.4. PO results with package tracking.


We encourage you to examine the Java source for the tracking page (track.jsp) to see how this works; as usual, we've just got a JSP front end which calls a remote Web service. The only difference is that for this one, the service is provided by .NET—interoperability in action!

The modified POSubmissionClient class is also worth a look; it works exactly the same way as we've traditionally been writing this class for our examples—in particular, it doesn't expect the SOAP body (the returned invoice) to change in order to carry the tracking number. Rather, we do that by introducing a SOAP header that is plucked out by the client.

The header is produced by a modified version of the POSubmission service—, which you'll find in com/skatestown/services alongside the normal POSubmission class.

GLUE: Another Take on Java Web Services

GLUE, a commercial package put out by The Mind Electric, is another Java SOAP engine, built to be small and fast. It includes its own custom XML parser, Electric XML, in addition to the standard SOAP/WSDL functionality we know and love. GLUE is a very nice package, containing a lot of features that make Web service programming simple. Let's spin through a few quick examples with this toolkit, too.

The GLUE Client for SkatesTown's InventoryCheck Service

Listing 8.2 shows how a client for our InventoryCheck service might appear in GLUE.

Listing 8.2 GLUE Client for InventoryCheck Service
import electric.registry.Registry;

public class GlueCheck
  public static void main( String[] args )
    throws Throwable
      if (args.length != 2) {
        System.out.println("usage: java GlueCheck <SKU> <quantity>");

      // URL to WSDL of web service to invoke
      String url =

      // invoke using array of Objects
      Boolean result = (Boolean) Registry.invoke( url, "checkInventory",
                       new Object[]{ args[0], Integer.parseInt(args[1]) }  );

      System.out.println( "result = " + result );

This looks quite similar to the Axis client code we're used to looking at. GLUE uses the Registry class to dynamically invoke services (and also to publish them, as we'll soon see)—in this case, it's acting as the equivalent of Axis's ServiceClient. The invoke() method on GLUE's Registry class is static, so we pass the URL on each invoke() instead of embedding it within a ServiceClient instance as we would in Axis. Also, you'll note that the URL points to the InventoryCheck WSDL as opposed to the service endpoint itself. GLUE will dynamically parse the WSDL and invoke the service at the URL specified in the service description.

Exposing Services with GLUE : Package Tracking Take 2

GLUE also has a built-in HTTP server, similar to the SimpleAxisServer we talked about in Chapter 4, "Creating Web Services." Publishing a Java class as a Web service in GLUE is really simple—look at the main() method in Listing 8.3. (The rest of the code implements the same package tracking app we built in .NET earlier—and again, the Java version of the PackageInfo class is available in the examples directory.)

Listing 8.3 Simple Web Service in GLUE (Using the Built-in HTTP Server)
import electric.registry.Registry;
import electric.server.http.HTTP;
import java.util.Hashtable;

public class TestService {
    private int lastTrackingNumber = 1;
    Hashtable trackingReports = new Hashtable();
    // Synchronized just in case
    private synchronized int getNextTrackingNumber()
      return lastTrackingNumber++;

    // Move a package one hop and update its
    // tracking log. Don't bother if it has
    // reached its destination.
    public void movePackage(PackageInfo info)
        if (!info.delivered())

    public int getTrackingNumber(String invoiceID) {
        PackageInfo info = new PackageInfo(invoiceID);
        int trackingNumber = getNextTrackingNumber();
        trackingReports.put(trackingNumber, info);
        return trackingNumber;

    public String generateTrackingReport(int trackingNumber) {
        PackageInfo info = trackingReports.get(trackingNumber);

        // For the sake of example, we move the package
        // one "step" each time this is called.

        // Now return the tracking report
        return info.getTrackingReport();

     * The main() method is the actual meat of web service
     * publishing. First we start an HTTP server listening
     * on port 8081, then we publish the service, and
     * we're done!
    public static void main(String [] args) {

        Registry.publish("urn:packageTracking", new TestService());

Note that once you call the publish() API, the server creates background threads which listen for requests. Therefore, you won't be able to stop the server until you interrupt those threads (typically with Ctrl+C).

Other Features in GLUE

GLUE also provides some nice additional features, such as:

  • Customization of serialization/deserialization via decorated XML Schema files. This feature lets you annotate a schema with metadata telling GLUE how to turn the XML into Java.

  • A custom XML parser, ElectricXML, which is designed to be small and fast.

  • A Java<->XML persistence engine.

  • A built-in servlet engine.

It's definitely another package worth checking out.

    Previous Section Next Section