24 Using Provider-based Endpoints and Dispatch Clients to Operate on SOAP Messages

This chapter describes how to develop web service provider-based endpoints and dispatch clients to operate on SOAP messages at the XML message level for WebLogic web services using Java API for XML Web Services (JAX-WS).

This chapter includes the following sections:

Overview of Web Service Provider-based Endpoints and Dispatch Clients

Although the use of JAXB-generated classes is simpler, faster, and likely to be less error prone, there are times when you may want to generate your own business logic to manipulate the XML message content directly. Message-level access can be accomplished on the server side using web service Provider-based endpoints, and on the client side using Dispatch clients.

A web service Provider-based endpoint offers a dynamic alternative to the Java service endpoint interface (SEI)-based endpoint. Unlike the SEI-based endpoint that abstracts the details of converting between Java objects and their XML representation, the Provider interface enables you to access the content directly at the XML message level—without the JAXB binding. web service Provider-based endpoints can be implemented synchronously or asynchronously using the javax.xml.ws.Provider<T> or com.sun.xml.ws.api.server.AsyncProvider<T> interfaces, respectively. For more information about developing web service Provider-based endpoints, see Developing a Web Service Provider-based Endpoint (Starting from Java).

A web service Dispatch client, implemented using the javax.xml.ws.Dispatch<T> interface, enables clients to work with messages at the XML level. The steps to develop a web service Dispatch client are described in Developing a Web Service Dispatch Client.

Provider endpoints and Dispatch clients can be used in combination with other WebLogic web services features as long as a WSDL is available, including:

  • WS-Security

  • WS-ReliableMessaging

  • WS-MakeConnection

  • WS-AtomicTransaction

In addition, Dispatch clients can be used in combination with the asynchronous client transport and asynchronous client handler features. These features are described in detail in Developing Asynchronous Clients, and a code example is provided in Creating a Dispatch Instance.

Usage Modes and Message Formats for Operating at the XML Level

When operating on messages at the XML level using Provider-based endpoints or Dispatch clients, you use one of the usage modes defined in the following table. You define the usage mode using the javax.xml.ws.ServiceMode annotation, as described in Specifying the Usage Mode (@ServiceMode Annotation).

Table 24-1 Usage Modes for Operating at the XML Message Level

Usage Mode Description

Message

Operates directly with the entire message. For example, if a SOAP binding is used, then the entire SOAP envelope is accessed.

Payload

Operates on the payload of a message only. For example, if a SOAP binding is used, then the SOAP body is accessed.

Provider-based endpoints and Dispatch clients can receive and send messages using one of the message formats defined in Table 24-2. This table also defines the valid message format and usage mode combinations based on the configured binding type (SOAP or XML over HTTP).

Table 24-2 Message Formats Supported for Operating at the XML Message Level

Message Format Usage Mode Support for SOAP/HTTP Binding Usage Mode Support for XML/HTTP Binding

javax.xml.transform.Source

Message mode: SOAP envelope

Payload mode: SOAP body

Message mode: XML content as Source

Payload mode: XML content as Source

javax.activation.DataSource

Not valid in either mode because attachments in SOAP/HTTP binding are sent using SOAPMessage format.

Message mode: DataSource object

Not valid in payload mode because DataSource is used for sending attachments.

javax.xml.soap.SOAPMessage

Message mode: SOAPMessage object

Not valid in payload mode because the entire SOAP message is received, not just the payload.

Not valid in either mode because the client can send a non-SOAP message in XML/HTTP binding.

Developing a Web Service Provider-based Endpoint (Starting from Java)

You can develop both synchronous and asynchronous web service Provider-based endpoints, as described in the following sections:

Note:

To start from WSDL and flag a port as a web service provider, see Developing a Web Service Provider-based Endpoint (Starting from WSDL).

Developing a Synchronous Provider-based Endpoint

