by Gautam Shah

Bridging islands of enterprise software

news
Sep 26, 200516 mins

WSIF offers enterprise Java systems a bridge to any component or service, regardless of implementation or location

Every enterprise software system must tie together numerous existing software systems and codebases. Such systems might need to access existing Enterprise JavaBeans (EJB) components, legacy code in Java, or Web services over SOAP. Such dependencies make enterprise software systems brittle. They tend to break when external systems change location or when implementation technologies change. Basing all your components and solutions on SOAP is not always the answer because a SOAP-based implementation has penalties. Web Services Invocation Framework (WSIF) is the answer. It provides your Java codebase total freedom for such platform and location vagaries.

Simply put, WSIF is a client-side invocation framework. It is a simple Java codebase with an API that sits between your client code and the services your code must access. It provides a layer of abstraction to decouple client code from access to a service, as well as its location and underlying implementation. Thereby, your Java code can access both SOAP and non-SOAP-based services in a transport-, language-, and platform-independent fashion. As will be demonstrated in examples below, with WSIF, you will find that your code does not need to change or be recompiled when the service implementation changes from Java classes to EJB, or to SOAP-based services, or to even .Net and COM-based (Component Object Model) services.

WSIF also provides location independence. A service’s actual location is externalized in a configuration file. This allows your client code’s access location to change with no code modifications or recompilation.

Just to give you an idea about WSIF’s power, the following Java StockQuote client code will not change when the actual service provider moves from Java to EJB or to SOAP; the required interface remains.

                        ...   
// Create a service factory.
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// Parse WSDL.
WSIFService service =
factory.getService('c://stockquoteservice.wsdl',
                  null,
                  null,
                  "http://mycompany.stockquote/",
                  "net.xmethods.services.stockquote.StockQuotePortType");
// Create the service stub, StockQuote.class is class generated by WSDL2Java for StockQuote service WSIF configuration file.
StockQuote service = (StockQuote) service.getStub(StockQuote.class);
// Do the invocations.
string symbol = "IBM";
string result = service.getQuote(symbol);
system.out.println("Price for " + symbol + " is " + result);
...
                   

Benefits of WSIF

An enterprise application usually consists of numerous pieces of software services developed over many years in assorted languages on various platforms with different protocols—pieces that must work together to provide business and operational functionality. These pieces constantly change: A service previously available as Java class may change to a Java Message Service-based implementation. Or a service that used a particular version of a SOAP implementation may be upgraded, leaving your code with a deprecated API. Or a service available as an EJB component internally within a company is outsourced to an external vendor and is now available as a SOAP-based service.

The other volatile aspect of these services is location. A service that may have been available locally may suddenly be moved to servers on the other side of the globe. As a practice, experienced designers have learned to externalize the location of such services; however, enforcing such rigors in a large and complex enterprise solution developed and maintained by a global fleet of designers and developers proves difficult.

Typically, SOAP is touted as panacea for such pain points. SOAP has been a unifying protocol, but its implementation, from a practical perspective, has limitations. First, not all services may be enabled as SOAP-based services. There could be significant cost implications in enabling all the services developed over the years as SOAP-based services. Second, using SOAP has performance implications. Benchmarking comparisons indicate that SOAP calls using Apache Axis have several hundred times more latency than Java RMI (remote method invocation) calls (see “Latency Performance of SOAP Implementations” (IEEE Cluster Computing and the Grid, 2002)). Considering the performance impact, it would be unreasonable to expect Java clients to use SOAP for accessing EJB components to gain platform and location independence.

WSIF, modeled after WSDL (Web Services Description Language), is more suitable for alleviating such problems. For a given service, WSIF uses a WSDL-based XML file so that custom wrappers for new or existing Java and EJB objects are not needed. WSDL provides definitions of services: it defines the interface consisting of functions, parameters, return values, and exceptions and the binding consisting of the service’s implementation specification and location. WSDL was designed with extensibility in mind. In a typical SOAP-based Web service, the binding is almost always soap:binding. WSDL provides plug-ins to other bindings such as Java and EJB. WSIF exploits this specific WSDL extensibility. I describe more on this extensibility in later sections.

Using WSIF

There are two invocation models for using the WSIF API: stub invocation or dynamic invocation. The stub model relies on stubs at the client side; service functions are invoked on these stubs. This approach offers a more natural way of programming and has the benefits of compiler-checked code. The dynamic model programmatically constructs service calls. This model suits those applications that want a more abstract view of a service.

To better understand these invocation models, let’s look at an example that provides a stock price. The service StockQuote has a single call, getQuote(), that expects a string. Let’s first look at a stub invocation:

                        ...
