Developing a WSIF service

A Web Services Invocation Framework (WSIF) service is a web service that uses WSIF.

About this task

To develop a WSIF service, develop the web service (or use an existing web service), then develop the WSIF client based on the Web Services Description Language (WSDL) document for that Web service.

To develop a WSIF service, complete the following steps:

Procedure

  1. Implement the web service.

    Use web services tools to discover, create, and publish the web service. You can develop Java™ bean, enterprise bean, and URL web services. You can use web service tools to create skeleton Java code and a sample application from a WSDL document. For example, an enterprise bean can be offered as a Web service, and use Remote Method Invocation over Internet Inter-ORB Protocol (RMI-IIOP) as the access protocol. Or you can use a Java class as a web service, with native Java invocations as the access protocol.

    [AIX Solaris HP-UX Linux Windows][z/OS]You can use the WebSphere® Studio Application Developer to create a web service from a Java application, as described in its StockQuote service tutorial. The Java application that you use in this scenario returns the last trading price from the Internet website www.xmltoday.com, given a stock symbol. Using the web service wizard, you generate a binding WSDL document named StockQuoteService-binding.wsdl and a service WSDL document named StockQuoteService-service.wsdl from the StockQuoteService.java bean. You then deploy the web service to a web server, generate a client proxy to the Web service, and generate a sample application that accesses the StockQuoteService through the client proxy. You test the StockQuote web service, publish it by using the IBM® UDDI Explorer, and then discover the StockQuote web service in the IBM UDDI Test Registry.

    [IBM i]You can use the WebSphere Development Studio for System i® (WDS) to create a web service from a Java application. Using the web service wizard, you generate a binding WSDL document and a service WSDL document from the Java bean. You can then deploy the web service to a web server, generate a client proxy to the web service, and generate a sample application that accesses the service through the client proxy. You can test the service, publish it by using the IBM UDDI Explorer, and then discover the service in the IBM UDDI Test Registry.

  2. Develop the WSIF client.
    Use the following information to help you develop a WSIF client:

    The AddressBook sample is written for synchronous interaction. If you are using a JMS provider, your WSIF client might have to act asynchronously. WSIF provides two main features that meet this requirement:

    • A correlation service that assigns identifiers to messages so that the request can match up with the (eventual) response.
    • A response handler that picks up the response from the web service at a later time.
    For more information, see WSIFOperation - Asynchronous interactions reference.

Example: Using WSIF to invoke the AddressBook sample web service dynamically

