Skip to main content

Explore the Web Services Bus, Part 2: Comparing Bus filters and Axis handlers

See how the Web Services Bus and Axis stack up

Greg Flurry, Senior Technical Staff Member, IBM Software Group
Greg Flurry
Greg Flurry is a member of IBM's Software Group Emerging Technologies, which investigates leading-edge technologies for a wide range of e-business environments. You can reach Greg at flurry@us.ibm.com.

Summary:  What does the Web Services Bus offer when compared to other Web services frameworks? Well, for one thing, its Web Services Invocation Framework (WSIF) heritage means that it always operates on a canonical form of data, not a SOAP-specific form. In this second article in a two-part series, Greg Flurry takes you step by step through a simple example Web service to show you how the Web Services Bus stacks up against the SOAP-based Apache Axis. But not every decision is either/or; this article will also give you a good look at the ease at which these two frameworks can interoperate.

Date:  01 Jan 2003
Level:  Intermediate
Activity:  593 views

The Web Services Bus, available in version 3.2.2 of the Web Services Toolkit at IBM alphaWorks, is a framework for constructing Web services processors. (See the Resources section below for a link to the WSTK.) The Bus offers an enhanced environment for conducting dynamic e-business with Web services for both the service requestor (the client side on-ramp) and the service provider (the server side off-ramp).

In Part 1 of this series, you learned how to leverage unique features of the Bus to publish, discover, and invoke Web services implementations. In this article, you'll learn more about the filters that the Bus provides, which can manipulate requests and responses in both the on- and off-ramps. Bus filters are analogous to Apache Axis handlers. Bus filters, consistent with the Web Services Invocation Framework (WSIF) heritage of the Bus, operate on a canonical form of information rather than a SOAP-specific form as current Axis handlers do.

The Bus prototype that is part of version 3.2.2 of the WSTK includes a number of demonstrations of the various capabilities of the Bus, including a few examples that show how to deploy and use Bus filters. In this article, you'll build on those with new examples and use them to explore Bus filters in depth. In addition, I'll compare a Bus filter-based implementation to an Axis handler-based implementation to demonstrate the advantages of Bus filters. Please see the documentation provided with the Bus prototype implementation for additional details. (See the Resources.)

The example components

The basis for the examples in this article is the ubiquitous stock quote JavaBean. I'll use the same implementation for both the Bus and Axis versions of the example; this implementation is slightly different than the one used in Part 1 of this series. It is the Bus filters and Axis handlers -- both of which fall under the generic category of interceptors -- that make the examples interesting. The interceptors in the examples simulate the (de)compression of the payload using a very simplistic technique. Figure 1 shows the overall architecture used in the examples.


Figure 1. Client-server architecture of the example
Client-server architecture of the example

Figure 1 shows both the client and the server side of the example. On the client side, a service requestor makes a request for a quote, using some form of Web service engine to interact with a service provider. The engine can be the Axis client engine or the Bus on-ramp engine. The engine invokes an interceptor that examines the request, potentially compresses the content, and inserts context into the request, indicating the compression technique used. The engine eventually sends the modified request to the service provider.

On the server side, the Axis server engine or the Bus off-ramp engine receives the incoming request and invokes an interceptor that examines the request and potentially decompresses the content, based on the compression technique indicated in the context retrieved from the request. The engine passes the modified request on to the actual service provider -- in this case, the JavaBean. In the example, the response from the provider does not pass through any interceptors, though both Axis and the Bus support that capability.

The stock quote service

Listing 1 contains the implementation of the stock quote service used in the examples, SQ.java.


Listing 1. SQ.java, the example stock quote service
		
package gaf.filter.sq;
public class SQ {
    public float getQuote(String symbol) throws Exception {
        if (symbol.equals("XXX")) {
            return ((float) 55.25);
        } else if (symbol.equals("YYY")) {
            return ((float) 125.35);
        } else {
            return ((float) 0);
        }
    }
}

This stock quote service implementation returns unique values for the symbols XXX and YYY, and returns zero for anything else. It is important to notice that the service does not have to know about any (de)compression that might take place.

The stock quote clients

Both clients have been written to be driven by WSDL. This is mandatory for Bus clients, as WSIF is driven by WSDL. It is optional for Axis, and makes the Axis client a little bit more complex than it absolutely needs to be; but it's generally a good practice, as it allows Axis to automatically extract the information required to invoke services.