// Create a service factory.
1.  WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// Parse WSIF WSDL file that contains exact StockQuote service and StockQuote port-type.
2. WSIFService service =
3. factory.getService('c://stockquoteservice.wsdl',
4.                  "http://mycompany.stockquote/",
5.                  "net.xmethods.services.stockquote.StockQuoteService",
6.                  "http://mycompany.stockquote/",
7.                  "net.xmethods.services.stockquote.StockQuotePortType");
// Create the service stub, StockQuote.class is a class generated by WSDL2Java for 
// StockQuote service WSIF configuration file.
8. StockQuote stub = (StockQuote) service.getStub(StockQuote.class);
// Call the function to get the stock price.
9. string symbol = "IBM";
10. float result = stub.getQuote(symbol);
11. system.out.println("Price for " + symbol + " is " + result);
...
                   

On Line 1, an instance of a WSIF factory is created, which initializes the WSIF framework if it has not already initialized.

On Lines 2 through 7, the WSIF factory retrieves instances of specific services. The WSIF factory is supplied the WSIF-WSDL file location, service namespace, service name, port-type namespace, and port-type name. The service namespace and service name can be left as null if the WSDL file contains only one service definition and location. The WSIF parses the WSIF-WSDL file to create instances of services requested.

On Line 8, a stub instance is retrieved. Calls are made against this stub. Stub classes can be created using the WSDL2Java tool, an industry-standard tool for generating Java proxies and skeletons for services with WSDL descriptions. WSIF uses client-side proxies generated using the following command: %java org.apache.axis.wsdl.WSDL2Java (WSIF-WSDL-file-URL).

On Line 10, an actual call is made against the stub. Here, the WSIF framework internally maps to the appropriate port-type implementation specified in the WSIF-WSDL file and places a call to the endpoint. The value returns to your client code.

Now let’s look at a dynamic invocation:

                        ...
// Create a service factory.
1. WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// Parse WSIF WSDL file that contains exact StockQuote service and StockQuote 
// port-type.
2. WSIFService service =
3. factory.getService('c://stockquoteservice.wsdl',
4.                  "http://mycompany.stockquote/",
5.                  "net.xmethods.services.stockquote.StockQuoteService",
6.                  "http://mycompany.stockquote/",
7.                  "net.xmethods.services.stockquote.StockQuotePortType");
// Get the port.
8. WSIFPort port = service.getPort();
// Create the operation.
9. WSIFOperation operation = port.createOperation("getQuote");
                    
// Create the input, output, and fault messages for the operation.
10. WSIFMessage input = operation.createInputMessage();
11. WSIFMessage output = operation.createOutputMessage();
12. WSIFMessage fault = operation. createFaultMessage();
// Populate the input message.
13. String symbol = "UIS"
14. input.setObjectPart("symbol", symbol);
// Do the invocation.
15. operation.executeRequestResponseOperation(input, output, fault); 
// Extract the result from output message.
16. float result = output.getFloatPart("result")
...
                   

In the dynamic invocation, Lines 1 through 7 match the code in the stub invocation. On Line 8, a port is created for the service; on Line 9, a specific operation of interest is created. On Lines 10, 11, and 12, input, output, and fault messages are created. For the getQuote() operation, we have string input and string output. The input values are set in Line 14, and finally, on Line 15, the operation is invoked. On Line 16, the stock price value is retrieved.

Using WSIF step by step

  1. Download the WSIF framework from Apache.
  2. Run wsif-2.0classpath.bat to set appropriate classpath. This script also sets the classpath for samples included in the download. You may need to modify this file depending on your development environment.
  3. Create a WSIF-WSDL file for your service provider. For SOAP-based applications, you could use its WSDL as a starting point. For Java and EJB applications, you could use Java2WSDL. And, for adventurous types, you could create WSDL by hand.
  4. Run WSDL2Java to create Java stubs for the WSDL.
  5. Modify WSDL to include WSIF extensions for Java, EJB, etc., depending on type of service provider.
  6. Place WSIF-WSDL file and stubs in your application’s directory path.
  7. Start using WSIF in your application.

WSIF and service-oriented architecture

SOA-based services must adhere to three basic tenets:

  • Interface contract is platform-independent
  • Service can be dynamically located and invoked
  • Service is self contained

WSIF takes your code a few steps closer to service-oriented architecture:

  • WSIF’s WSDL-based interface description of services provides platform-independent interface definitions in portType.
  • The WSIF framework automatically locates component locations specified in the WSDL-based XML configuration file. The choice of implementation can be deferred until runtime.
  • Being a client-side framework, WSIF cannot make a service self contained; however, WSIF works best with self-contained services and does not require state management between calls.

WSIF Java extension and WSDL

Let’s walk through a structure of WSDL to see how WSIF extends WSDL. WSDL is an XML file with four main sections:

  1. Definitions
  2. Types
  3. Bindings
  4. Services

