Articles
Java Platform, Standard Edition
|
| By Sameer Tyagi, December 2005 |
|
| |
Part 1 and Part 2 of this series discussed different patterns and strategies for building Document-Based Web Services with Java Platform, Enterprise Edition (Java EE, formerly known as J2EE) technologies such as the Java API for XML-Based RPC (JAX-RPC) as well as how they can interoperate with Microsoft .NET technology.
This white paper, Part 3 of the series, will examine how to realize some of the same strategies with the Java API for XML-Based Web Services (JAX-WS) 2.0, a successor to JAX-RPC 1.1. JAX-WS 2.0 has been developed in the Java Community Process program through JSR 224 and extends JAX-RPC with new functionality as well as integration with Java Architecture for XML Binding (JAXB) 2.0 ( JSR 222). JAX-WS 2.0 is part of Java EE 5 as well as Java Platform, Standard Edition (Java SE) 6. It is available for download independently as well as through Project GlassFish, an open-source Java EE 5 application server.
To recap, the Document-Based Web Services pattern can be realized using the following eight strategies, each with its own advantages and disadvantages:
xsd:any element in WSDL
xsd:anyType in WSDL
Table 1 summarizes the various strategies for choosing a type to represent the XML documents being exchanged with a document-oriented web service. These topics are covered in detail in Part 1 as well as in the Java BluePrints Solutions Catalog. This white paper will further explore six of the eight strategies listed here. For information on using string in the SOAP body and using an external URI to reference the business document, see Part 1 and Part 2 of the series.
|
Table 1: Comparison of Various Strategies
|
|
|
Strategy
|
Advantages
|
Disadvantages
|
||
|---|---|---|---|---|
| |
||||
|
Using XML in the SOAP body
|
|
|
||
|
Using string in the SOAP body
|
|
|
||
|
Using base64-encoded or raw bytes in the SOAP body
|
|
|
||
|
Switching off data binding
|
|
|
||
|
Using the
xsd:any element in WSDL
|
|
|
||
|
Using the
xsd:anyType element in WSDL
|
|
|
||
|
Using an external URI to reference the business document
|
|
|
||
|
Using message attachments in the SOAP message
|
|
|
||
| |
||||
| |
In this strategy, the web service is deployed with document-literal formatting, and the XML document that needs to be exchanged is passed in the body of the SOAP message. When starting with WSDL, just as in
Part 1, we first generate the server-side code using a runtime-provided tool. In JAX-RPC, we used
wscompile. In JAX-WS 2.0, this has been replaced by a new tool called
wsimport, which is used to generate JAX-WS portable artifacts such as the following:
wsdl:fault and
soap:headerfault
wsdl:message
These artifacts can be packaged in a WAR file with the WSDL and schema documents, along with the endpoint implementation to be deployed. Code Sample 1 shows the Ant target used in the
sample code file
Doc-Literal-From-WSDL\build.xml.
Code Sample 1: Ant Target for Importing the WSDL
<!-- Generate the server bindings -->
<pre><target name="generate-server-from-wsdl" depends="init">
|
Unlike JAX-RPC, JAX-WS delegates the binding of schema types to JAXB 2.0. The
wsimport tool facilitates this by allowing a custom binding file to used in the configuration. Our configuration contains the following binding information, which allows the code generated by JAXB 2.0 to be generated in specifically named packages for the data types defined in the schemas.
Code Sample 2: Custom Configuration File Used With
wsimport
<jxb:bindings version="1.0"
xmlns:jxb=
http://java.sun.com/xml/ns/jaxb
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="wsdl/PurchaseOrder.xsd" node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="com.examples.types.po"/>
</jxb:schemaBindings>
</jxb:bindings>
<jxb:bindings schemaLocation="wsdl/PurchaseOrderStatus.xsd" node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="com.examples.types.postatus"/>
</jxb:schemaBindings>
</jxb:bindings>
<jxb:bindings schemaLocation="wsdl/POProcessingProblem.xsd" node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="com.examples.types.poproblem"/>
</jxb:schemaBindings>
</jxb:bindings>
|
With the generated code, we write our implementation class and annotate it using the
@WebService annotation, defined in
JSR 181. The
@WebService annotation and its attributes are used to specify the name of the web service, its service name, WSDL file location, and so on. In our case, we specify only the
endpointInterface attribute to point to the generated interface and leave all the attributes at the default values. The interface specified in the
endpointInterface is used to determine the abstract WSDL contract (
portType and bindings). With this annotation in place, the code is almost identical to what we used in
Code Sample 11 in Part 1 of this series.
Code Sample 3: Endpoint Implementation With Annotation
package com.examples.docliteral;
import java.rmi.RemoteException;
@javax.jws.WebService(endpointInterface="com.examples.docliteral.IPurchaseOrder")
public PurchaseOrderStatus acceptPO(PurchaseOrder order) throws ProcessingFault {
|
With the code now generated, we package everything into a WAR file along with the
web.xml shown in Code Sample 4. We will use the same
web.xml for subsequent examples as well. This
web.xml delegates the incoming requests to the JAX-WS runtime using a servlet and a listener.
Code Sample 4:
web.xml Descriptor
<?xml version="1.0" encoding="UTF-8"?>
|
The second descriptor is
sun-jaxws.xml, which defines the endpoints and contains implementation- or container-specific details about the specific endpoint. It is used by the runtime to determine what class to use to process the incoming requests. This descriptor is shown in Code Sample 5 and will also be reused for subsequent examples.
Code Sample 5: The
sun-jaxws.xml Descriptor
<?xml version="1.0" encoding="UTF-8"?>
|
| |
We can pass the document as XML in the SOAP body by starting with Java code also. JAX-WS uses the same JSR 181 annotations in the source code to mark the code as a web service. To process the annotations at compile time, JAX-WS uses the J2SE 5.0 annotation processing tool called Apt and ships with the corresponding Ant task. The Apt tool provides a facility for programmatically processing the annotations that
JSR 175 added to Java technology. In brief, JSR 175 allows programmers to declare new kinds of structured modifiers that can be associated with program elements, fields, methods, classes, and so on. The Apt tool generates the portable artifacts used in JAX-WS services. To build a web service from Java code, we simply add the
@WebService annotation shown in Code Sample 6 to the code from Part 1 and use the Ant task shown in Code Sample 7.
Code Sample 6: Service Implementation With Annotations
package com.examples.docliteral;
|
It is important when using
apt with JAX-WS to specify all of the JAR files in the distributed JAX-WS bundle in the class path passed to
apt. The
-sourcepath <path> option must also be provided so that
apt and the JAX-WS annotation processor can find all types referenced by a web service endpoint implementation class. For more information on the Apt tool, please refer to the
Apt documentation. The Ant task used to process the annotations and compile the code is shown in Code Sample 7.
Code Sample 7: Ant Task for Processing Java Code
<target name="build-server-java" depends="init">
|
| |
In this strategy, the XML document structure is either base64-encoded or passed as raw bytes to the endpoint. In Part 1, we used the
xsd:base64Binary data type to represent the XML document in the WSDL file. JAX-WS includes full support for SOAP Message Transmission Optimization Mechanism (MTOM), which is a W3C proposed recommendation for optimizing the transmission and wire format of SOAP messages. With MTOM and XML-Binary Optimized Packaging (XOP), data of this type are extracted from the SOAP message and placed in the MIME package. Code Sample 8 shows the WSDL extract with the
base64Binary type. This is similar to the string-based "hello world" example, because the endpoint doesn't really know what the contents of the payload are and they are not described by any schema definition.
Code Sample 8 shows the WSDL extract, and Code Sample 9 shows the SOAP request on the wire with the XML document referenced from the SOAP body with an
xop:Include. The complete example is available in the
sample code directory
RawBytes-MTOM.
Code Sample 8: WSDL Extract Showing
base64Binary Data Type
<types>
|
Code Sample 9: SOAP Message on the Wire Showing XOP and Multipart Packaging
POST /mtomservice-war/jaxws HTTP/1.1
Content-Length: 1763
SOAPAction: ""
Content-Type: Multipart/Related; type="application/xop+xml";
------=_Part_0_5525185.1133991209879
Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
<?xml version="1.0" ?>
<?xml version="1.0" encoding="UTF-8"?>
tns:PurchaseOrderDocument xmlns:tns="http://www.examples.com/types"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.examples.com/types PurchaseOrder.xsd">
<billTo>
<street>1 Main Street</street>
<city>Beverly Hills</city>
<state>CA</state>
<zipCode>90210</zipCode>
</billTo>
<createDate>2004-03-27T12:21:02.055-05:00</createDate>
<items>
<itemname>Copier Paper</itemname>
<price>10</price>
<quantity>2</quantity>
</items>
|
Because there is a performance cost involved in creating the MIME package, for smaller data sets, the cost may be more than the value of not having to base64-encode and decode the data. For flexibility, the JAX-WS implementation contains a configurable property that allows developers to set the threshold size in KB, with a default of 1 KB, after which the MTOM package is created for the
base64Binary data. The property can be set on the
BindingProvider, for example, by the following:
((BindingProvider) stub).getRequestContext().put( com.sun.xml.ws.developer.JAXWSProperties.MTOM_THRESHOLD_VALUE,0) |
| |
In this strategy, the explicit binding of Java types is turned off. Java service endpoint interfaces (SEIs) provide a high-level Java technology-centric abstraction that hides the details of converting between Java objects and their XML representations for use in XML-based messages. The
javax.xml.ws.Provider interface in JAX-WS offers a mechanism to endpoint implementations that want to work with the message level directly, rather than with their binding representation. In such implementations, the
invoke(Source source) method is invoked by the runtime for each web service invocation, and a
javax.xml.transform.Source object corresponding to the message representation is passed to it. Developers can choose whether the runtime should pass only the SOAP payload in this invocation or the entire SOAP message by marking up the code with the appropriate
javax.xml.ws.ServiceMode annotation. A
value=MESSAGE annotation indicates that the provider instance should receive and send entire protocol messages, that is, the entire SOAP message. If this annotation is omitted or used with
@ServiceMode(value=PAYLOAD), then the provider instance will receive and send message payloads only, that is, the contents of a SOAP
Body element.
Code Sample 10: Generic Endpoint Implementation With a Provider
package com.sun.demo; import org.w3c.dom.Node; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.ws.Provider; import javax.xml.ws.Service;
@javax.xml.ws.ServiceMode(value=Service.Mode.PAYLOAD)
@javax.xml.ws.WebServiceProvider(wsdlLocation="WEB-INF/wsdl/POService.wsdl")
public class PurchaseOrderService implements Provider<Source> {
public static void printNodeToConsole(Node n) {
|
Just as is true in the server side, the client can operate directly at the XML message level, rather than binding to objects. In JAX-WS, the
javax.xml.ws.Dispatch interface provides support for this mode of interaction. The
javax.xml.ws.Dispatch is a low-level API that allows clients to construct messages or message payloads as XML, but it requires developers to have an intimate knowledge of the desired message or payload structure. The
javax.xml.ws.Dispatch itself is a generic class that supports input and output of messages or message payloads of arbitrary types. It supports two usage modes, identified by the constants
javax.xml.ws.Service.Mode.MESSAGE and
javax.xml.ws.Service.Mode.PAYLOAD, respectively, which behave identically to the annotation we previously described for the server-side endpoint. Code Sample 11 shows the client for this strategy using the dispatch API.
Code Sample 11: Generic Client Implementation With the Dispatch API
public class DispatchClient {
|
xsd:any Element in WSDL
| |
In this strategy, the XML schemas or data types used in the WSDL messages are not explicitly defined. Instead, the generic wildcard type of
xsd:any is used to describe the data being passed back and forth without defining the contents of the complex types being used. The implementation with JAX-WS remains similar to that with JAX-RPC, except that the
xsd:any is no longer mapped to
javax.xml.soap.SOAPElement. Because JAXB 2.0 mappings are used, the Document Object Model (DOM) representation is still obtained, but it can be cast to a
org.w3c.dom.Element object instead. In our implementation, we also use the
javax.xml.ws.WebServiceContext interface, which makes it possible for the endpoint implementation to access contextual information pertaining to the request being served. The
javax.xml.ws.WebServiceContext itself is a
java.util.Map of entries, some of which are standardized using the key names shown in Table 2, and is used in Code Sample 12 to access the
ServletContext and then the file to use as a response. This is identical to what we did with JAX-RPC in
Code Sample 44 of Part 1 with its
createSOAPMessage method and the
javax.xml.rpc.server.ServletEndpointContext.
|
Table 2: Standard Properties in the
javax.xml.ws.handler.MessageContext
|
|
|
Standard Property Name
|
Property Description
|
|---|---|
|
|
The HTTP request headers. |
|
|
The HTTP request method. |
|
|
The HTTP response status code. |
|
|
The HTTP response headers. |
|
|
The map of attachments to a message; key is the MIME
|
|
|
The message direction: true for outbound messages, false for inbound. |
|
|
The servlet context object. |
|
|
The servlet request object. |
|
|
The servlet response object. |
|
|
The servlet session object. |
|
|
The input source for the WSDL document. |
|
|
The name of the WSDL interface (2.0) or port type (1.1). |
|
|
The name of the WSDL operation. |
|
|
The name of the WSDL port. |
|
|
The name of the WSDL service. |
Code Sample 12: Service Endpoint Implementation
@javax.jws.WebService(endpointInterface="com.examples.soapelement.IPurchaseOrder")
@javax.annotation.Resource javax.xml.ws.WebServiceContext ctx;
public BusinessDocumentReply acceptPO(BusinessDocumentRequest request)
try{
Element requestdata= (Element) request.getAny();
// Print the request to the console.
printNodeToConsole(requestdata);
Element replydata = createSOAPMessage("/Response.xml");
printNodeToConsole (replydata);
BusinessDocumentReply reply = new BusinessDocumentReply();
reply.setAny(replydata);
return reply;
}catch(Exception e){
BusinessDocumentFault bdf= new BusinessDocumentFault();
bdf.setAny(createExceptionXML("Web service could not construct a reply :" + e));
throw new POProcessingProblem("Exception in processing your request", bdf);
}
|
The client implementation is shown in Code Sample 13. It is much like
Code Sample 45 in Part 1, except that it uses the
org.w3c.dom.Element.
Code Sample 13: Client Implementation Sending an XML Document
public class WSDLClient {
POService serviceproxy = new POService();
IPurchaseOrder stub = serviceproxy.getIPurchaseOrderPort() ;
((BindingProvider) stub).getRequestContext().
|
xsd:anyType in WSDL
| |
In this strategy, the
xsd:anyType element is used to represent the XML fragment being passed to the endpoint. With JAX-WS 2.0, the code remains much like the code in Part 1 but with a few minor changes. First, the
@WebService annotation must be added to mark the class as an endpoint. Second, the generated interface no longer uses
javax.xml.soap.SOAPElement as method parameters and arguments but uses
java.lang.Object instead. As Code Sample 14 shows, the implementation class uses not the
javax.xml.soap.SOAPElement but the
org.w3c.dom.Element.
Code Sample 14: Service Endpoint Implementation Processing
xsd:anyType
@javax.jws.WebService(endpointInterface="com.examples.soapelement.IPurchaseOrder")
@javax.annotation.Resource
public Object acceptPO(Object request) throws POProcessingProblem{
if (request == null) {
throw new POProcessingProblem("Web service was passed a null purchase order",null);
}
|
| |
The WS-I Attachments Profile describes two separate attachment mechanisms, both based on use of the WSDL 1.1 MIME binding:
wsiap:swaRef is a schema type that may be used in the abstract message description to indicate a reference to an attachment.
mime:content is a binding construct that may be used to bind a message part to an attachment.
JAXB 2.0 defines a mapping between MIME types and Java types. In JAX-WS, when a message part is bound using one or more
mime:content elements in the WSDL and use of the additional metadata is enabled, then the JAXB mapping is customized to use the most specific type allowed by the set of MIME types described for the part in the binding. If the binding is not customized, it will use the default binding for the data types used in the WSDL.
The JAX-WS version of this strategy remains more or less same as the example in the
Attachments-From-WSDL directory in Part 1, a
downloadable zip archive. The endpoint implementation code for JAX-WS also remains unchanged from the JAX-RPC code in
Part 1's Code Sample 53 and also appears in this white paper in Code Sample 15. The MIME mappings used by JAXB remain the same and map to a
DataHandler and
Source object, respectively. We do need to add the
@WebService annotation to the implementation endpoint, as shown in Code Sample 15. What changes is the configuration. By default, JAXB will map the data types using its binding rules for data type in the WSDL -- in this case,
byte[], because the XML data type is binary (or
xsd:hexBinary). Additional metadata can be passed to JAXB that enables it to narrow this default mapping into a more meaningful representation for the endpoints to work with. To facilitate this, we specify in both the client and server configuration used by
wsimport that it should use the corresponding Java data type for the type defined in the
mime:content using the
jaxws:enableMIMEContent binding declaration, as shown in Code Sample 16. This declaration must be supported by all JAX-WS runtimes.
Code Sample 15: Service Endpoint Implementation Processing Attachments
@javax.jws.WebService(endpointInterface="com.examples.attachmentservice.IPurchaseOrder")
public String storeDocumentXML(Source dh, String filename) {
// Code not shown
}
}
|
Code Sample 16: Configuration Descriptor Enabling Binding of MIME Types
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings node="wsdl:definitions/wsdl:binding
|
Additionally, when using a combination of the switched-off data-binding strategy along with attachments, the attachment contents can be retrieved from the message context using the
javax.xml.ws.binding.attachments property. This represents a
Map<String,DataHandler> of attachments to a message, in which the key is a unique identifier for the attachment and the value is a
DataHandler for the attachment data.
| |
In this document, we have explored some of the new features of JAX-WS 2.0 and seen how some of the strategies discussed for the Document-Based Web Services pattern in Parts 1 and 2 of this series can be implemented using this new technology -- often with only minor modifications. You can download all the sample code discussed here, including WSDL and build scripts.
Part 4 of this series will explore the interoperability aspect of the same strategies with Microsoft’s Windows Communication Foundation (formerly code-named Indigo).
| |
| |
Sameer Tyagi is a senior staff engineer at Sun Microsystems. He remains focused on architecture, design, and implementation of large-scale enterprise applications with Java technology. Among his publications are industry periodicals and books on Java and Java EE technologies, as well as a blog.