The Bus client
Listing 2 shows a synopsis of the Bus version of the client. The full source for both clients is included in the code package that accompanies this article.


Listing 2. A synopsis of the Bus version of the sample client
		
package services.demos.wsbus.client.examples;
public class BusSQClient extends SQClientBase {

    public static void main(String[] args) throws Exception {

        System.setProperty(
            WSIFServiceFactory.WSIFFACTORY_CLASSNAME,
            "com.ibm.wsbus.wsif.WSIFBusServiceFactory");
        WSIFBusServiceFactory factory =
            (WSIFBusServiceFactory) WSIFServiceFactory.newInstance();
        WSIFService service = factory.getService(null, args[0]);

        getQuote(service, "XXX");
        getQuote(service, "YYY");
        getQuote(service, "ZZZ");
    }

    private static void getQuote(WSIFService service, String sym) 
        throws Exception {

        javax.wsdl.Port wp = getPort();
        WSIFPort port = service.getPort(wp.getName());
        WSIFOperation operation =
            port.createOperation("getQuote", "getQuoteRequest", null);
        WSIFMessage inputMessage = operation.createInputMessage();
        WSIFMessage outputMessage = operation.createOutputMessage();
        WSIFMessage faultMessage = operation.createFaultMessage();

        inputMessage.setObjectPart("symbol", sym);
        boolean operationSucceeded =
            operation.executeRequestResponseOperation(
                inputMessage, 
                outputMessage,
                faultMessage);
        System.out.println("The quote: " + outputMessage.getFloatPart("return"));
    }
}

In the Bus version of the client, BusSQClient first takes the steps necessary to ensure that the Bus is used; this entails setting a system property appropriately and using a Bus-specific factory for generating service representations. Next, the client gets a representation for the stock quote service defined by the incoming WSDL (arg[0]). To get a quote, the client gets the single port defined for the service; using that port as a factory, the client gets the representation of the getQuote operation defined by the indicated signature (operation name and parameter name). Finally, the client invokes the operation.

The Axis client
Listing 3 contains a synopsis of the Axis version of the client.


Listing 3. A synopsis of the Axis version of the sample client
		
package services.demos.wsbus.client.examples;
public class AxisSQClient extends SQClientBase {

    public static void main(String[] args) throws Exception {
            
        QName serviceQN = wsdlService.getQName();
        Service service = new Service(new URL(args[0]), serviceQN);

        getQuote(service, "XXX");
        getQuote(service, "YYY");
        getQuote(service, "ZZZ");
    }

    private static void getQuote(Service service, String sym) 
        throws Exception {

        QName portQN = new QName(def.getTargetNamespace(), getPort().getName());
        Call call = (Call) service.createCall(portQN, "getQuote");
        Object in[] = new Object[1];
        RPCParam p = new RPCParam("", "symbol", sym);
        in[0] = p;
                
        Float ret = (Float) call.invoke(in);
        System.out.println("The quote: " + ret);
    }
}

In this version of the client, AxisSQClient first gets a representation for the stock quote service defined by the incoming WSDL (arg[0]). To get a quote, the client gets the representation of an operation for the only port in the service. Finally, the client invokes the operation.

It is important to note that neither client knows anything about any compression that may or may not take place.

The interceptors

The interceptors are of course complementary, in that the decompression interceptor must understand what the compression interceptor has done to the body of the message.

The Bus filters
Listing 4 contains a synopsis of the Bus filter used to compress the request. This article's code package contains the complete source.


Listing 4. A synopsis of the Bus filter used to compress the request
		
package services.demos.wsbus.client.filters;
public class CompressFilter implements Filter {

    private static QName name = new QName("http://gaf.filter.test", "compressType");

    public FilterAction filterRequest(WSIFRequest request, WSIFResponse response)
        throws WSBusException, FilterException {

        try {
            // get parameter
            WSIFMessage requestMessage = request.getIncomingMessage();
            sym = (String) requestMessage.getObjectPart("symbol");
            // "compress"
            if (sym.equals("XXX")) {
                System.out.println("Filter compressing with X type.");
                requestMessage.setObjectPart("symbol", "X");
                compType = "X";
            } else if (sym.equals("YYY")) {
                System.out.println("Filter compressing with Y type.");
                requestMessage.setObjectPart("symbol", "Y");
                compType = "Y";
            }
            // create element that indicates compression type
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            Document doc = factory.newDocumentBuilder().newDocument();
            Element token = doc.createElementNS(name.getNamespaceURI(), 
                                    name.getLocalPart());
            token.setAttribute("type", compType);
            // insert context that indicates compression type
            WSIFMessage contextMessage = request.getContextMessage();
            if (contextMessage == null) {
                contextMessage = new WSIFDefaultMessage();
                request.setContextMessage(contextMessage);
            }
            contextMessage.setObjectPart(name.toString(), token);

        } catch (Exception e) {
            e.printStackTrace();
            throw new WSBusException("Compressor: didn't work!");
        }

        return action;
    }
}