This is example code for dynamic invocation of the AddressBook sample web service by using WSIF:


    try {
        String wsdlLocation="clients/addressbook/AddressBookSample.wsdl";

        // The starting point for any dynamic invocation using wsif is a
        // WSIFServiceFactory. Create one through the newInstance
        // method.
        WSIFServiceFactory factory = WSIFServiceFactory.newInstance();

        // Once you have a factory, you can use it to create a WSIFService object
        // corresponding to the AddressBookService service in the wsdl file.
        // Note: because you only have one service defined in the wsdl file, you
        // do not have to use the namespace and name of the service and can pass
        // null instead. This also applies to the port type, although values have
        // been used in the following example for illustrative purposes.
        WSIFService service = factory.getService(
            wsdlLocation,    // location of the wsdl file 
            null,            // service namespace
            null,            // service name
           https://www.ibm.com/namespace/wsif/samples/ab, // port type namespace
            AddressBookPT // port type name
        );

        // The AddressBook.wsdl file contains the definitions for two complexType
        // elements within the schema element. Map these complexTypes
        // to Java classes. These mappings are used by the Apache SOAP provider            
        service.mapType(
            new javax.xml.namespace.QName(
                https://www.ibm.com/namespace/wsif/samples/ab/types,
                address),
            Class.forName(com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress));
        service.mapType(
            new javax.xml.namespace.QName(
                https://www.ibm.com/namespace/wsif/samples/ab/types,
                phone),
            Class.forName(com.ibm.www.namespace.wsif.samples.ab.types.WSIFPhone));
            // You now have a WSIFService object. The next step is to create a WSIFPort
            // object for the port you want to use. The getPort(String portName) method
            // allows us to generate a WSIFPort from the port name.
        WSIFPort port = null;

        if (portName != null) {
            port = service.getPort(portName);
        }
        if (port == null) {
            // If no port name was specified, attempt to create a WSIFPort from
            // the available ports for the port type specified on the service
            port = getPortFromAvailablePortNames(service);
        }

        // Once you have a WSIFPort, you can create an operation. Execute
        // the addEntry operation and therefore attempt to create a WSIFOperation
        // corresponding to it. The addEntry operation is overloaded in the wsdl i.e. 
		// there are two versions of it, each taking different parameters (parts). 
		// This overloading requires that you specify the input and output message 
		// names for the operation in the createOperation method so that the correct 
		// operation can be resolved.
        // Because the addEntry operation has no output message, you use null for its name.
        WSIFOperation operation =
            port.createOperation(addEntry, AddEntryWholeNameRequest, null);

        // Create messages to use in the execution of the operation. This should
        // be done by invoking the createXXXXXMessage methods on the WSIFOperation.
        WSIFMessage inputMessage = operation.createInputMessage();
        WSIFMessage outputMessage = operation.createOutputMessage();
        WSIFMessage faultMessage = operation.createFaultMessage();

        // Create a name and address to add to the addressbook
        String nameToAdd=Chris P. Bacon;
        WSIFAddress addressToAdd = 
            new WSIFAddress (1, 
                The Waterfront,
                Some City,
                NY,
                47907,
                new WSIFPhone (765, 494, 4900));

        // Add the name and address to the input message
        inputMessage.setObjectPart(name, nameToAdd);
        inputMessage.setObjectPart(address, addressToAdd);

        // Execute the operation, obtaining a flag to indicate its success
        boolean operationSucceeded =
            operation.executeRequestResponseOperation(
                inputMessage,
                outputMessage,
                faultMessage);

        if (operationSucceeded) {
            System.out.println(Successfully added name and address to addressbook\n);
        } else {
            System.out.println(Failed to add name and address to addressbook);
        }

        // Start from fresh
        operation = null;
        inputMessage = null;
        outputMessage = null;
        faultMessage = null;

        // This time you will lookup an address from the addressbook.
        // The getAddressFromName operation is not overloaded in the
        // wsdl and therefore you can specify the operation name
        // without any input or output message names.
        operation = port.createOperation(getAddressFromName);

        // Create the messages
        inputMessage = operation.createInputMessage();
        outputMessage = operation.createOutputMessage();
        faultMessage = operation.createFaultMessage();

        // Set the name to find in the addressbook
        String nameToLookup=Chris P. Bacon;
        inputMessage.setObjectPart(name, nameToLookup);

        // Execute the operation
        operationSucceeded =
            operation.executeRequestResponseOperation(
                inputMessage,
                outputMessage,
                faultMessage);

        if (operationSucceeded) {
            System.out.println(Successful lookup of name '+nameToLookup+' in addressbook);

            // You can get the address that was found by querying the output message
            WSIFAddress addressFound = (WSIFAddress) outputMessage.getObjectPart(address);
            System.out.println(The address found was:);
            System.out.println(addressFound);
        } else {
            System.out.println(Failed to lookup name in addressbook);
        }

    } catch (Exception e) {
        System.out.println(An exception occurred when running the sample:);
        e.printStackTrace();
    }
}

The preceding code refers to the following Sample method:


    WSIFPort getPortFromAvailablePortNames(WSIFService service)
            throws WSIFException {
        String portChosen = null;
        
        // Obtain a list of the available port names for the service
        Iterator it = service.getAvailablePortNames();
        {
            System.out.println(Available ports for the service are: );
            while (it.hasNext()) {
                String nextPort = (String) it.next();
                if (portChosen == null)
                    portChosen = nextPort;
                System.out.println( -  + nextPort);
            }
        }
        if (portChosen == null) {
            throw new WSIFException(No ports found for the service!);
        }
        System.out.println(Using port  + portChosen + \n);
        
        // An alternative way of specifying the port to use on the service
        // is to use the setPreferredPort method. Once a preferred port has
        // been set on the service, a WSIFPort can be obtained through getPort
        // (no arguments). If a preferred port has not been set and more than
        // one port is available for the port type specified in the WSIFService,
        // an exception is thrown. 
        service.setPreferredPort(portChosen);
        WSIFPort port = service.getPort();
        return port;
    }

The web service uses the following classes:

WSIFAddress:


public class WSIFAddress implements Serializable {

    //instance variables
    private int	streetNum;
    private java.lang.String	streetName;
    private java.lang.String	city;
    private java.lang.String	state;
    private int	zip;
    private WSIFPhone	phoneNumber;

    //constructors
    public WSIFAddress () { }

    public WSIFAddress (int streetNum, 
                        java.lang.String streetName, 
                        java.lang.String city, 
                        java.lang.String state, 
                        int zip, 
                        WSIFPhone phoneNumber) {
          this.streetNum	= streetNum;
          this.streetName	= streetName;
          this.city	= city;
          this.state	= state;
          this.zip	= zip;
          this.phoneNumber	= phoneNumber;
    }

