XML/SOAP Clients  Locate

Overview  Locate

XML/SOAP clients work on the XML/SOAP Protocol level (see Overview to Message Processing for a description of levels). This is a lower level than the one on which Java clients reside. In contrast to Java or JAX-RPC clients, XML/SOAP clients do not call a specific method on the server objects. Instead, a client creates a SOAP message and sends it as an XML document to the server for processing.

In WSO2 SOA Enablement Server, SOAP messages on the XML/SOAP level follow Simple Object Access Protocol (SOAP) 1.1 or 1.2 and SOAP with Attachments specifications, and are accessible by using SOAP with Attachments API for Java (SAAJ) 1.1 and the Java API for XML Messaging (JAXM) 1.1. SAAJ enables developers to produce and consume messages conforming to the SOAP 1.1 specification and SOAP with Attachments note. JAXM enables applications to send and receive document oriented XML messages using a pure Java API.

One-Way Invocation Using JAXM, SAAJ  Locate

In one-way messaging, when the client sends a message to the service it does not wait for a response. It can continue processing after it has sent the message. Thus one-way messages are "non-blocking"; they do not block the sender until the response arrives.

A client that wants to send one-way (non-blocking) messages has to use the JAXM provider. Such a client maintains its connection to its provider and all messages that the client sends or receives go through this messaging provider.

The WSO2 SOA Enablement Server implementation of the ProviderConnection is an instance of org.systinet.wasp.messaging.WaspProviderConnection, which extends the javax.xml.messaging.ProviderConnection interface. The WSO2 SOA Enablement Server extension enables a client to send either one-way or request-response messages to a given endpoint, set up custom message processing with the help of interceptors and handlers and perform asynchronous messaging.

The instance of WaspProviderConnection can be obtained from a ProviderConnetionFactory, usually the newInstance() method.

The WaspProviderConnection can also be used for obtaining an instance of MessageFactory, which produces SOAPMessage objects according to the SOAP 1.2 protocol.

The code fragment in Example 85 demonstrates how to obtain an instance of the WaspProviderConnection, how to use it for creating a SOAP 1.2 message and how to send this message as a one-way message.

Example 85. Code Fragment Showing How to Obtain Instance of WaspProviderConnection

ProviderConnectionFactory connectionFactory = 
    ProviderConnectionFactory.newInstance();
WaspProviderConnection connection = 
    WaspProviderConnection)connetionFactory.createConnection();
MessageFactory factory = 
    connection.createMessageFactory(
        WaspProviderConnection.MESSAGE_FACTORY_SOAP12);
SOAPMessage message = factory.createMessage();
// fill the message
SOAPBody body = message.getSOAPPart().getEnvelope().getBody();
//...
// send the message
connection.send(message, "http://localhost:6060/OnewayService");

Example 86 is a simple client that performs a one-way message call. The client creates a new SOAP message that includes the path of the endpoints to which it should be resent and sends it to the first target. The example is the client of the MessagingService service from the XML/SOAP Service. Both examples are part of the Messaging demo.

Example 86. One-way Messaging Client

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.invocation;

import org.systinet.wasp.messaging.WaspProviderConnection;

import javax.xml.messaging.ProviderConnectionFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;


public class MessagingClient {
    private static String servicesPath = "/demo/advanced/MessagingService/";

    public static void main(String[] args) throws Exception {
        String serverURL = "http://localhost:6060";

        // we will send message via SOAP 1.1
        WaspProviderConnection provider =
            (WaspProviderConnection) 
            ProviderConnectionFactory.newInstance()
                                     .createConnection();
        MessageFactory msgFactory =
            provider.createMessageFactory(
            WaspProviderConnection.MESSAGE_FACTORY_SOAP11);
        SOAPMessage msg = msgFactory.createMessage();

        // add headers - these are targets for the message
        SOAPEnvelope envelope = msg.getSOAPPart()
                                   .getEnvelope();
        SOAPHeader headers = envelope.getHeader();
        SOAPHeaderElement target;
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Happy");
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Bashful");
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Sneezy");
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Sleepy");
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Grumpy");
        target = headers.addHeaderElement(envelope.createName("target"));
        target.addTextNode(serverURL + servicesPath + "Dopey");

        // create body with a string message
        SOAPBody body = envelope.getBody();
        SOAPElement message =
            body.addBodyElement(envelope.createName("message"));
        message.addTextNode("Hello Doc !!!");

        // send the message
        String url = serverURL + servicesPath + "Doc";
        System.out.println("Sending message to " + url + " ...");
        provider.send(msg, url);
        System.out.println("See the result at the server console.");

        // close
        provider.close();
    }
}
[Note]Note