The CompressFilter first gets the symbol from the incoming request. It then compresses the symbol using a very simplistic algorithm. After compressing, the filter replaces the incoming symbol in the request with the compressed version. Next, the filter creates a context that indicates how the symbol was compressed and puts that context information into the overall request context. Notice that all of this work is done on a canonical form of the information, and would be the same regardless of the format and transport used to interact with the real service provider.

Listing 5 shows a synopsis of the Bus filter used to decompress the request.


Listing 5. A synopsis of the Bus filter used to decompress the request
		
package gaf.filter.sq;
public class DecompressFilter implements Filter {

    private static QName name = new QName("http://gaf.filter.test", "compressType");

    public FilterAction filterRequest(WSIFRequest request, WSIFResponse response)
        throws WSBusException, FilterException {

        try {
            // get parameter
            WSIFMessage requestMessage = request.getIncomingMessage();
            sym = (String) requestMessage.getObjectPart("symbol");
            // get the compression type
            WSIFMessage contextMessage = request.getContextMessage();
            // since do 'custom' name creation from qname, use following format
            Element token = 
                (Element) contextMessage.getObjectPart(name.getNamespaceURI() + 
                   ":" + name.getLocalPart());
            compType = token.getAttribute("type");
            // "decompress"
            WSIFMessage newReq = null;
            if (!compType.equals("none")) {
                newReq = new WSIFDefaultMessage();
                request.setIncomingMessage(newReq);
            }
            if (compType.equals("X")) {
                System.out.println("Filter decompressing with type X.");
                newReq.setObjectPart("symbol", "XXX");
            } else if (compType.equals("Y")) {
                System.out.println("Filter decompressing with type Y.");
                newReq.setObjectPart("symbol", "YYY");
            }

        } catch (Exception ex) {
            throw new WSBusException("Decompressor: can't work!");
        }
        
        return action;
    }
}

The DecompressFilter first gets the incoming compressed symbol. Next, the filter gets the context part that indicates the compression type and extracts that information from it. The name of the context in the off-ramp is derived from the QName of the context; the Bus uses the form <namespace>:<local name> to name contexts. The filter then decompresses the symbol according to the compression type and replaces the compressed symbol in the request with the decompressed symbol.

The Axis handlers
Listing 6 contains a synopsis of the Axis handler used to compress the request.


Listing 6. A synopsis of the Axis handler used to compress the request
		
package services.demos.wsbus.client.filters;
public class CompressHandler extends BasicHandler {

    private static QName name = new QName("http://gaf.filter.test", "compressType");

    public void invoke(MessageContext context) throws AxisFault {

        try {
            // get the parameter
            SOAPPart part =
                (org.apache.axis.SOAPPart) context.getCurrentMessage().getSOAPPart();
            SOAPEnvelope envelope = part.getAsSOAPEnvelope();
            RPCElement pel = (RPCElement) envelope.getFirstBody();
            RPCParam parm = pel.getParam("symbol");
            sym = (String) parm.getValue();
            // "compress"
            if (sym.equals("XXX")) {
                System.out.println("Handler compressing with X type.");
                parm.setValue("X");
                compType = "X";
            } else if (sym.equals("YYY")) {
                System.out.println("Handler compressing with Y type.");
                parm.setValue("Y");
                compType = "Y";
            }
            // create element that indicates compression type
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            Document doc = factory.newDocumentBuilder().newDocument();
            Element token = doc.createElementNS(name.getNamespaceURI(), 
                 name.getLocalPart());
            token.setAttribute("type", compType);
            // insert a header that indicates compression type
            envelope.addHeader(new SOAPHeaderElement(token));
            part.setSOAPEnvelope(envelope);

        } catch (Exception ex) {
            AxisFault fault = AxisFault.makeFault(ex);
            throw fault;
        }
    }
}