A web service Provider-based endpoint, implemented using the javax.xml.ws.Provider<T>, enables you to access content directly at the XML message level—without the JAXB binding. The Provider interface processes messages synchronously—the service waits to process the response before continuing with its work. For more information about the javax.xml.ws.Provider<T> interface, see http://docs.oracle.com/javaee/7/api/javax/xml/ws/Provider.html.

The following procedure describes the typical steps for programming a JWS file that implements a synchronous web service Provider-based endpoint.

Table 24-3 Steps to Develop a Synchronous Web Service Provider-based Endpoint

# Step Description

1

Import the JWS annotations that will be used in your web service Provider-based JWS file.

The standard JWS annotations for a web service Provider-based JWS file include:

import javax.xml.ws.Provider;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.ServiceMode;

Import additional annotations, as required. For a complete list of JWS annotations that are supported, see Web Service Annotation Support in WebLogic Web Services Reference for Oracle WebLogic Server.

2

Specify one of the message formats supported, defined in Table 24-2, when developing the Provider-based implementation class.

See Specifying the Message Format.

3

Add the standard required @WebServiceProvider JWS annotation at the class level to specify that the Java class exposes a web service provider.

See Specifying that the JWS File Implements a Web Service Provider (@WebServiceProvider Annotation).

4

Add the standard @ServiceMode JWS annotation at the class level to specify whether the web service provider is accessing information at the message or message payload level. (Optional)

See Specifying the Usage Mode (@ServiceMode Annotation).

The service mode defaults to Service.Mode.Payload.

5

Define the invoke() method.

The invoke() method is called and provides the message or message payload as input to the method using the specified message format. See Defining the invoke() Method for a Synchronous Provider-based Endpoints.

The following sample JWS file shows how to implement a simple synchronous web service Provider-based endpoint. The steps to develop a synchronous web service Provider-based endpoint are described in detail in the sections that follow. To review the JWS file within the context of a complete sample, see "Creating JAX-WS Web Services for Java EE" in the Web Services Samples distributed with Oracle WebLogic Server.

Note:

RESTful Web Services can be built using XML/HTTP binding Provider-based endpoints. For an example of programming a Provider-based endpoint within the context of a RESTful web service, see Programming Web Services Using XML Over HTTP.

Example 24-1 Example of a JWS File that Implements a Synchronous Provider- based Endpoint

package examples.webservices.jaxws;
 
import org.w3c.dom.Node;
 
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.Service;
import java.io.ByteArrayInputStream;
 
 
/**
 * A simple Provider-based web service implementation.
 *
 * @author Copyright (c) 2010, Oracle and/or its affiliates. 
 * All Rights Reserved.
 */
// The @ServiceMode annotation specifies whether the Provider instance 
// receives entire messages or message payloads.
@ServiceMode(value = Service.Mode.PAYLOAD)

// Standard JWS annotation that configures the Provider-based web service.
@WebServiceProvider(portName = "SimpleClientPort",
    serviceName = "SimpleClientService",
    targetNamespace = "http://jaxws.webservices.examples/",
    wsdlLocation = "SimpleClientService.wsdl")
public class SimpleClientProviderImpl implements Provider<Source> {
 
  //Invokes an operation according to the contents of the request message.
  public Source invoke(Source source) {
    try {
      DOMResult dom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(source, dom);
      Node node = dom.getNode();
      // Get the operation name node.
      Node root = node.getFirstChild();
      // Get the parameter node.
      Node first = root.getFirstChild();
      String input = first.getFirstChild().getNodeValue();
      // Get the operation name.
      String op = root.getLocalName();
      if ("invokeNoTransaction".equals(op)) {
        return sendSource(input);
      } else {
        return sendSource2(input);
      }
    }
    catch (Exception e) {
      throw new RuntimeException("Error in provider endpoint", e);
    }
  }
 