To allows better resource reuse, it is recommended to invoke WaspSoapMessage.release() as soon as the work with the SOAPMessage is finished.

Request-Response Invocation using JAXM, SAAJ  Locate

In request-response messaging, the client sends a message to a service and waits for a response. The response message unblocks the client, which can then continue processing other work. The client that wants to send a request-response message can use SOAPConnection, an implementation of the javax.xml.soap.SOAPConnection interface, which is part of the SAAJ API. It can also use the JAXM-based WaspProviderConnection messaging provider described in One-Way Invocation above.

[Note]Note

To send a SOAP message according to the SOAP 1.2 protocol, you must use WASPProviderConnection to obtain the proper MessageFactory object.

The code fragment in Example 87 demonstrates how to obtain an instance of SOAPConnection and how to send a request-response message.

Example 87. Obtaining an Instance of SOAPConnection

SOAPConnectionFactory connectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = connectionFactory.createConnection();
SOAPMessage messsage = MessageFactory.newInstance().createMessage();
// fill the message
SOAPBody body = messsage.getSOAPPart().getEnvelope().getBody();
//...
// send the message
SOAPMessage response = connection.call(messsage, 
                           "http://localhost:6060/ReqRespService");
// read the response
SOAPBody respBody = response.getSOAPPart().getEnvelope().getBody();
//...

Example 88 shows a simple HelloService client that uses SOAPConnection to create a SOAP message, send it and process the incoming response.

Example 88. Simple Request-response Client Using SOAPConnection

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.invocation;

import java.util.Iterator;

import javax.xml.messaging.Endpoint;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;


public class XMLHelloClient {
    public static void main(String[] args) throws SOAPException {
        // creates message
        MessageFactory factory = MessageFactory.newInstance();
        SOAPMessage message = factory.createMessage();
        SOAPEnvelope envelope = message.getSOAPPart()
                                       .getEnvelope();
        SOAPBody body = envelope.getBody();
        SOAPBodyElement bodyElement =
            body.addBodyElement(
                envelope.createName("string_Request", null,
                    "http://wso2.com/xsd/SchemaTypes/"));
        bodyElement.addTextNode("World");

        // sends message
        SOAPConnectionFactory soapConnectionFactory =
            SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection =
            soapConnectionFactory.createConnection();
        SOAPMessage outMessage =
            soapConnection.call(
                message,
                new Endpoint("http://localhost:6060/XMLHelloService"));

        // reads response
        envelope = outMessage.getSOAPPart()
                             .getEnvelope();
        body = envelope.getBody();

        Iterator operation =
            body.getChildElements(
                envelope.createName("string_Response", null,
                    "http://wso2.com/xsd/SchemaTypes/"));
        System.out.println(((SOAPElement) operation.next()).getValue());
    }
}
[Note]Note

To allows better resource reuse, it is recommended to invoke WaspSoapMessage.release() as soon as the work with the SOAPMessage is finished. This applies to both outgoing (request) and incoming (response) messages.

Stream-Based Invocation Using Tokenizer  Locate

Stream-based invocation is useful when an application works in both service and client roles and processes large SOAP messages.

The application processes an incoming request and immediately creates a response, which is sent to another recipient. For large messages, classical access by the tree-like SAAJ API would consume too much memory.

Instead of using the tree-like SAAJ API, you can access and process SOAP messages in a stream-based manner using Tokenizer (see Javadoc for org.idoox.xml.Tokenizer). The tokenizer represents an XML document as a sequence of XML tokens (elements). The stream-based SOAP message processing does not create a representation of the SOAP message in memory. This gives WSO2 SOA Enablement Server high performance and scalability.

A stream-based client is similar to a stream-based service that consumes one-way messages and sends the message, modified by Tokenizer, to another recipient. For an example of a stream-based service using Tokenizer, see Stream-based Service in the XML/SOAP Service chapter of Writing Web services.