The CompressHandler first gets the stock symbol. It then compresses the symbol with the same algorithm used by the Bus filter. The handler puts the compressed version of the symbol into the request, replacing the original symbol. Next, the handler creates a header that indicates how the symbol was compressed and puts that header into the overall request context. Notice that all of the work is done on a SOAP-specific form of the information. That is the significant difference between the two types of compressing interceptor; the compression algorithm and the form of information used in the Bus context or SOAP header is the same.

Listing 7 contains a synopsis of the Axis handler used to decompress the request.


Listing 7. A synopsis of the Axis handler used to decompress the request
		
package gaf.filter.sq;
public class DecompressHandler extends BasicHandler {

    private static QName name = new QName("http://gaf.filter.test", "compressType");

    public void invoke(MessageContext context) throws AxisFault {
               
        try {
            // get the parameter
            SOAPPart part =
                (org.apache.axis.SOAPPart) context.getCurrentMessage().getSOAPPart();
            SOAPEnvelope envelope = part.getAsSOAPEnvelope();
            RPCElement pel = (RPCElement) envelope.getFirstBody();
            RPCParam parm = pel.getParam("symbol");
            sym = (String) parm.getValue();
            // get the compression type
            SOAPHeaderElement header =
                envelope.getHeaderByName(name.getNamespaceURI(), name.getLocalPart());
            Element token = header.getAsDOM();
            compType = token.getAttribute("type");

            // "decompress"
            if (compType.equals("X")) {
                System.out.println("Handler decompressing with type X.");
                parm.setValue("XXX");
            } else if (compType.equals("Y")) {
                System.out.println("Handler decompressing with type Y.");
                parm.setValue("YYY");
            }

        } catch (Exception ex) {
            AxisFault fault = AxisFault.makeFault(ex);
            throw fault;
        }
    }
}

The DecompressHandler first gets the incoming compressed symbol. Next, the handler gets the header that indicates the compression type and extracts the type from it. The handler then decompresses the symbol according to the compression type and replaces the compressed symbol with the decompressed symbol. As with the compression interceptors, the significant difference here is that the Bus filter works on canonical data while the Axis filter works on SOAP-specific data; the decompression algorithm and content of the Bus context or SOAP header is the same.


Getting ready to set up the examples

If you want to run the examples in this article, you must install and configure version 3.2.2 of the Web Services Toolkit, available from IBM alphaWorks (see Resources). The WSTK includes an Axis implementation and a Web Services Bus prototype implementation. The Bus architecture permits the Bus to work with multiple data formats and transport protocols for communication between clients and servers. The Bus prototype, however, implements only SOAP/HTTP using Axis.

The WSTK runs on a number of Windows and Linux Web application servers. The examples in this article assume that your WSTK is installed in the IBM WSDK on Windows; you may need to adjust path names, host names, command files, and other artifacts for your environment if you're using a different platform. (See Resources.)

Once you've installed the WSTK, you should start your Web application server and confirm that the Bus prototype works. Open a command window to WSTK_HOME/services/demos/wsbus/client, where WSTK_HOME refers to the directory where you installed the WSTK. Run one or more of the demos in that directory; SimpleClientFilter.bat is a good one, as it tests Axis and both the client and server sides of the Bus. If the demos run successfully, you are ready to proceed with additional setup.

Next, you need to copy a number of files from the code package that accompanies this article into their proper locations. This package mirrors the WSTK directory structure. The files in the package directory services/demos/wsbus/client, including all files in subdirectories, should be copied to WSTK_HOME/services/demos/wsbus/client. The files in the package directory services/demos/wsbus/webapp should be copied to the corresponding directories in the WSDK WAR directory in your Web application server's installed applications directory; for the WSDK, this directory is WSDK_HOME/WebSphere/installedApps/wstk.ear/wstk.war, where WSDK_HOME is the directory where you installed the WSDK.

Of course, there is more to running the examples than just copying files. You must deploy the stock quote service and the interceptor on both the client and the server side. The files copied above include batch files and deployment descriptors needed to deploy the necessary components, make stock quote requests, and then undeploy the components.


Running the examples: A homogeneous environment

I'll start the examples simply, by running the Bus client against the Bus server, and the Axis client against the Axis server. I'll get a little fancier in subsequent sections, but let's begin with the basics.

Running the Bus client and server

You can run the Bus client against the Bus server by executing the batch file WSTK_HOME/services/demos/wsbus/client/RunBusSQ.bat. This batch file will:

  1. Deploy a Bus service and a decompression filter for the Bus off-ramp.
  2. Deploy a Bus service and a compression filter, and run BusSQClient, for the Bus on-ramp.
  3. Undeploy the Bus service and decompression filter for the Bus off-ramp.