WSIF extends WSDL’s bindings and services sections to specify WSIF providers. Bindings allow plug-ins of various providers. Thus, WSIF has providers for Java, EJB, SOAP, J2EE Connector Architecture, etc. These providers enable the invocation of corresponding services.

We will take a publicly available WSDL file at http://services.xmethods.net to understand various sections of WSDL and how WSIF extends such a file. For a more detailed explanation of WSDL, please see Resources. The WSDL delayed-quote service file is available here: http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl.

Definitions

Let’s look at the first two lines of the delayed-quote service WSDL file downloaded from the site above. This is the definitions section of the WSDL file:

                        <definitions name="net.xmethods.services.stockquote.StockQuote" 
   targetNamespace="http://www.themindelectric.com/wsdl/net.xmethods.services.
   stockquote.StockQuote/">
                   

The definitions section is WSDL’s root element and is a container for all other WSDL elements. It holds all necessary information about the service and its attributes. The definitions element’s targetNamespace attribute is required and points to a URI that demarcates this WSDL file’s namespace. The WSIF service definition requires the addition of a few namespaces as indicated below. targetNamespaces differentiate definitions from element declarations in different vocabularies. This means various elements defined in this WSDL file belong to the http://www.themindelectric.com/wsdl/net.xmethods.services namespace.

                        ...
<definitions name='net.xmethods.services.stockquote.StockQuote' 
             targetNamespace='http://mycompany.StockQuote/' 
             xmlns:xsd="http://www.w3.org/1999/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
             xmlns:java="http://schemas.xmlsoap.org/wsdl/java/"
             xmlns="http://schemas.xmlsoap.org/wsdl/">
...
                   

portType

The portType defines a service’s interface. It is an abstract definition, meaning it does not depend on the actual technology used to implement the interface. It incrementally defines functions, or operations, the service users should expect when using the service. First, parts are defined, which are the smallest units of schema-defined types. Next, messages are defined, which combines various parts to construct a logical unit used as a parameter in functions. Various operations combine to form a portType. Take a moment to look at the following portType section:

                        ...
<message name="getQuoteResponse1">
   <part name="result" type="xsd:float"/>
</message>
<message name="getQuoteRequest1">
   <part name="symbol" type="xsd:string"/>
</message>
<portType name="net.xmethods.services.stockquote.StockQuotePortType">
   <operation name="getQuote" parameterOrder="symbol">
      <input message="tns:getQuoteRequest1"/>
      <output message="tns:getQuoteResponse1"/>
   </operation>
</portType>
...
                   

In the example above, result is a part and is of type xsd:float. The getResponseQuote1 is a message and consists of part result. The operation getQuote consists of input and output messages getQuoteRequest1. The net.xmethods...StockQuotePortType is a portType and consists of operation getQuote. Although this port has only one operation, there could be more than one, with each having exceptions. For WSIF, portType definitions remain exactly the same as one might expect in a typical WSDL definition for a SOAP-based service.

Binding

As mentioned earlier, portTypes are abstract. The WSDL’s binding section ties the specific technology to the WSDL. The binding element maps between a portType and a protocol. Look at the following sample binding section:

                        ...
<binding name="net.xmethods.services.stockquote.StockQuoteBinding" type="tns:net.xmethods.services.stockquote.StockQuotePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
   <operation name="getQuote">
      <soap:operation soapAction="urn:xmethods-delayed-quotes#getQuote"/>
      <input>
         <soap:body use="encoded" namespace="urn:xmethods-delayed-quotes" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
         <soap:body use="encoded" namespace="urn:xmethods-delayed-quotes" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
   </operation>
</binding>
...
                   

In the sample above, tns:net.xmethods...StockQuotePortType is bound to soap:binding. Each operation, input, and output is bound to SOAP constructs soap:operation and soap:body. The SOAP body’s target namespace is specified under soap:body‘s namespace attribute.

WSIF extends WSDL’s binding element. WSIF has various types of bindings: Java, EJB, and JMS (Java Message Service) bindings are used to map a portType to respective types of service implementations. Bear in mind that the actual service provider does not change; only the WSDL’s service definition is bound to specific providers in the WSIF framework. A Java binding looks like this:

                        ...
<binding name="mycompany.java.services.stockquote.StockQuoteBinding" type="tns:net.xmethods.services.stockquote.StockQuotePortType">
   <java:binding/>
   <format:typeMapping encoding="Java" style="Java"/>
   <operation name="getQuote">
      <java:operation methodName="getQuote" parameterOrder="symbol" methodType="instance"/>
      <input name="getQuoteRequest1"/>
      <output name="getQuoteResponse1"/>
   </operation>
</binding>
...
                   