    public int getStreetNum() {
          return streetNum;
    }

    public  void setStreetNum(int streetNum) {
          this.streetNum	= streetNum;
    }

    public java.lang.String getStreetName() {
          return streetName;
    }

    public  void setStreetName(java.lang.String streetName) {
          this.streetName	= streetName;
    }

    public java.lang.String getCity() {
          return city;
    }

    public  void setCity(java.lang.String city) {
          this.city	= city;
    }

    public java.lang.String getState() {
          return state;
    }

    public  void setState(java.lang.String state) {
          this.state	= state;
    }

    public int getZip() {
          return zip;
    }

    public  void setZip(int zip) {
          this.zip	= zip;
    }

    public WSIFPhone getPhoneNumber() {
          return phoneNumber;
    }

    public  void setPhoneNumber(WSIFPhone phoneNumber) {
          this.phoneNumber	= phoneNumber;
    }
}

WSIFPhone:


public class WSIFPhone implements Serializable {

    //instance variables
    private int	areaCode;
    private java.lang.String	exchange;
    private java.lang.String	number;

    //constructors
    public WSIFPhone () { }

    public WSIFPhone (int areaCode, 
                      java.lang.String exchange,  
                      java.lang.String number) {
          this.areaCode	= areaCode;
          this.exchange	= exchange;
          this.number	= number;
    }

    public int getAreaCode() {
          return areaCode;
    }

    public  void setAreaCode(int areaCode) {
          this.areaCode	= areaCode;
}

    public java.lang.String getExchange() {
          return exchange;
    }

    public  void setExchange(java.lang.String exchange) {
          this.exchange	= exchange;
    }

    public java.lang.String getNumber() {
          return number;
    }

    public  void setNumber(java.lang.String number) {
          this.number	= number;
    }
}

WSIFAddressBook:


public class WSIFAddressBook {
    private Hashtable name2AddressTable = new Hashtable();

    public WSIFAddressBook() {
    }

    public void addEntry(String name, WSIFAddress address)
    {
        name2AddressTable.put(name, address);
    }

    public void addEntry(String firstName, String lastName, WSIFAddress address)
    {
        name2AddressTable.put(firstName+ +lastName, address);
    }

    public WSIFAddress getAddressFromName(String name)
        throws IllegalArgumentException
    {

        if (name == null)
        {
            throw new IllegalArgumentException(The name argument must not be  +
                                               null.);
        }
        return (WSIFAddress)name2AddressTable.get(name);
    }

}

The following code is the corresponding WSDL file for the web service:


<?xml version="1.0" ?>