deployBusSQ.xml, the deployment descriptor used in step 1 above, is shown in Listing 8.


Listing 8. deployBusSQ.xml
		
<deploy force="true">
  <filters>
    <filter name="decompressor" started="true" 
        className="gaf.filter.sq.DecompressFilter"/>
  </filters>
  <busServices>
    <busService serviceName="SQBus" ...>
      <channels>
        <channelReference channel="axis"/>
      </channels>
      <targetServices>
        <targetService className="gaf.filter.sq.SQ" serviceName="SQService" .../>
      </targetServices>
      <preFilters>
        <filterReference filter="decompressor" />
      </preFilters>
    </busService>
  </busServices>  
</deploy>

This deployment descriptor causes the Bus off-ramp to deploy the class gaf.filter.sq.DecompressFilter as a Bus filter under the name decompressor, and to deploy the JavaBean gaf.filter.sq.SQ as a bus service under the name SQBus. Furthermore, the off-ramp lists decompressor as a prefilter for SQBus. This causes the Bus off-ramp to run the decompression filter before passing the request to the JavaBean.

Step 2 of the list above uses the Bus on-ramp's dynamic configuration mechanism to set up the complete configuration for running the client. There is no permanent effect on the default on-ramp configuration used by the demonstrations shipped with the WSTK. Listing 9 shows the configuration established (by wsbusClientBusSQ.cfg) to run the client.


Listing 9. Configuration established to run the client
		
<busInfo started="true" >
  <filters >
    <filter name="compressor" 
         className="services.demos.wsbus.client.filters.CompressFilter" ... />
  </filters>
  <busServices >
    <busService serviceName="SQBus" ... >
      <preFilters >
        <filterReference  filter="compressor" >
        </filterReference>
      </preFilters>
    </busService>
  </busServices>
</busInfo>

This on-ramp configuration deploys the class services.demos.wsbus.client.filters.CompressFilter as a Bus filter under the name compressor, and lists compressor as a prefilter for the Bus service known as SQBus. This causes the Bus on-ramp to run the compression filter before sending the request to the WSIF provider to be serialized and sent to the actual service provider. Note that, for the Bus, the service name comes from the name attribute of the service element of the WSDL describing the service. If you peek inside RunBusSQ.bat, you will find that the URL for the WSDL describing the stock quote service deployed in the Bus is http://<hostname>:<port>/wstk/wsbus/ServiceDefinition?name=SQBus, with the hostname and port set appropriately for your Web application server. The URL reflects the Bus off-ramp's dynamic WSDL-generation capability, which produces SQBus as the name attribute of the service element.

When you execute RunBusSQ.bat (with no parameters), you should see results in your command window similar to those in Listing 10. First, you should see successful off-ramp deployment (step 1). Then you should see successful retrieval of the WSDL document, and, most importantly, an indication of successful round trip with compression on the client and decompression on the server (step 2). Finally, you should see successful off-ramp undeployment (step 3).


Listing 10. Running the Bus client and server: Results
		
C:\wstk-3.2.2\services\demos\wsbus\client>RunBusSQ.bat
 ===> Deploy the service and filter in the Bus off-ramp engine
Results: OK

 ===> Deploy service and filter in Bus on-ramp engine

 ===> Request quotes
Retrieving document at 'http://<hostname>:<port>/wstk/wsbus/ServiceDefinition?name=SQBus'.
Retrieving import document at 'http://<hostname>:<port>/wstk/wsbus/ServiceInterface?name=SQBus
Using WSIFServiceFactory
BusServiceFactory: no class name for discovery or selection. Using default.

Filter compressing with X type.
The quote: 55.25
Filter compressing with Y type.
The quote: 125.35
The quote: 0.0

 ===> Undeploy the service and filter in the Bus off-ramp
Results: OK

If you care to do so, you can confirm execution of the off-ramp filter by examining the console or log as appropriate. You should see a log entry that looks something like Listing 11.


Listing 11. Log entries for running the Bus client and server
		
[<date & time >] 6fa289b6 SystemOut     U Filter decompressing with type X.
[<date & time >] 6fa289b6 SystemOut     U Filter decompressing with type Y.

Running the Axis client and server

