This chapter describes how to develop Web service provider-based endpoints and dispatch clients to operate 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
Usage Modes and Message Formats for Operating at the XML Level
Developing a Web Service Provider-based Endpoint (Starting from Java)
Developing a Web Service Provider-based Endpoint (Starting from WSDL)
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 Chapter 4, "Invoking Web Services Asynchronously," and a code example is provided in Creating a Dispatch Instance.
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 19-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 19-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 19-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 |
---|---|---|
|
Message mode: SOAP envelope Payload mode: SOAP body |
Message mode: XML content as Payload mode: XML content as |
|
Not valid in either mode because attachments in SOAP/HTTP binding are sent using |
Message mode: Not valid in payload mode because |
|
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. |
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).
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://download.oracle.com/javaee/5/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 19-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 19-2, when developing the Provider-based implementation class. |
|
3 |
Add the standard required |
See Specifying that the JWS File Implements a Web Service Provider (@WebServiceProvider Annotation). |
4 |
Add the standard |
See Specifying the Usage Mode (@ServiceMode Annotation). The service mode defaults to |
5 |
Define the |
The |
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 19-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; } }
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 19-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 19-2, when developing the Provider-based implementation class. |
|
3 |
Add the standard required |
See Specifying that the JWS File Implements a Web Service Provider (@WebServiceProvider Annotation). |
4 |
Add the standard |
See Specifying the Usage Mode (@ServiceMode Annotation). The service mode defaults to |
5 |
Define the |
The |
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 19-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)); } } } }
Specify one of the message formats supported, defined in Table 19-2, when developing the Provider-based implementation class.
For example, in the Provider implementation example shown in Example 19-1, "Example of a JWS File that Implements a Synchronous Provider- based Endpoint", 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 19-2, "Example of a JWS File that Implements an Asynchronous Provider-based Endpoint", 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> { . . . }
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 http://docs.oracle.com/javaee/5/api/javax/xml/ws/WebServiceProvider.html
.
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 19-2.
For more information about the @ServiceMode
annotation, see http://docs.oracle.com/javaee/5/api/javax/xml/ws/ServiceMode.html
.
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 of a JWS File that Implements a Synchronous Provider- based Endpoint, 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); } }
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 19-2, "Example of a JWS File that Implements an Asynchronous Provider-based Endpoint", 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); } }
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 19-2, "Example of a JWS File that Implements an Asynchronous Provider-based Endpoint", 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)); } } } }
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>
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 17-1, "Steps to Add SOAP Message Handlers to a Web Service" 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:
Design SOAP message handlers and group them together in a handler chain, as described in Designing the SOAP Message Handlers and Handler Chains..
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(); } }); } }
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); } } }
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>
Compile all handler classes in the handler chain and rebuild your Web service, as described in Compiling and Rebuilding the Web Service..
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 19-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 |
|
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. |
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 19-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; } }
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 19-2.
Usage mode. In this example, the message payload is specified. For valid usage modes, see Table 19-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: http://docs.oracle.com/javaee/5/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 19-2.
Usage mode. In this example, the message payload is specified. For valid usage modes, see Table 19-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 Chapter 4, "Invoking Web Services Asynchronously."
... 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; } ...
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: http://docs.oracle.com/javaee/5/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 19-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); ...