<definitions targetNamespace="https://www.ibm.com/namespace/wsif/samples/ab"
             xmlns:tns="https://www.ibm.com/namespace/wsif/samples/ab"
             xmlns:typens="https://www.ibm.com/namespace/wsif/samples/ab/types"
             xmlns:xsd="https://www.w3.org/2001/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:ejb="http://schemas.xmlsoap.org/wsdl/ejb/"
             xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types>
    <xsd:schema
      	targetNamespace="https://www.ibm.com/namespace/wsif/samples/ab/types"
        xmlns:xsd="https://www.w3.org/2001/XMLSchema">
        
      <xsd:complexType name="phone">
        <xsd:element name="areaCode" type="xsd:int"/>
        <xsd:element name="exchange" type="xsd:string"/>
        <xsd:element name="number" type="xsd:string"/>
      </xsd:complexType>

      <xsd:complexType name="address">
        <xsd:element name="streetNum" type="xsd:int"/>
        <xsd:element name="streetName" type="xsd:string"/>
        <xsd:element name="city" type="xsd:string"/>
        <xsd:element name="state" type="xsd:string"/>
        <xsd:element name="zip" type="xsd:int"/>
        <xsd:element name="phoneNumber" type="typens:phone"/>      
      </xsd:complexType>
      	  
    </xsd:schema>
  </types>

  <message name="AddEntryWholeNameRequestMessage">
    <part name="name" type="xsd:string"/>
    <part name="address" type="typens:address"/>
  </message>

  <message name="AddEntryFirstAndLastNamesRequestMessage">
    <part name="firstName" type="xsd:string"/>
    <part name="lastName" type="xsd:string"/>
    <part name="address" type="typens:address"/>
  </message>

  <message name="GetAddressFromNameRequestMessage">
    <part name="name" type="xsd:string"/>
  </message>

  <message name="GetAddressFromNameResponseMessage">
    <part name="address" type="typens:address"/>
  </message>

  <portType name="AddressBookPT">
    <operation name="addEntry">
      <input name="AddEntryWholeNameRequest" 
	      message="tns:AddEntryWholeNameRequestMessage"/>
    </operation>
    <operation name="addEntry">
      <input name="AddEntryFirstAndLastNamesRequest" 
	      message="tns:AddEntryFirstAndLastNamesRequestMessage"/>
    </operation>
    <operation name="getAddressFromName">
      <input name="GetAddressFromNameRequest" 
	      message="tns:GetAddressFromNameRequestMessage"/>
      <output name="GetAddressFromNameResponse" 
	       message="tns:GetAddressFromNameResponseMessage"/>
    </operation>
  </portType>

  <binding name="SOAPHttpBinding" type="tns:AddressBookPT">
    <soap:binding style="rpc"
                   transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="addEntry">
      <soap:operation soapAction=""/>
      <input name="AddEntryWholeNameRequest">
        <soap:body use="encoded"
                   namespace="https://www.ibm.com/namespace/wsif/samples/ab"
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
    </operation>
    <operation name="addEntry">
      <soap:operation soapAction=""/>
      <input name="AddEntryFirstAndLastNamesRequest">
        <soap:body use="encoded"
                   namespace="https://www.ibm.com/namespace/wsif/samples/ab"
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
    </operation>
    <operation name="getAddressFromName">
      <soap:operation soapAction=""/>
      <input name="GetAddressFromNameRequest">
        <soap:body use="encoded"
                   namespace="https://www.ibm.com/namespace/wsif/samples/ab"
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output name="GetAddressFromNameResponse">
        <soap:body use="encoded"
                   namespace="https://www.ibm.com/namespace/wsif/samples/ab"
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
  </binding>

  <binding name="JavaBinding" type="tns:AddressBookPT">
    <java:binding/>
    <format:typeMapping encoding="Java" style="Java">
      <format:typeMap typeName="typens:address" 
             formatType="com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress"/>
      <format:typeMap typeName="xsd:string" formatType="java.lang.String"/>
    </format:typeMapping>
    <operation name="addEntry">
      <java:operation
         methodName="addEntry"
         parameterOrder="name address"
         methodType="instance"/>
      <input name="AddEntryWholeNameRequest"/>
    </operation>
    <operation name="addEntry">
      <java:operation
         methodName="addEntry"
         parameterOrder="firstName lastName address"
         methodType="instance"/>
      <input name="AddEntryFirstAndLastNamesRequest"/>
    </operation>
    <operation name="getAddressFromName">
      <java:operation
         methodName="getAddressFromName"
         parameterOrder="name"
         methodType="instance"
         returnPart="address"/>
      <input name="GetAddressFromNameRequest"/>
      <output name="GetAddressFromNameResponse"/>
    </operation>
  </binding>
  
  <binding name="EJBBinding" type="tns:AddressBookPT">
    <ejb:binding/>
    <format:typeMapping encoding="Java" style="Java">
      <format:typeMap typeName="typens:address" 
             formatType="com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress"/>
      <format:typeMap typeName="xsd:string" formatType="java.lang.String"/>
    </format:typeMapping>
    <operation name="addEntry">
      <ejb:operation
         methodName="addEntry"
         parameterOrder="name address"
         interface="remote"/>
      <input name="AddEntryWholeNameRequest"/>
    </operation>
    <operation name="addEntry">
      <ejb:operation
         methodName="addEntry"
         parameterOrder="firstName lastName address"
         interface="remote"/>
      <input name="AddEntryFirstAndLastNamesRequest"/>
    </operation>
    <operation name="getAddressFromName">
      <ejb:operation
         methodName="getAddressFromName"
         parameterOrder="name"
         interface="remote"
         returnPart="address"/>
      <input name="GetAddressFromNameRequest"/>
      <output name="GetAddressFromNameResponse"/>
    </operation>
  </binding> 
  <service name="AddressBookService">
    <port name="SOAPPort" binding="tns:SOAPHttpBinding">
      <soap:address 
	      location="http://myServer/wsif/samples/addressbook/soap/servlet/rpcrouter"/>
    </port>
    <port name="JavaPort" binding="tns:JavaBinding">
      <java:address className="services.addressbook.WSIFAddressBook"/>
    </port>
    <port name="EJBPort" binding="tns:EJBBinding">
      <ejb:address className="services.addressbook.ejb.AddressBookHome"
        jndiName="ejb/samples/wsif/AddressBook"
		classLoader="services.addressbook.ejb.AddressBook.ClassLoader"/>
    </port>    
  </service>

</definitions>