You can run the Axis client against the Axis server by executing the batch file WSTK_HOME/services/demos/wsbus/client/RunAxisSQ.bat. This batch file will:

  1. Deploy a service and a decompression handler for the Axis server.
  2. Deploy a service and a compression handler for the Axis client.
  3. Run AxisSQClient.
  4. Undeploy the service and compression handler for the Axis client.
  5. Undeploy the service and decompression handler for the Axis server.

The deployment descriptor used in step 1 (deployAxisSQ.wsdd) is shown in Listing 12.


Listing 12. deployAxis.wsdd
		
<deployment xmlns="http://xml.apache.org/axis/wsdd/" 
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <handler name="decompressor" type="java:gaf.filter.sq.DecompressHandler">
  </handler>
  <service name="SQAxis" provider="java:RPC">
    <parameter name="className" value="gaf.filter.sq.SQ"/>
    <parameter name="allowedMethods" value="getQuote"/>
    <requestFlow>
      <handler type="decompressor"/>
    </requestFlow>
  </service>
</deployment>

This deployment descriptor causes the Axis server engine to deploy the class gaf.filter.sq.DecompressHandler as a handler under the name decompressor and to deploy the JavaBean gaf.filter.sq.SQ as a service under the name SQAxis. Furthermore, it lists decompressor in the request flow for SQAxis. This causes the Axis server engine to run the decompression filter before passing the request to the JavaBean.

Step 2 of the list above uses the deployment descriptor deployAxisClient.wsdd, shown in Listing 13.


Listing 13. deployAxisClient.wsdd
		
<deployment xmlns="http://xml.apache.org/axis/wsdd/" 
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <handler name="compressor" 
      type="java:services.demos.wsbus.client.filters.CompressHandler">
  </handler>
  <service name="http://localhost/wstk/services/SQAxis/wstk/services/SQAxis" 
       provider="java:RPC">
    <requestFlow>
      <handler type="compressor"/>
    </requestFlow>
  </service>
</deployment>

This deployment descriptor deploys the class services.demos.wsbus.client.filters.CompressHandler as a handler under the name compressor, and lists compressor in the request flow for the service known as http://localhost/wstk/services/SQAxis/wstk/services/SQAxis. This causes the Axis client engine to run the compression filter before sending the request to the actual service provider. Axis derives the service name differently than the Bus does; the WSDL describing the service contains a SOAP binding element; that element contains an input element, and Axis derives the service name from the namespace attribute of that input element. If you peek inside RunAxisSQ.bat, you will find that the URL for the WSDL describing the stock quote service deployed in Axis is http://<hostname>:<port>/wstk/service/SQAxis?wsdl, with the hostname and port set appropriately for your Web application server. The URL reflects Axis's dynamic WSDL-generation capability. The name used above reflects a Web application server using the default port (80); if you use a different port, you will have to modify the deployment descriptor (and the corresponding deployment descriptor used to undeploy).

When you execute RunAxisSQ.bat (with no parameters), you should see results in your command window very similar to Listing 14. You should see successful Axis server deployment (step 1) and client deployment (step 2). Then you will see successful retrieval of the WSDL document, and, most importantly, indication of successful round trip with compression on the client and decompression on the server (step 3). Finally, you will see successful undeployment (steps 4 and 5).


Listing 14. Running the Axis client and server: Results
		
C:\wstk-3.2.2\services\demos\wsbus\client>RunAxisSQ.bat
 ===> Deploy the service and handler in the Axis server engine
- Processing file deployment/deployAxisSQ.wsdd
<Admin>Done processing</Admin>

 ===> Deploy the service and handler in the Axis client engine
 
 ===> Request quotes
Retrieving document at 'http://<hostname>:<port>/wstk/services/SQAxis?wsdl'.

Handler compressing with X type.
The quote: 55.25
Handler compressing with Y type.
The quote: 125.35
The quote: 0.0

 ===> Undeploy the service and handler from Axis client engine

 ===> Undeploy the service and handler from the Axis server engine
- Processing file deployment/undeployAxisSQ.wsdd
<Admin>Done processing</Admin>

If you care to do so, you can confirm execution of the Axis handler by examining the console or log as appropriate. You should see a log entry similar to Listing 15.


Listing 15. Log entries for running the Axis client and server
		
[<date & time >] 6fce09b6 SystemOut     U Handler decompressing with type X.
[<date & time >] 6fce09b6 SystemOut     U Handler decompressing with type Y.


Advanced examples: Running a heterogenous environment