  private Source sendSource(String input) {
    String body =
        "<ns:invokeNoTransactionResponse
             xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeNoTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
  private Source sendSource2(String input) {
    String body =
        "<ns:invokeTransactionResponse 
            xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
}

Developing an Asynchronous Provider-based Endpoint

As with the Provider interface, web service Provider-based endpoints implemented using the com.sun.xml.ws.api.server.AsyncProvider<T> interface enable you to access content directly at the XML message level—without the JAXB binding. However, the AsyncProvider interface processes messages asynchronously—the service can continue its work and process the request when it becomes available, without blocking the thread.

The following procedure describes the typical steps for programming a JWS file that implements an asynchronous web service Provider-based endpoint.

Table 24-4 Steps to Develop an Asynchronous Web Service Provider-based Endpoint

# Step Description

1

Import the JWS annotations that will be used in your web service Provider-based JWS file.

The standard JWS annotations for an asynchronous web service Provider-based JWS file include:

import com.sun.xml.ws.api.server.AsyncProvider;
import com.sun.xml.ws.api.server.AsyncProviderCallback;
import javax.xml.ws.ServiceMode;

Import additional annotations, as required. For a complete list of JWS annotations that are supported, see Web Service Annotation Support in WebLogic Web Services Reference for Oracle WebLogic Server.

2

Specify one of the message formats supported, defined in Table 24-2, when developing the Provider-based implementation class.

See Specifying the Message Format.

3

Add the standard required @WebServiceProvider JWS annotation at the class level to specify that the Java class exposes a web service provider.

See Specifying that the JWS File Implements a Web Service Provider (@WebServiceProvider Annotation).

4

Add the standard @ServiceMode JWS annotation at the class level to specify whether the web service provider is accessing information at the message or message payload level. (Optional)

See Specifying the Usage Mode (@ServiceMode Annotation).

The service mode defaults to Service.Mode.Payload.

5

Define the invoke() method.

The invoke() method is called and provides the message or message payload as input to the method using the specified message format. See Defining the invoke() Method for an Asynchronous Provider-based Endpoints.

6

Define the asynchronous handler callback method to handle the response.

The method handles the response when it is returned. See Defining the Callback Handler for the Asynchronous Provider-based Endpoint.

The following sample JWS file shows how to implement a simple asynchronous web service Provider-based endpoint. The steps to develop an asynchronous web service Provider-based endpoint are described in detail in the sections that follow.

Example 24-2 Example of a JWS File that Implements an Asynchronous Provider-based Endpoint

package asyncprovider.server;
 
import com.sun.xml.ws.api.server.AsyncProvider;
import com.sun.xml.ws.api.server.AsyncProviderCallback;
 
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceProvider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
 
@WebServiceProvider(
    wsdlLocation="WEB-INF/wsdl/hello_literal.wsdl",
    targetNamespace = "urn:test",
    serviceName="Hello")

public class HelloAsyncImpl implements AsyncProvider<Source> {
 
    private static final JAXBContext jaxbContext = createJAXBContext();
    private int bodyIndex;
 
    public javax.xml.bind.JAXBContext getJAXBContext(){
        return jaxbContext;
    }
    
    private static javax.xml.bind.JAXBContext createJAXBContext(){
        try{
            return javax.xml.bind.JAXBContext.newInstance(ObjectFactory.class);
        }catch(javax.xml.bind.JAXBException e){
            throw new WebServiceException(e.getMessage(), e);
        }
    }
 
    private Source sendSource() {
        System.out.println("**** sendSource ******");
 
        String[] body  = {
            "<HelloResponse xmlns=\"urn:test:types\">
              <argument xmlns=\"\">foo</argument>
              <extra xmlns=\"\">bar</extra>
             </HelloResponse>",
            "<ans1:HelloResponse xmlns:ans1=\"urn:test:types\">
               <argument>foo</argument>
               <extra>bar</extra>
             </ans1:HelloResponse>",
        };
        int i = (++bodyIndex)%body.length;
        return new StreamSource(
            new ByteArrayInputStream(body[i].getBytes()));
    }
 
    private Hello_Type recvBean(Source source) throws Exception {
        System.out.println("**** recvBean ******");
        return (Hello_Type)jaxbContext.createUnmarshaller().unmarshal(source);
    }
 
    private Source sendBean() throws Exception {
        System.out.println("**** sendBean ******");
        HelloResponse resp = new HelloResponse();
        resp.setArgument("foo");
        resp.setExtra("bar");
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        jaxbContext.createMarshaller().marshal(resp, bout);
        return new StreamSource(new ByteArrayInputStream(bout.toByteArray()));
    }
 
    public void invoke(Source source, AsyncProviderCallback<Source> cbak, 
                       WebServiceContext ctxt) {
        System.out.println("**** Received in AsyncProvider Impl ******");
        try {
             Hello_Type hello = recvBean(source);
             String arg = hello.getArgument();
             if (arg.equals("sync")) {
                 String extra = hello.getExtra();
                 if (extra.equals("source")) {
                        cbak.send(sendSource());
                 } else if (extra.equals("bean")) {
                        cbak.send(sendBean());
                 } else {
                        throw new WebServiceException("Expected extra =
                             (source|bean|fault), Got="+extra);
                 }
             } else if (arg.equals("async")) {
               new Thread(new RequestHandler(cbak, hello)).start();
             } else {
                throw new WebServiceException("Expected Argument = 
                  (sync|async), Got="+arg);
             }
        } catch(Exception e) {
          throw new WebServiceException("Endpoint failed", e);
        }
    }
 
    private class RequestHandler implements Runnable {
        final AsyncProviderCallback<Source> cbak;
        final Hello_Type hello;
        public RequestHandler(AsyncProviderCallback<Source> cbak, Hello_Type hello) {
            this.cbak = cbak;
            this.hello = hello;
        }
 
        public void run() {
            try {
                Thread.sleep(5000);
            } catch(InterruptedException ie) {
                  cbak.sendError(new WebServiceException("Interrupted..."));
                  return;
            }
            try {
                String extra = hello.getExtra();
                if (extra.equals("source")) {
                    cbak.send(sendSource());
                } else if (extra.equals("bean")) {
                    cbak.send(sendBean());
                } else {
                    cbak.sendError(new WebServiceException(
                     "Expected extra = (source|bean|fault), Got="+extra));
                }
           } catch(Exception e) {
                cbak.sendError(new WebServiceException(e));
           }
       }
    }
}

Specifying the Message Format

Specify one of the message formats supported, defined in Table 24-2, when developing the Provider-based implementation class.

For example, in the Provider implementation example shown in Example 24-1, the SimpleClientProviderImpl class implements the Provider<Source> interface, indicating that both the input and output types are java.xml.transform.Source objects.

public class SimpleClientProviderImpl implements Provider<Source> {
. . .
}

Similarly, in the AsyncProvider implementation example shown in Example 24-2, the HelloAsyncImpl class implements the AsyncProvider<Source> interface, indicating that both the input and output types are java.xml.transform.Source objects.

public class HelloAsyncImpl implements AsyncProvider<Source>  {
. . .
}

Specifying that the JWS File Implements a Web Service Provider (@WebServiceProvider Annotation)

Use the standard javax.xml.ws.WebServiceProvider annotation to specify, at the class level, that the JWS file implements a web service provider, as shown in the following code excerpt:

@WebServiceProvider(portName = "SimpleClientPort",
    serviceName = "SimpleClientService",
    targetNamespace = "http://jaxws.webservices.examples/",
    wsdlLocation = "SimpleClientService.wsdl")

In the example, the service name is SimpleClientService, which will map to the wsdl:service element in the generated WSDL file. The port name is SimpleClientPort, which will map to the wsdl:port element in the generated WSDL. The target namespace used in the generated WSDL is http://jaxws.webservices.examples/ and the WSDL location is local to the web service provider, at SimpleClientService.wsdl.

For more information about the @WebServiceProvider annotation, see https://jax-ws.java.net/nonav/2.1.5/docs/annotations.html.

Specifying the Usage Mode (@ServiceMode Annotation)

The javax.xml.ws.ServiceMode annotation is used to specify whether the web service Provider-based endpoint receives entire messages (Service.Mode.MESSAGE) or message payloads (Service.Mode.PAYLOAD) only.

For example:

@ServiceMode(value = Service.Mode.PAYLOAD)

If not specified, the @ServiceMode annotation defaults to Service.Mode.PAYLOAD.

For a list of valid message format and usage mode combinations, see Table 24-2.

For more information about the @ServiceMode annotation, see https://jax-ws.java.net/nonav/2.1.4/docs/annotations.html.

Defining the invoke() Method for a Synchronous Provider-based Endpoints

The Provider<T> interface defines a single method that you must define in your implementation class:

T invoke(T request)

When a web service request is received, the invoke() method is called and provides the message or message payload as input to the method using the specified message format.

For example, in the Provider implementation example shown in Example 24-1, excerpted below, the class defines an invoke method to take as input the Source parameter and return a Source response.

  public Source invoke(Source source) {
    try {
      DOMResult dom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(source, dom);
      Node node = dom.getNode();
      // Get the operation name node.
      Node root = node.getFirstChild();
      // Get the parameter node.
      Node first = root.getFirstChild();
      String input = first.getFirstChild().getNodeValue();
      // Get the operation name.
      String op = root.getLocalName();
      if ("invokeNoTransaction".equals(op)) {
        return sendSource(input);
      } else {
        return sendSource2(input);
      }
    }
    catch (Exception e) {
      throw new RuntimeException("Error in provider endpoint", e);
    }
  }

Defining the invoke() Method for an Asynchronous Provider-based Endpoints

The AsycnProvider<T> interface defines a single method that you must define in your implementation class:

void invoke(T request, AsyncProviderCallback<t> callback, WebserviceContext context))

You pass the following parameters to the invoke method:

  • Request message or message payload in the specified format.

  • com.sun.xml.ws.api.server.AsyncProviderCallback implementation that will handle the response once it is returned. For more information, see Defining the Callback Handler for the Asynchronous Provider-based Endpoint.

  • The javax.xml.ws.WebServiceContext that defines the message context for the request being served. An asynchronous Provider-based endpoint cannot use the injected WebServiceContext which relies on the calling thread to determine the request it should return information about. Instead, it passes the WebServiceContext object which remains usable until you invoke AsyncProviderCallback.

For example, in the AysncProvider implementation example shown in Example 24-2, excerpted below, the class defines an invoke method as shown below:

    public void invoke(Source source, AsyncProviderCallback<Source> cbak, 
                       WebServiceContext ctxt) {
        System.out.println("**** Received in AsyncProvider Impl ******");
        try {
             Hello_Type hello = recvBean(source);
             String arg = hello.getArgument();
             if (arg.equals("sync")) {
                 String extra = hello.getExtra();
                 if (extra.equals("source")) {
                        cbak.send(sendSource());
                 } else if (extra.equals("bean")) {
                        cbak.send(sendBean());
                 } else {
                        throw new WebServiceException("Expected extra =
                             (source|bean|fault), Got="+extra);
                 }
             } else if (arg.equals("async")) {
               new Thread(new RequestHandler(cbak, hello)).start();
             } else {
                throw new WebServiceException("Expected Argument = 
                  (sync|async), Got="+arg);
             }
        } catch(Exception e) {
          throw new WebServiceException("Endpoint failed", e);
        }
    }
 

Defining the Callback Handler for the Asynchronous Provider-based Endpoint

The AsyncProviderCallback interface enables you to define a callback handler for processing the asynchronous response once it is received.

For example, in the AysncProvider implementation example shown in Example 24-2, excerpted below, the RequestHandler method uses the AsyncProviderCallback callback handler to process the asynchronous response.

    private class RequestHandler implements Runnable {
        final AsyncProviderCallback<Source> cbak;
        final Hello_Type hello;
        public RequestHandler(AsyncProviderCallback<Source> cbak, Hello_Type hello) {
            this.cbak = cbak;
            this.hello = hello;
        }
 
        public void run() {
            try {
                Thread.sleep(5000);
            } catch(InterruptedException ie) {
                  cbak.sendError(new WebServiceException("Interrupted..."));
                  return;
            }
            try {
                String extra = hello.getExtra();
                if (extra.equals("source")) {
                    cbak.send(sendSource());
                } else if (extra.equals("bean")) {
                    cbak.send(sendBean());
                } else {
                    cbak.sendError(new WebServiceException(
                     "Expected extra = (source|bean|fault), Got="+extra));
                }
           } catch(Exception e) {
                cbak.sendError(new WebServiceException(e));
           }
       }
    }
}

Developing a Web Service Provider-based Endpoint (Starting from WSDL)

If the Provider-based endpoint is being generated from a WSDL file, the <provider> WSDL extension can be used to mark a port as a provider. For example:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<bindings wsdlLocation="SimpleClientService.wsdl" 
  xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="wsdl:definitions" > 
    <package name="provider.server"/>    
   <provider>true</provider>
</bindings>

Using SOAP Handlers with Provider-based Endpoints

Provider-based endpoints may need to access the SOAP message for additional processing of the message request or response. You can create SOAP message handlers to enable Provider-based endpoints to perform this additional processing on the SOAP message, just as you do for an SEI-based endpoint. For more information about creating the SOAP handler, see Creating the SOAP Message Handler.

Table 18-1 enumerates the steps required to add a SOAP handler to a web service. These steps apply to web service Provider-based endpoints, as well.

For example:

  1. Design SOAP message handlers and group them together in a handler chain, as described in Designing the SOAP Message Handlers and Handler Chains.
  2. For each handler in the handler chain, create a Java class that implements the SOAP message handler interface, as described in Creating the SOAP Message Handler.

    An example of the SOAP handler, MyHandler, is shown below.

    package provider.rootpart_charset_772.server; 
     
    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    import javax.xml.namespace.QName;
    import javax.xml.soap.AttachmentPart;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.WebServiceException;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import java.io.InputStream;
    import java.io.OutputStream;.import java.io.ByteArrayInputStream;
    import java.util.Set;
     
    public class MyHandler implements SOAPHandler<SOAPMessageContext> { 
       
        public Set<QName> getHeaders() {
            return null;     
        } 
        
        public boolean handleMessage(SOAPMessageContext smc) {
            if (!(Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY))            
                return true;
            try {
                SOAPMessage msg = smc.getMessage();
                AttachmentPart part = msg.createAttachmentPart(getDataHandler());           
                part.setContentId("SOAPTestHandler@example.jaxws.sun.com");             
                msg.addAttachmentPart(part);
                msg.saveChanges();
                smc.setMessage(msg);
            } catch (Exception e) {
                throw new WebServiceException(e);
            }
            return true;
        }
        
        public boolean handleFault(SOAPMessageContext context) {
            return true;
        } 
         
        public void close(MessageContext context) {}
        
        private DataHandler getDataHandler() throws Exception {
            return new DataHandler(new DataSource() {
                public String getContentType() {
                    return "text/xml";
                }
               
                public InputStream getInputStream() { 
                    return new ByteArrayInputStream("<a/>".getBytes());           
                }
                
                public String getName() {
                    return null; 
                }  
                
                public OutputStream getOutputStream() {
                    throw new UnsupportedOperationException();
                }
            }); 
        } 
    }
    
  3. Add the @javax.jws.HandlerChain annotation to the Provider implementation, as described in Configuring Handler Chains in the JWS File.

    For example:

    package provider.rootpart_charset_772.server;  
     
    import javax.jws.HandlerChain;
    import javax.xml.soap.MessageFactory;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.transform.Source;
    import javax.xml.transform.stream.StreamSource;
    import javax.xml.ws.*; 
    import java.io.ByteArrayInputStream;
     
    @WebServiceProvider(targetNamespace="urn:test", portName="HelloPort", serviceName="Hello")
    @ServiceMode(value=Service.Mode.MESSAGE)
    @HandlerChain(file="handlers.xml")
    public class SOAPMsgProvider implements Provider<SOAPMessage> { 
        
        public SOAPMessage invoke(SOAPMessage msg) {
            try {
        // keeping white space in the string is intentional
                String content = "<soapenv:Envelope
                    xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
                    <soapenv:Body>  <VoidTestResponse
                    xmlns=\"urn:test:types\">
                    </VoidTestResponse></soapenv:Body></soapenv:Envelope>";
                Source source = new StreamSource(new 
                    ByteArrayInputStream(content.getBytes()));
                MessageFactory fact = MessageFactory.newInstance();
                SOAPMessage soap = fact.createMessage();
                soap.getSOAPPart().setContent(source);
                soap.getMimeHeaders().addHeader("foo", "bar");
                return soap;
            } catch(Exception e) {
                throw new WebServiceException(e);
            }   
        }  
    }
    
  4. Create the handler chain configuration file, as described in Creating the Handler Chain Configuration File.

    An example of the handler chain configuration file, handlers.xml, is shown below.

    <handler-chains xmlns='http://java.sun.com/xml/ns/javaee'>  
       <handler-chain>    
          <handler>      
             <handler-name>MyHandler</handler-name>      
             <handler-class>
                 provider.rootpart_charset_772.server.MyHandler
             </handler-class> 
          </handler>   
       </handler-chain>
    </handler-chains>
    
  5. Compile all handler classes in the handler chain and rebuild your web service, as described in Compiling and Rebuilding the Web Service.

Developing a Web Service Dispatch Client

A web service Dispatch client, implemented using the javax.xml.ws.Dispatch<T> interface, enables clients to work with messages at the XML level.

The following procedure describes the typical steps for programming a web service Dispatch client.

Table 24-5 Steps to Develop a Web Service Provider-based Endpoint

# Step Description

1

Import the JWS annotations that will be used in your web service Provider-based JWS file.

The standard JWS annotations for a web service Provider-based JWS file include:

import javax.xml.ws.Service;
import javax.xml.ws.Dispatch;
import javax.xml.ws.ServiceMode;

Import additional annotations, as required. For a complete list of JWS annotations that are supported, see Web Service Annotation Support in WebLogic Web Services Reference for Oracle WebLogic Server.

2

Create a Dispatch instance.

See Creating a Dispatch Instance.

3

Invoke a web service operation.

You can invoke a web service operation synchronously (one-way or two-way) or asynchronously (polling or asynchronous handler). See Invoking a Web Service Operation.

Example of a Web Service Dispatch Client

The following sample shows how to implement a basic web service Dispatch client. The sample is described in detail in the sections that follow.

Example 24-3 Example of a Web Service Dispatch Client

package jaxws.dispatch.client;
 
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.URL;
 
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.ws.soap.SOAPBinding;
 
public class WebTest extends TestCase {
   private static String in_str = "wiseking";
   private static String request = 
      "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
 
   private static final QName portQName = new QName("http://example.org", "SimplePort");
   private Service service = null;

   protected void setUp() throws Exception {
 
      String url_str = System.getProperty("wsdl");
      URL url = new URL(url_str);
      QName serviceName = new QName("http://example.org", "SimpleImplService");
      service = Service.create(serviceName);
      service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
      System.out.println("Setup complete.");
 
   }
 
   public void testSayHelloSource() throws Exception {
      setUp();
      Dispatch<Source> sourceDispatch = 
         service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
      System.out.println("\nInvoking xml request: " + request);
      Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
      String xmlResult = sourceToXMLString(result);
      System.out.println("Received xml response: " + xmlResult);
      assertTrue(xmlResult.indexOf("HELLO:"+in_str)>=0);
   }
 
   private String sourceToXMLString(Source result) {
      String xmlResult = null;
      try {
         TransformerFactory factory = TransformerFactory.newInstance();
         Transformer transformer = factory.newTransformer();
         transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         transformer.setOutputProperty(OutputKeys.METHOD, "xml");
         OutputStream out = new ByteArrayOutputStream();
         StreamResult streamResult = new StreamResult();
         streamResult.setOutputStream(out);
         transformer.transform(result, streamResult);
         xmlResult = streamResult.getOutputStream().toString();
      } catch (TransformerException e) {
         e.printStackTrace();
      }
      return xmlResult;
   }
 
}

Creating a Dispatch Instance

The javax.xml.ws.Service interface acts as a factory for the creation of Dispatch instances. So to create a Dispatch instance, you must first create a Service instance. Then, create the Dispatch instance using the Service.createDispatch() method.

You can pass one or more of the following parameters to the createDispatch() method:

  • Qualified name (QName) or endpoint reference of the target service endpoint.

  • Class of the type parameter T. In this example, the javax.xml.transform.Source format is used. For valid values, see Table 24-2.

  • Usage mode. In this example, the message payload is specified. For valid usage modes, see Table 24-1.

  • A list of web service features to configure on the proxy.

  • JAXB context used to marshal or unmarshal messages or message payloads.

For more information about the valid parameters that can be used to call the Service.createDispatch() method, see the javax.xml.ws.Service Javadoc at: https://jax-ws.java.net/nonav/2.1.1/docs/api/javax/xml/ws/Service.html.

For example:

...
      String url_str = System.getProperty("wsdl");
      QName serviceName = new QName("http://example.org", "SimpleImplService");
      service = Service.create(serviceName);
      service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
      Dispatch<Source> sourceDispatch = 
        service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
...

In the example above, the createDispatch() method takes three parameters:

  • Qualified name (QName) of the target service endpoint.

  • Class of the type parameter T. In this example, the javax.xml.transform.Source format is used. For valid values, see Table 24-2.

  • Usage mode. In this example, the message payload is specified. For valid usage modes, see Table 24-1.

The following example shows how to pass a list of web service features, specifically the asynchronous client transport feature and asynchronous client handler feature. For more information about these features, see Developing Asynchronous Clients.

...
  protected Dispatch createDispatch(boolean isSoap12, Class dateType,
               Service.Mode mode, AsyncClientHandlerFeature feature) 
               throws Exception {
    String address = publishEndpoint(isSoap12);
    Service service = Service.create(new URL(address + "?wsdl"), 
               new QName("http://example.org", "AddNumbersService"));
    QName portName = new QName("http://example.org", "AddNumbersPort");
    AsyncClientTransportFeature transportFeature = new
         AsyncClientTransportFeature("http://localhost:8238/clientsoap12/" + 
               UUID.randomUUID().toString());
    Dispatch dispatch = service.createDispatch(portName, dateType, mode, 
         feature, transportFeature);
    return dispatch;
  }
...

Invoking a Web Service Operation

Once the Dispatch instance is created, use it to invoke a web service operation. You can invoke a web service operation synchronously (one-way or two-way) or asynchronously (polling or asynchronous handler). For complete details about the synchronous and asynchronous invoke methods, see the javax.xml.ws.Dispatch Javadoc at: https://jax-ws.java.net/nonav/2.1.1/docs/api/javax/xml/ws/Dispatch.html

For example, in the following code excerpt, the XML message is encapsulated as a javax.xml.transform.stream.StreamSource object and passed to the synchronous invoke() method. The response XML is returned in the result variable as a Source object, and transformed back to XML. The sourcetoXMLString() method used to transform the message back to XML is shown in Example 24-3.

...
private static String request = "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
String xmlResult = sourceToXMLString(result);
...