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 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

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.
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.
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 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:
- Deploy a Bus service and a decompression filter for the Bus off-ramp.
- Deploy a Bus service
and a compression filter, and run
BusSQClient, for the Bus on-ramp. - 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:
- Deploy a service and a decompression handler for the Axis server.
- Deploy a service and a compression handler for the Axis client.
- Run
AxisSQClient. - Undeploy the service and compression handler for the Axis client.
- 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:
- Deploy a service and a decompression handler for the Axis server.
- Deploy a bus service
and a compression filter, and run
BusSQClient, for the Bus on-ramp. - 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:
- Deploy a bus service and a decompression filter for the Bus off-ramp.
- Deploy a service and a compression handler for the Axis client.
- Run
AxisSQClient. - Undeploy the service and compression handler for the Axis client.
- 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. |
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.
| Name | Size | Download method |
|---|---|---|
| getbusresources2.zip | HTTP |
Information about download methods
- 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.

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.