MIME and DIME Attachments, JAF  Locate

Sometimes a client needs to send application-specific binary data to its peer. Such data is represented at the XML/SOAP level as attachments, following the SOAP with Attachments specification. A SOAP message can contain any number of these attachments in addition to the SOAP part.

In the SAAJ API the SOAPMessage object provides methods for creating AttachmentPart objects and for adding them to a SOAPMessage object.

Example 89 shows a simple client that adds an attachment to the SOAP message and sends it:

Example 89. Client Using SOAP with Attachments

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.invocation;

import org.systinet.wasp.messaging.WaspProviderConnection;

import java.io.ByteArrayInputStream;

import javax.xml.messaging.ProviderConnectionFactory;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;


public class XMLAttachmentClient {
    public static void main(String[] args) {
        try {
            // gets message factory
            MessageFactory factory = MessageFactory.newInstance();

            // creates SOAP message
            SOAPMessage message = factory.createMessage();

            // attachment data
            ByteArrayInputStream data =
                new ByteArrayInputStream(new byte[] { 0, 1, 2, 3 });

            // creates attachment part
            AttachmentPart attachmentPart =
                message.createAttachmentPart(data, "application/binary");

            // adds attachemtn part to message
            message.addAttachmentPart(attachmentPart);

            // gets provider connetion fatory
            ProviderConnectionFactory connectionFactory =
                ProviderConnectionFactory.newInstance();

            // creates wasp provider connection - 
            // enable to send message without blocking the client
            WaspProviderConnection connection =
                (WaspProviderConnection) connectionFactory.createConnection();

            // sends message
            connection.send(message,
                "http://localhost:6060/XMLAttachmentService");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Handling Attachments Through JAF  Locate

Attachments can also be handled through the JavaBeans Activation Framework (JAF) by using a DataHandler object. See the following code fragment for example:

Example 90. Handling Attachments Through JAF

MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
java.awt.Image image = Toolkit.getDefaultToolkit().createImage("image.jpg");
AttachmentPart attachmentPart = message.createAttachmentPart(
                                    new DataHandler(image, "image/jpeg"));
message.addAttachmentPart(attachmentPart);
Setting Encapsulation Type  Locate

WSO2 SOA Enablement Server supports both MIME and DIME encapsulation. The XML service can use the default encapsulation chosen during WSO2 SOA Enablement Server installation as its default Multi-part encapsulation or it can be set in the SOAP message. Both options are transparent to the user.

The code fragment in Example 91 illustrates how to set DIME encapsulation in a SOAP message:

Example 91. Setting DIME Encapsulation in a SOAP Message

MessageFactory factory = MessageFactory.newInstance();
WaspSOAPMessage message = (WaspSOAPMessage)factory.createMessage();
message.setAttachmentType(org.idoox.transport.Message.CT_APPLICATION_DIME);

Asynchronous Invocation  Locate

In asynchronous invocation, the client does not wait for the service response. It can continue independent computation until the response is received.

WSO2 SOA Enablement Server uses the callback mechanism for asynchrony. Callbacks are called by the service when the results are ready.

For more information and examples see Asynchronous Invocation.

Client Using SOAP Faults  Locate

If a service cannot correctly process an incoming SOAP message for any reason, the client gets back a response containing a SOAP Fault with information about the error. A SOAP message can carry one SOAP Fault element, which must be placed in the body of the message. In the SAAJ API, a SOAP fault is represented by the SOAPFault object. An overview of SOAPFault is given in SOAP Faults.

The code fragment in Example 92 demonstrates how a client accesses the SOAP fault element in a message:

Example 92. Accessing the SOAP Fault Element in a Message

SOAPBody body = message.getSOAPPart().getEnvelope().getBody();
if(body.hasFault()) {
  SOAPFault fault = body.getFault();
  String faultCode = fault.getFaultCode();
  String faultString = fault.getFaultString();
  String faultActor = fault.getFaultActor();
  Detail detail = fault.getDetail();
  if(detail != null) {
    Iterator iterator = detail.getDetailEntries();
    while (iterator.hasNext()) {
      DetailEntry detailEntry = (DetailEntry)iterator.next();
      String value = detailEntry.getValue();
    }
    //...
  }
}