In the example above, java:binding indicates that the service is provided by a Java-based provider. In other words, our Java client calls other Java classes. format:TypeMapping maps qnames to Java classes. Using java:binding is sufficient for indicating a Java binding, since no transformation is needed for Java objects going from the client code to the target service, which is also in Java. This may however differ for SOAP bindings, for example, because Java objects from client code would need to transform to an XML-based type system.

The java:operation maps abstract portType operation getQuote to Java function getQuote(). Here, parameterOrder overrides portType‘s order. It changes the parameter orders and, in Java binding, specifies the method signature. The methodType attribute specifies whether the Java method is an instance method, a constructor, or a static method. input and output, as the names suggest, indicate input and output types of the getQuote operation. For more information on EJB, JMS, and other binding types please refer to the WSIF Website.

Service

A standard WSDL service specifies information that identifies the service’s location for a binding. The port element specifies the exact endpoint where the service is available, as shown in the code below:

                        ...
<service name="net.xmethods.services.stockquote.StockQuoteService">
   <port name="net.xmethods.services.stockquote.StockQuotePort" binding="tns:net.xmethods.services.stockquote.StockQuoteBinding">
      <soap:address location="http://64.124.140.30:9090/soap"/>
   </port>
</service>
...
                   

In the example above, StockQuoteService with SOAP StockQuoteBinding binding is available at SOAP address http://64.124…/soap. WSIF extends the port element to specify Java endpoints. java:address specifies the Java endpoint. className is a fully qualified Java class name. Optionally, classPath and classLoader can be used to specify classpath and classloader prior to invocation.

The service element for the Java provider will look as follows:

                        ...
<service name="mycompany.java.services.stockquote.StockQuoteService">
   <documentation>mycompany.java.services.stockquote.StockQuote service</documentation>
   <port name="mycompany.java.services.stockquote.StockQuotePort" binding="mycompany.java.services.stockquote.StockQuoteBinding">
      <java:address className="mycompany.stockquote"/>
   </port>
</service>
...
                   

In the example above, Java service StockQuoteService is made available by the mycompany.stockquote Java class.

WSIF-EJB extension and WSDL

For a WSIF-EJB extension, portType definitions remain exactly the same as one might expect in a typical WSDL definition for a SOAP-based service.

Binding

An EJB binding would look like the following:

                        ...
<binding name="mycompany.ejb.services.stockquote.StockQuoteBinding" type="tns:net.xmethods.services.stockquote.StockQuotePortType">
   <ejb:binding/>
   <format:typeMapping encoding="Java" style="Java"/>
   <operation name="getQuote">
      <ejb:operation methodName="getQuote" parameterOrder="symbol"    interface="remote"/>
      <input name="getQuoteRequest1"/>
      <output name="getQuoteResponse1"/>
   </operation>
</binding>
...
                   

In the example above, ejb:binding indicates that the service is provided by an EJB-based service provider. In other words, our Java client calls EJB objects. format:typeMapping maps qnames to Java classes. For EJB-like Java bindings, indicating “Java” proves sufficient since no transformation is needed for the Java objects going from client code to the target service, which is also in Java. ejb:operation maps abstract portType operation getQuote to Java function getQuote(). The remainder of this binding section matches our previous example.

Service

An EJB service element would look like the following:

                        ...
<service name="mycompany.java.services.stockquote.StockQuoteService">
   <documentation>mycompany.java.services.stockquote.StockQuote service</documentation>
   <port name="mycompany.ejb.services.stockquote.StockQuotePort" 
      binding="mycompany.ejb.services.stockquote.StockQuoteBinding">
      jndiName="vendor specific jndiname needs to be specified here"
      initialContextFactory="vendor specific initialcontextfactory needs to be specified here"
      jndiProviderURL="vendor specific jndiproviderURL needs to be specified here"/>
</port>
</service>
...
                   

WSIF extends the port element to specify EJB endpoints. ejb:address specifies the EJB endpoint. className is a fully qualified EJB home interface class name. In the example above, EJB service StockQuoteService is made available by the EJB service located at jndiName.

Conclusion

The beauty of WSIF is that not a single line of the original code retrieving the stock quote needs to change when the implementations for the underlying provider change from Java to EJB. We just need to change the underlying WSIF configuration file from one that contains Java bindings to one that contains EJB bindings, maintaining the same file name. WSIF simply picks up the new file placed at the same location and starts routing calls to EJB providers as opposed to Java providers.

Gautam Shahhas been developing large complex applications for more than a decade. Currently, as a senior architect for Unisys, he has designed patent-pending solutions that enable information sharing between agencies. He has varied expertise in J2EE, .Net, open source solutions, and various integration platforms such as BizTalk, WebMethods, and WebSphere Business Integration Server.