Now I'll make things really interesting and demonstrate the interoperability inherent in Web services. In the next two sections, you'll first use a Bus client to interact with a service deployed in Axis, and then an Axis client to interact with a service deployed in the Bus; these examples require no code changes. This is only possible because the Bus prototype uses Axis as its only transport mechanism. In theory, the Bus could use a different format and protocol (for example, RMI/IIOP) and the Axis handlers would no longer be applicable, while the Bus filters would be.

Running the Bus client and Axis server

You can run the Bus client against the Axis server by executing the batch file WSTK_HOME/services/demos/wsbus/client/RunBusSQX.bat. This batch file will:

  1. Deploy a service and a decompression handler for the Axis server.
  2. Deploy a bus service and a compression filter, and run BusSQClient, for the Bus on-ramp.
  3. Undeploy the bus service and decompression handler for the Axis server.

The deployment descriptor used in step 1 (deployAxisSQ.wsdd) is the same one used to deploy the Axis server components in the Axis-client-to-Axis-server example; you can examine its code in detail in Listing 12.

Step 2 uses the Bus on-ramp's dynamic configuration mechanism to set up the complete configuration for running the client. Listing 16 shows the configuration established (by wsbusClientBusSQX.cfg) to run the client.


Listing 16. Configuration established to run the client
		
<busInfo started="true" >
  <filters >
    <filter name="compressor" 
         className="services.demos.wsbus.client.filters.CompressFilter" ... />
  </filters>
  <busServices >
    <busService serviceName="SQService" ... >
      <preFilters >
        <filterReference  filter="compressor" >
        </filterReference>
      </preFilters>
    </busService>
  </busServices>
</busInfo>

This on-ramp configuration differs from the configuration in the Bus-client-to-Bus-server example only in the name of the bus service, which must be SQService instead of SQBus. If you peek inside RunBusSQX.bat, you will find that the URL for the WSDL describing the stock quote service deployed in the Bus on-ramp is http://<hostname>:<port>/wstk/services/SQAxis?wsdl. Axis generates the name SQService for the name attribute of the service element used by the Bus to identify services.

When you execute RunBusSQX.bat (with no parameters), you should see results in your command window similar to those in Listing 17. You should see successful Axis server deployment (step 1). Then you should see successful retrieval of the WSDL document, and, most importantly, indication of successful round trip with compression on the Bus client and decompression on the Axis server (step 2). Finally, you should see successful Axis server undeployment (step 3).


Listing 17. Running the Bus client and Axis server: Results
		
C:\wstk-3.2.2\services\demos\wsbus\client>RunBusSQX.bat
 ===> Deploy the service and handler in the Axis server engine
- Processing file deployment/deployAxisSQ.wsdd
<Admin>Done processing</Admin>

 ===> Deploy service and filter in Bus on-ramp engine

 ===> Request quotes
Retrieving document at 'http://<hostname>:<port>/wstk/services/SQAxis?wsdl'.
using WSIFServiceFactory
BusServiceFactory: no class name for discovery or selection. Using default.

Filter compressing with X type.
The quote: 55.25
Filter compressing with Y type.
The quote: 125.35
The quote: 0.0

 ===> Undeploy the service and handler from the Axis server engine
- Processing file deployment/undeployAxisSQ.wsdd
<Admin>Done processing</Admin>

If you care to do so, you can confirm execution of the handler in the Axis server by examining the console or log as appropriate. You should see a log entry similar to Listing 18.


Listing 18. Log entries for running the Bus client and Axis server
		
[<date & time >] 6fa289b6 SystemOut     U Handler decompressing with type X.
[<date & time >] 6fa289b6 SystemOut     U Handler decompressing with type Y.

Running the Axis client and Bus server

You can run the Axis client against the Bus server by executing the batch file WSTK_HOME/services/demos/wsbus/client/RunAxisSQX.bat. This batch file will:

  1. Deploy a bus service and a decompression filter for the Bus off-ramp.
  2. Deploy a service and a compression handler for the Axis client.
  3. Run AxisSQClient.
  4. Undeploy the service and compression handler for the Axis client.
  5. Undeploy the bus service and decompression filter for the Bus off-ramp.

The deployment descriptor used in step 1 (deployBusSQ.xml) is the same one used to deploy the Bus on-ramp components in the Bus-client-to-Bus-server example; you can examine it in detail in Listing 8.

Step 2 uses deployAxisClientX.wsdd, the deployment descriptor shown in Listing 19.


Listing 19. deployAxisClientX.wsdd
		
