Web Services Invocation Framework – introduction, design, motivation and architecture

 

Introduction

The Web Service Invocation Framework (WSIF) is a simple Java API for invoking Web services, no matter how or where the services are provided. It has all the features identified in the discussion above:

 

Background - recap on WSDL

The Web Services Description Language (http://www.w3.org/TR/WSDL) is inherently extensible – from the beginning the designers built in a separation between the interface and implementation of services in WSDL.

 

In WSDL a service is defined in three distinct parts:

  1. The PortType. The PortType defines the abstract interface offered by the service. A PortType defines a set of Operations. Each operation can be In-Out (request-response), In-Only, Out-Only and Out-In (Solicit-Response). Each operation defines the input and/or output Messages. A message is defined as a set of Parts and each part has a schema-defined type.
  2. The Binding. A binding defines how to map between the abstract PortType and a real service format and protocol. For example, the SOAP binding defines the encoding style, the SOAPAction header, the namespace of the body (the targetURI), and so forth.
  3. The Port. This defines the actual location (endpoint) of the available service – for example, the HTTP URL on which a SOAP service is available.

 

In WSDL today, each Port has one and only one binding, and each binding has a single PortType. Conversely (and more importantly), each Service (PortType) can have multiple Ports, each which represents an alternative location and binding for accessing that service.

 

We set out to mirror WSDL when we designed WSIF – because we wanted an API based on WSDL rather than directly on SOAP. WSIF is effectively a framework for plugging in support for transports and formats. These are called Providers in WSIF, and the most obvious provider is for SOAP.

 

Adding extensibility elements to WSDL allows the creation of descriptions of other service implementations than SOAP. Typically, WebServices are implemented using existing application components – such as Java classes, Enterprise JavaBeans, or COM objects. These components are also sometimes wrappers onto legacy systems, such as mainframe transaction systems. By extending WSDL to describe the existing component models, we can capture the dependence relationship between the exposed SOAP-available service and the underlying component, and the fact that the two available implementations are actually the same business service. In fact, adding extensibility elements for existing components does something more – it adds the description capability of the services oriented architecture to the existing component model.

 

Motivation

The motivation for WSIF is that we wanted to see the “Services Oriented Architecture” as wider than just SOAP. On the one hand there are a number of different protocols, transports and distributed computing technologies that offer more than SOAP does today – especially in terms of management, transactions, security and other Quality of Service (QoS) features. While SOAP is catching up quickly, the main issue is actually one of investment. Many companies have an investment in technologies such as CORBA that they wish to use and keep. On the other hand, Web Services and SOAP have a unique advantage – an infrastructure for description and discovery. Anyone can download a WSDL document they have found either in a UDDI directory or in an inspection document, and use a commonly available tool to generate code that uses that service, whether it is on a local network or across the Internet. The common availability of this description language is also fuelling the growth of other tools – for example the development of languages for composing and choreographing services together (for example XLANG and WSFL).

 

We really wanted to make the extensibility and structure of WSDL real. WSDL allows us to describe existing systems using extensibility elements. For example, we have written WSDL extensions to describe transactions in CICS and IMS using connectors, calls to remote stateless session Enterprise JavaBeans, as well as SOAP and non-SOAP messages over JMS-based messaging systems. However, while describing things is useful, it isn’t  as useful as executing them!

 

WSDL today is not just a description layer – it has a real implementation in tools that can use WSDL descriptions to generate stubs that can access the services. So if we add descriptions of non-SOAP systems, we are in danger of losing that benefit. WSIF addresses that. Effectively it is a pluggable framework, which allows providers to be plugged in. A provider is code that supports a WSDL extension and allows invocation of the service through that particular implementation. This means that the client code is independent of the implementation, and only dependent on the PortType of the service. WSIF also allows late binding, where a new provider and description are made available at runtime, and the existing client can then utilize the new implementation. Finally WSIF allows the client to delegate the choice of port to the infrastructure and runtime, which can allow the implementation to be chosen on the basis of quality of service characteristics or business policy.

 

And the structure of WSDL allows there to be multiple implementations for a Web Service, multiple Ports that share the same PortType. In other words, WSDL allows the same interface to have bindings to SOAP and IIOP. We wanted our API to allow the same client code to access any available binding – if the code was written to the PortType then it would be a deployment or configuration setting (or a code choice) which port and binding was used.

Requirements

  1. Support any valid WSDL extensions.
  2. Support dynamic invocation of WSDL-described services
  3. Support an API based on WSDL PortTypes.
  4. Allow late binding to different formats and transports
  5. Support both compiled and dynamic approaches
  6. Support minimum code deployment scenarios (n providers, no per-service code)
  7. Support different in-memory representations of service request data.

Usage

There are two ways of using WSIF. WSIF offers both a stub-based model and a dynamic invocation interface (DII).

 

Stub model

The stub-based model allows users to use the normal programming model to call business methods on Services. There is a standardised Java mapping from WSDL defined interfaces into Java defined interfaces – in the JAX-RPC standard. There was some effort to integrate the WSIF model with JAX-RPC through the JCP/JSR process, but it was felt that WSIF was too experimental to include at that point. What we have done is a loose-integration. JAX-RPC defines the Service Definition Interface – the business interface of the stubs. WSIF also defines an interface to use the same SDI as JAX-RPC. So, although WSIF and JAX-RPC do not share interfaces, they do share tooling (e.g. Axis WSDL2Java).

 

Figure 1 - example of using the stub model with WSIF

Text Box: 1	WSIFService sq = ServiceFactory.newInstance().
	getService(“http://my.com/svcs/stockquote.wsdl”);
2	MyService mySvcStub = sq.getStub("soap", MyService.class);
3	mySvcStub.myMethod();

 

 


Dynamic Invocation Interface

The DII is modelled very closely on WSDL. In WSDL, an operation has an input message and optionally an output or fault messages.

In WSIF, we navigate a similar hierarchy. There is a close correspondence. In fact our first iteration was a one-for-one correspondence, but we refactored to be more logical and (slightly) simpler.

The correspondence is shown in Figure 2 - Correspondence of WSDL and WSIF entities.

 

Figure 2 - Correspondence of WSDL and WSIF entities

WSDL

WSIF

(WSIL/UDDI)

WSIFServiceFactory or JNDI

Service

WSIFService

Port

WSIFPort

Binding

 

Operation

WSIFOperation

Message

WSIFMessage

Part

 

 

To use the DII, you need to:

·        select a port

·        create an operation

·        create and populate the in message

·        execute the operation

·        read the response data from the out message

 

A simple example is shown below in Figure 3 - Example of using the dynamic invocation interface.

Figure 3 - Example of using the dynamic invocation interface

Text Box: 1	WSIFService sq = ServiceFactory.newInstance().
	getService(“http://my.com/svcs/stockquote.wsdl”);
2	WSIFPort defPort = sq.getPort();
3	WSIFOperation getQ = defPort.createOperation(“getQuote”);
4	WSIFMessage inMessage = getQ.createInputMessage();
5	inMessage.setStringPart(“symbol”, “IBM”);
6	…
7	getQ.executeRequestResponse(inMessage, outMsg, fltMsg);
8	outMessage.getFloatPart(“value”);
 

 


Architecture

The architecture of WSIF is based on a number of factories. The reason for using factories is that we wanted to hide whether the objects used were “static” or “dynamic”. In the static case, the objects are generated to satisfy that particular port, message or operation. This allows a very fast implementation to be built. In the dynamic case, the objects use the WSDL description at runtime to handle the particular port, operation or message handling. Currently WSIF mainly uses dynamic objects, as this is how we implemented them initially. We actually envisage several different levels of dynamism:

 

 

Experimental Stuff

Currently there are a number of areas we are involved in exploring with WSIF.

 

Asynchronous request response.

We currently have an async request response model, where the response is handled in a different thread of execution from the request.

 

Basically, the caller defines a callback object (handler), which is called when the response is received.

 

The request message is sent, and the handler object is passed to the WSIFOperation. WSIF provides a correlation service to store the handlers against a given correlation id.  The WSIFOperation calls the WSIF correlation service, which stores itself (and the handler) against the correlation id of the request. This all takes place within the current transaction. If the user has specified a transactional queue, then the work is done within the current WebSphere transaction.

 

The WSIFOperation and WSIFResponseHandler objects are serializable so that any state the handler object has can be persisted in case of system failure between the request and response. The correlation service is pluggable so that a transactional, persistent correlation service can be provided for high-availability.

 

When the response comes at some later point, a listener thread picks it up and passes it to the stored WSIFOperation. The operation contains the logic to demarshall the response into a WSIFMessage, and then it executes the handler method executeAsyncResponse with the outMessage. The listener thread is running on a different transaction from the original request, and so the response is a separate transaction from the request.

 

 

Example

Text Box: A handler is designed to understand the response message and use the response values. The handler implements the WSIFResponseHandler interface.
 
1	public class QuoteHandler implements WSIFResponseHandler  {
2	       
3	protected String symbol = null; // local storage of the symbol we wanted quoted
4	public void setSymbol(String value) { symbol = value };   
5	public void executeAsyncResponse(WSIFMessage out, WSIFMessage fault) {
6	         // this simplified example assumes no failures and that the symbol has been set correctly
7		float quoteValue = out.getPart(“quote”);
8		updateQuoteDB(symbol, quoteValue);
9	}

The service invocation looks like this:

1	String symbol = “IBM”;
2	QuoteHandler quoteHandler = new QuoteHandler();
3	quoteHandler.setSymbol(symbol); // the handler needs to know the symbol when it gets executed later.
4	
5	WSIFMessage inMessage;
6	WSIFOperation quoteOperation;
7	…
8	inMessage.setXXXPart(…) // set up inMessage for invocation
9	quoteOperation.executeAsyncRequestResponse(inMessage, quoteHandler);

 

 


Context

We also wanted to support the idea of setting and using context. There has been some discussion in the WS-Description working group of the W3C on this topic, but no actual syntax or semantics yet.

For example, a SOAP/HTTP port may require an HTTP username and password. This information is specific to the invocation, but not usually a parameter of the service. In general, context is defined as a set of name-value pairs. However, as WebServices tend to define the types of data using XML Schema types, we choose to represent the name-value pairs of the context using the same representation that “WSIFMessages” use – namely a set of named Parts, each of which equates to an instance of an XML Schema type. This is slightly more overhead than using a “properties” concept, but more in keeping with the rest of WSDL and WSIF.

 

The methods setContext and getContext on a WSIFPort and WSIFOperation allow the application programmer or stub to pass context information to the binding. The Port implementation may use this context – for example to update a SOAP header. There is no definition of how a Port may utilize the context.

 

Ideas/Futures

There are a number of areas we are working on:

  1. Refactoring to separate transport and formatting. We have defined a WSIFFormatter class to allow access to the formatting of data from a message to a native format.
  2. Abstract tree representation of the data. Currently we mainly use compiled classes from the schema to carry the service parameters in the WSIFMessage. However, in the WebServices Gateway (a user of WSIF – see  http://www7b.software.ibm.com/wsdd/downloads/wsgw/wsgw.html), we use an abstract tree notation called “JROM” which closely maps to XML Schema. This approach is still in research.
  3. More and better providers
  4. WSIF in C/C++

 

Credits

 

The main contributors to the WSIF release are (in alphabetical order).

 

Aleksander A. Slominski

Anthony Elder

Dieter Koenig

Gerhard Pfau

Jeremy Hughes

Mark Whitlock

Matthew J. Duftler

Michael Beisiegel

Nirmal Mukhi

Owen Burroughs

Paul Fremantle

Piotr Przybylski

Sanjiva Weerawarana