<deployment xmlns="http://xml.apache.org/axis/wsdd/" 
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <handler name="compressor" 
      type="java:services.demos.wsbus.client.filters.CompressHandler">
  </handler>
  <service name=""http://mybus/#SQBus" provider="java:RPC">
    <requestFlow>
      <handler type="compressor"/>
    </requestFlow>
  </service>
</deployment>

This deployment descriptor differs from its equivalent in the Axis-client-to-Axis-server example only in that it uses http://mybus/#SQBus as the service name instead of http://localhost/wstk/services/SQAxis/wstk/services/SQAxis. Note that, for Axis, the service name comes from the namespace attribute of the input element in the SOAP binding element of the WSDL describing the service. If you peek inside RunAxisSQ.bat, you will find that the URL for the WSDL describing the stock quote service deployed in Axis is http://<hostname>:<port>/wstk/wsbus/ServiceDefinition?name=SQBus. The Bus generates http://mybus/#SQBus for the SOAP binding element because the namespaceURI attribute of the Bus prototype configuration is http://mybus/ and the Bus appends a # plus the name of the service.

When you execute RunAxisSQX.bat (with no parameters), you should see results in your command window that appear similar to those in Listing 20. You should first see successful Bus on-ramp deployment (step 1) and Axis client deployment (step 2). Then you should see successful retrieval of the WSDL document, and, most importantly, indication of successful round trip with compression on the Axis client and decompression on the Bus server (step 3). Finally, you should see successful undeployment (steps 4 and 5).


Listing 20. Running the Axis client and Bus server: Results
		
C:\wstk-3.2.2\services\demos\wsbus\client>RunAxisSQX.bat
 ===> Deploy the service and filter in the Bus off-ramp engine
Results: OK

 ===> Deploy the service and handler in the Axis client engine

 ===> Request quotes
Retrieving document at 'http://<hostname>:<port>/wstk/wsbus/ServiceDefinition?name=SQBus'.
Retrieving import document at 'http://<hostname>:<port>/wstk/wsbus/ServiceInterface?name=SQBus

Handler compressing with X type.
The quote: 55.25
Handler compressing with Y type.
The quote: 125.35
The quote: 0.0
 
 ===> Undeploy the service and handler from Axis client engine
 ===> Undeploy the service and filter in the Bus off-ramp
Results: OK

If you care to do so, you can confirm execution of the Bus off-ramp filter by examining the console or log as appropriate. You should see a log entry that looks similar to Listing 21.


Listing 21. Log entries for running the Axis client and Bus server
		
[<date & time >] 6fbe49b6 SystemOut     U Filter decompressing with type X.
[<date & time >] 6fbe49b6 SystemOut     U Filter decompressing with type Y.


Conclusion

In this article, you learned how to use Web Services Bus filters on both the Bus on-ramp (the client) and the Bus off-ramp (the server). Furthermore, you saw how to establish context between the client-side and server-side filters. In addition, you compared Bus filter use to Axis handler use. Finally, you saw that it is possible to mix and match Bus clients and Axis servers, and vice versa, under certain conditions.

This series has demonstrated several features of the Web Services Bus. These features combine to make the Bus a superior framework for heterogeneous, dynamic e-business conducted with Web services. I hope that you'll now be ready to start exploring the Web Services Bus on your own, and see how it can be useful to you in your own projects.



Download

NameSizeDownload method
getbusresources2.zip HTTP

Information about download methods


Resources

  • Read the first installment of this series, Explore the Web Services Bus, Part 1 (developerWorks, November 2002).

  • Download the code package that accompanies this article, which includes the source, WSDL files, batch files, and other files necessary for the examples. The code is written to run in the WSTK environment and is structured in the same manner as other WSTK demos.

  • Version 3.3 of the Web Services Toolkit demonstrates a number of Web services technologies, including the Web Services Bus.

  • The IBM WebSphere SDK for Web Services (WSDK) offers an environment for Web service providers, and supports installation of the WSTK.

  • Axis offers an environment for Web services requestors and providers; it is available in the WSTK.

About the author

Greg Flurry

Greg Flurry is a member of IBM's Software Group Emerging Technologies, which investigates leading-edge technologies for a wide range of e-business environments. You can reach Greg at flurry@us.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=11743
ArticleTitle=Explore the Web Services Bus, Part 2: Comparing Bus filters and Axis handlers
publish-date=01012003
author1-email=flurry@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers