20 Optimizing Binary Data Transmission
This chapter includes the following sections:
Optimizing Binary Data Transmission Optimization Using MTOM/XOP
SOAP Message Transmission Optimization Mechanism/XML-binary Optimized Packaging (MTOM/XOP) defines a method for optimizing the transmission of XML data of type xs:base64Binary
or xs:hexBinary
in SOAP messages. When the transport protocol is HTTP, Multipurpose Internet Mail Extension (MIME) attachments are used to carry that data while at the same time allowing both the sender and the receiver direct access to the XML data in the SOAP message without having to be aware that any MIME artifacts were used to marshal the base64Binary
or hexBinary
data.
The binary data optimization process involves the following steps:
-
Encode the binary data.
-
Remove the binary data from the SOAP envelope.
-
Compress the binary data.
-
Attach the binary data to the MIME package.
-
Add references to the MIME package in the SOAP envelope.
MTOM/XOP support is standard in JAX-WS via the use of JWS annotations. The MTOM specification does not require that, when MTOM is enabled, the web service runtime use XOP binary optimization when transmitting base64binary
or hexBinary
data. Rather, the specification allows the runtime to choose to do so. This is because in certain cases the runtime may decide that it is more efficient to send the binary data directly in the SOAP Message; an example of such a case is when transporting small amounts of data in which the overhead of conversion and transport consumes more resources than just inlining the data as is.
The following Java types are mapped to the base64Binary
XML data type, by default: javax.activation.DataHandler
, java.awt.Image
, and javax.xml.transform.Source
. The elements of type base64Binary
or hexBinary
are mapped to byte[]
, by default.
The following table summarizes the steps required to use MTOM/XOP to send base64Binary
or hexBinary
attachments.
Table 20-1 Steps to Use MTOM/XOP to Send Binary Data
# | Step | Description |
---|---|---|
1 |
Annotate the data types that you are going to use as an MTOM attachment. (Optional) |
Depending on your programming model, you can annotate your Java class or WSDL to define the content types that are used for sending binary data. This step is optional. By default, XML binary types are mapped to Java |
2 |
Enable MTOM on the web service. |
|
3 |
Enable MTOM on the client of the web service. |
|
4 |
Set the attachment threshold. |
Set the attachment threshold to specify when the |
5 |
(Optional) Enable HTTP chunking. |
Enable HTTP chunking to minimize excessive buffering on the client side during the processing of MTOM attachments. See Enabling HTTP Chunking. |
For more information see:
-
MTOM specification at
http://www.w3.org/TR/soap12-mtom
-
XOP specification at
http://www.w3.org/TR/xop10
Annotating the Data Types
Depending on your programming model, you can annotate your Java class or WSDL to define the MIME content types that are used for sending binary data. This step is optional.
The following table defines the mapping of MIME content types to Java types. In some cases, a default MIME type-to-Java type mapping exists. If no default exists, the MIME content types are mapped to DataHandler
.
Table 20-2 Mapping of MIME Content Types to Java Types
MIME Content Type | Java Type |
---|---|
image/gif |
java.awt.Image |
image/jpeg |
java.awt.Image |
text/plain |
java.lang.String |
text/xml or application/xml |
javax.xml.transform.Source |
*/* |
javax.activation.DataHandler |
The following sections describe how to annotate the data types based on whether you are starting from Java or WSDL.
Annotating the Data Types: Start From Java
When starting from Java, to define the content types that are used for sending binary data, annotate the field that holds the binary data using the @XmlMimeType
annotation.
The field that contains the binary data must be of type DataHandler
.
The following example shows how to annotate a field in the Java class that holds the binary data.
@WebMethod @Oneway public void dataUpload( @XmlMimeType("application/octet-stream") DataHandler data) { }
Annotating the Data Types: Start From WSDL
When starting from WSDL, to define the content types that are used for sending binary data, annotate the WSDL element of type xs:base64Binary
or xs:hexBinary
using one of the following attributes:
-
xmime:contentType
- Defines the content type of the element. -
xmime:expectedContentType
- Defines the range of media types that are acceptable for the binary data.
The following example maps the image
element of type base64binary
to image/gif
MIME type (which maps to the java.awt.Image
Java type).
<element name="image" type="base64Binary" xmime:expectedContentTypes="image/gif" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/>
Enabling MTOM on the Web Service
You can enable MTOM on the web service using an annotation or WS-Policy file, as described in the following sections:
Enabling MTOM on the Web Service Using Annotation
To enable MTOM in the web service, specify the @java.xml.ws.soap.MTOM
annotation on the service endpoint implementation class, as illustrated in the following example. Relevant code is shown in bold.
package examples.webservices.mtom;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.soap.MTOM;
@MTOM
@WebService(name="MtomPortType",
serviceName="MtomService",
targetNamespace="http://example.org")
public class MTOMImpl {
@WebMethod
public String echoBinaryAsString(byte[] bytes) {
return new String(bytes);
}
}
Enabling MTOM on the Web Services by Attaching a WS-Policy File
In addition to the @MTOM annotation, described in the previous section, support for MTOM/XOP in WebLogic JAX-WS web services is implemented using the pre-packaged WS-Policy file Mtom.xml
. WS-Policy files follow the WS-Policy specification, described at http://www.w3.org/TR/ws-policy
; this specification provides a general purpose model and XML syntax to describe and communicate the policies of a web service, in this case the use of MTOM/XOP to send binary data. The installation of the pre-packaged Mtom.xml
WS-Policy file in the types
section of the web service WSDL is as follows (provided for your information only; you cannot change this file):
<wsp:Policy wsu:Id="myService_policy"> <wsp:ExactlyOne> <wsp:All> <wsoma:OptimizedMimeSerialization xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization" /> </wsp:All> </wsp:ExactlyOne> </wsp:Policy>
When you deploy the compiled JWS file to WebLogic Server, the dynamic WSDL will automatically contain the following snippet that references the MTOM WS-Policy file; the snippet indicates that the web service uses MTOM/XOP:
<wsdl:binding name="BasicHttpBinding_IMtomTest" type="i0:IMtomTest"> <wsp:PolicyReference URI="#myService_policy" /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
You can associate the Mtom.xml
WS-Policy file with a web service at development-time by specifying the @Policy
metadata annotation in your JWS file. Be sure you also specify the attachToWsdl=true
attribute to ensure that the dynamic WSDL includes the required reference to the Mtom.xml
file; see the example below.
You can associate the Mtom.xml
WS-Policy file with a web service at deployment time by modifying the WSDL to add the Policy to the types section just before deployment.
In addition, you can attach the file at runtime using by the WebLogic Server Administration Console; for details, see Attach a WS-Policy file to a web service in the Oracle WebLogic Server Administration Console Online Help. This section describes how to use the JWS annotation.
The following simple JWS file example shows how to use the @weblogic.jws.Policy
annotation in your JWS file to specify that the pre-packaged Mtom.xml
file should be applied to your web service (relevant code shown in bold):
package examples.webservices.mtom; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.Policy; @WebService(name="MtomPortType", serviceName="MtomService", targetNamespace="http://example.org") @Policy(uri="policy:Mtom.xml", attachToWsdl=true) public class MtomImpl { @WebMethod public String echoBinaryAsString(byte[] bytes) { return new String(bytes); }
Enabling MTOM on the Client
To enable MTOM on the client of the web service, pass an instance of the javax.xml.ws.soap.MTOMFeature
as a parameter when creating the web service proxy or dispatch, as illustrated in the following example. Relevant code is shown in bold.
package examples.webservices.mtom.client;
import javax.xml.ws.soap.MTOMFeature;
public class Main {
public static void main(String[] args) {
String FOO = "FOO";
MtomService service = new MtomService()
MtomPortType port = service.getMtomPortTypePort(new MTOMFeature());
String result = null;
result = port.echoBinaryAsString(FOO.getBytes());
System.out.println( "Got result: " + result );
}
}
Setting the Attachment Threshold
You can set the attachment threshold to specify when the xs:binary64
data is sent inline or as an attachment. By default, the attachment threshold is 0 bytes. All xs:binary64
data is sent as an attachment.
To set the attachment threshold:
-
On the web service, pass the
threshold
attribute to the@java.xml.ws.soap.MTOM
annotation. For example:@MTOM(threshold=3072)
-
On the client of the web service, pass the threshold value to
javax.xml.ws.soap.MTOMFeature
. For example:MtomPortType port = service.getMtomPortTypePort(new MTOMFeature(3072));
In each of the examples above, if a message is greater than or equal to 3 KB, it will be sent as an attachment. Otherwise, the content will be sent inline, as part of the SOAP message body.
Enabling HTTP Chunking
You can minimize excessive buffering on the client side when processing MTOM attachments by enabling HTTP chunking on the transport layer using one of the following methods:
-
Set the
jaxws.transport.streaming
system property totrue
. In this case, no code modifications are required. -
Set
com.sun.xml.ws.developer.JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE
property on the protocol binding request context. For more information, see theJAXWSProperties
Javadoc at:https://www.javadoc.io/doc/com.sun.xml.ws/jaxws-rt/2.3.2/com.sun.xml.ws.jaxws/com/sun/xml/ws/developer/JAXWSProperties.html
.
It is recommended that you enable HTTP chunking for CPU-intensive applications that are running on a WebLogic Server instance that is participating in web services interactions as a client and is sending out large messages.
The following excerpt from an Ant build script shows an example of setting the system property when invoking a client application called clients.InvokeMTOMService
:
<target name="run-client"> <java fork="true" classname="clients.InvokeMTOMService" failonerror="true"> <classpath refid="client.class.path"/> <arg line="${http-endpoint}"/> <jvmarg line= "-Djaxws.transport.streaming=true" /> </java> </target>
The following code excerpt shows how to set the HTTP_CLIENT_STREAMING_CHUNK_SIZE
property.
package examples.webservices.mtomstreaming.client; import java.util.Map; import javax.xml.ws.BindingProvider; import com.sun.xml.ws.developer.JAXWSProperties; ... public class Main { public static void main(String[] args) { ... Map<String, Object> ctxt=((BindingProvider)port).getRequestContext(); ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); ... }
Streaming SOAP Attachments
Note:
The com.sun.xml.ws.developer.StreamingDataHandler
API is supported as an extension to the JAX-WS RI. Because this API is not provided as part of the WebLogic software, it is subject to change.
Using MTOM and the javax.activation.DataHandler
and com.sun.xml.ws.developer.StreamingDataHandler
APIs you can specify that a web service use a streaming API when reading inbound SOAP messages that include attachments, rather than the default behavior in which the service reads the entire message into memory. This feature increases the performance of web services whose SOAP messages are particularly large.
Note:
Streaming MTOM cannot be used in conjunction with message encryption.
The following sections describe how to employ streaming SOAP attachments on the client and server sides.
Client Side Example
The following provides an example that employs streaming SOAP attachments on the client side.
package examples.webservices.mtomstreaming.client; import java.util.Map; import java.io.InputStream; import javax.xml.ws.soap.MTOMFeature; import javax.activation.DataHandler; import javax.xml.ws.BindingProvider; import com.sun.xml.ws.developer.JAXWSProperties; import com.sun.xml.ws.developer.StreamingDataHandler; public class Main { public static void main(String[] args) { MtomStreamingService service = new MtomStreamingService(); MTOMFeature feature = new MTOMFeature(); MtomStreamingPortType port = service.getMtomStreamingPortTypePort( feature); Map<String, Object> ctxt=((BindingProvider)port).getRequestContext(); ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); DataHandler dh = new DataHandler(new FileDataSource("/tmp/example.jar")); port.fileUpload("/tmp/tmp.jar",dh); DataHandler dhn = port.fileDownload("/tmp/tmp.jar"); StreamingDataHandler sdh = (StreamingDataHandler)dhn; try{ File file = new File("/tmp/tmp.jar"); sdh.moveTo(file); sdh.close(); } catch(Exception e){ e.printStackTrace(); } } }
The preceding example demonstrates the following:
-
To enable MTOM on the client of the web service, pass an instance of the
javax.xml.ws.soap.MTOMFeature
as a parameter when creating the web service proxy or dispatch. -
Configure HTTP streaming support by enabling HTTP chunking on the MTOM streaming client. For more information, see Enabling HTTP Chunking.
Map<String, Object> ctxt = ((BindingProvider)port).getRequestContext(); ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
-
Call the
port.fileUpload
method. -
Cast the
DataHandler
toStreamingDataHandler
and use theStreamingDataHandler.readOnce()
method to read the attachment.
Server Side Example
The following provides an example that employs streaming SOAP attachments on the server side.
package examples.webservices.mtomstreaming; import java.io.File; import java.jws.Oneway; import javax.jws.WebMethod; import java.io.InputStream; import javax.jws.WebService; import javax.xml.bind.annotation.XmlMimeType; import javax.xml.ws.WebServiceException; import javax.xml.ws.soap.MTOM; import javax.activation.DataHandler; import javax.activation.FileDataSource; import com.sun.xml.ws.developer.StreamingAttachment; import com.sun.xml.ws.developer.StreamingDataHandler; @StreamingAttachment(parseEagerly=true, memoryThreshold=40000L) @MTOM @WebService(name="MtomStreaming", serviceName="MtomStreamingService", targetNamespace="http://example.org", wsdlLocation="StreamingImplService.wsdl") @Oneway @WebMethod public class StreamingImpl { // Use @XmlMimeType to map to DataHandler on the client side public void fileUpload(String fileName, @XmlMimeType("application/octet-stream") DataHandler data) { try { StreamingDataHandler dh = (StreamingDataHandler) data; File file = new File(fileName); dh.moveTo(file); dh.close(); } catch (Exception e) { throw new WebServiceException(e); } @XmlMimeType("application/octet-stream") @WebMethod public DataHandler fileDownload(String filename) { return new DataHandler(new FileDataSource(filename)); } }
The preceding example demonstrates the following:
-
The
@StreamingAttachement
annotation is used to configure the streaming SOAP attachment. For more information, see Configuring Streaming SOAP Attachments. -
The
@XmlMimeType
annotation is used to map theDataHandler
, as follows:-
If starting from WSDL, it is used to map the
xmime:expectedContentTypes="application/octet-stream"
toDataHandler
in the generated SEI. -
If starting from Java, it is used to generate an appropriate schema type in the generated WSDL.
-
-
Cast the
DataHandler
toStreamingDataHandler
and use theStreamingDataHandler.moveTo(File)
method to store the contents of the attachment to a file.
Configuring Streaming SOAP Attachments
You can configure streaming SOAP attachments on the client and server sides to specify the following:
-
Directory in which large attachments are stored.
-
Whether to parse eagerly the streaming attachments.
-
Maximum attachment size (bytes) that can be stored in memory. Attachments that exceed the specified number of bytes are written to a file.
Configuring Streaming SOAP Attachments on the Server
Note:
The com.sun.xml.ws.developer.StreamingAttachment
API is supported as an extension to the JDK 6.0. Because this API is not provided as part of the JDK 6.0 kit, it is subject to change.
To configure streaming SOAP attachments on the server, add the @StreamingAttachment
annotation on the endpoint implementation. The following example specifies that streaming attachments are to be parsed eagerly (read or write the complete attachment) and sets the memory threshold to 4MB. Attachments under 4MB are stored in memory.
... import com.sun.xml.ws.developer.StreamingAttachment; import javax.jws.WebService; @StreamingAttachment(parseEagerly=true, memoryThreshold=4000000L) @WebService(name="HelloWorldPortType", serviceName="HelloWorldService") public class StreamingImpl { }
Configuring Streaming SOAP Attachments on the Client
Note:
The com.sun.xml.ws.developer.StreamingAttachmentFeature
API is supported as an extension to the JDK 6.0. Because this API is not provided as part of the JDK 6.0 kit, it is subject to change.
To configure streaming SOAP attachments on the client, create a StreamingAttachmentFeature
object and pass this as an argument when creating the PortType
stub implementation. The following example sets the directory in which large attachments are stored to /tmp
, specifies that streaming attachments are to be parsed eagerly and sets the memory threshold to 4MB. Attachments under 4MB are stored in memory.
... import com.sun.xml.ws.developer.StreamingAttachmentFeature; ... MTOMFeature mtom = new MTOMFeature(); StreamingAttachmentFeature stf = new StreamingAttachmentFeature("/tmp", true, 4000000L); MtomStreamingService service = new MtomStreamingService(); MtomStreamingPortType port = service.getMtomStreamingPortTypePort( mtom, stf); ...
Sending SOAP Messages With Attachments Using swaRef
Together, the specifications defined in Table 20-3 define a mechanism for sending SOAP messages with attachments using the swaRef
XML attachment type.
Table 20-3 Specifications Supported for Sending SOAP Messages With Attachments
Specification | Description |
---|---|
SOAP With Attachments (SwA) |
Defines a MIME |
WS-I Attachments Profile |
Defines the JAXB maps the For more information, see: |
The following shows an example of how to use swaRef
in a WSDL file to specify that the claimForm
request and response messages be passed as an attachment.
Example 20-1 Example of WSDL File Using swaRef Data Type
<?xml version="1.0" encoding="utf-8"?> <wsdl:definitions name="SOAPBuilders-mime-cr-test" xmlns:types="http://example.org/mime/data" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://example.org/mime" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://example.org/mime"> <wsdl:types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.org/mime/data" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" elementFormDefault="qualified" xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd"> <import namespace="http://ws-i.org/profiles/basic/1.1/xsd" schemaLocation="WS-ISwA.xsd"/> . . . <complexType name="claimFormTypeRequest"> <sequence> <element name="request" type="ref:swaRef"/> </sequence> </complexType> <complexType name="claimFormTypeResponse"> <sequence> <element name="response" type="ref:swaRef"/> </sequence> </complexType> <element name="claimFormRequest" type="types:claimFormTypeRequest"/> <element name="claimFormResponse" type="types:claimFormTypeResponse"/> </schema> </wsdl:types> . . . <wsdl:message name="claimFormIn"> <wsdl:part name="data" element="types:claimFormRequest"/> </wsdl:message> <wsdl:message name="claimFormOut"> <wsdl:part name="data" element="types:claimFormResponse"/> </wsdl:message> . . . <wsdl:portType name="Hello"> . . . <wsdl:operation name="claimForm"> <wsdl:input message="tns:claimFormIn"/> <wsdl:output message="tns:claimFormOut"/> </wsdl:operation> </wsdl:portType> . . . </wsdl:definitions>
As specified in the WSDL example in Example 20-1, the XML content that is tagged as type swaRef
is sent as a MIME attachment and the element inside the SOAP body holds the reference to this attachment, as shown in Example 20-2.
Example 20-2 Example of SOAP Message with MIME Attachment
Content-Type: Multipart/Related; start-info="text/xml"; type="application/xop+xml"; boundary="----=_Part_4_32542424.1118953563492"Content-Length: 1193SOAPAction: "" ------=_Part_5_32550604.1118953563502Content-Type: application/xop+xml; type="text/xml"; charset=utf-8 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <request xmlns="http://example.org/mtom/data"> cid:b0a597fd-5ef7-4f0c-9d85-6666239f1d25@example.jaxws.sun.com </request> </soapenv:Body> </soapenv:Envelope> ------=_Part_5_32550604.1118953563502 Content-Type: application/xmlContent-ID: <b0a597fd-5ef7-4f0c-9d85-6666239f1d25@example.jaxws.sun.com> <?xml version="1.0" encoding="UTF-8"?><application xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocaption="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd" version="1.4"> <display-name>Simple example of application</display-name> <description>Simple example</description> <module> <ejb>ejb1.jar</ejb> </module> <module> <ejb>ejb2.jar</ejb> </module> <module> <web> <web-uri>web.war</web-uri> <context-root>web</context-root></web> </module></application>
Example 20-3 shows a sample web service that defines the claimForm
operation. As defined in the WSDL, the request and response messages are sent as MIME attachments.
Example 20-3 Example Web Service
package mime.server;
import javax.jws.WebService;
import javax.xml.ws.Holder;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.activation.DataHandler;
import java.awt.*;
import java.io.ByteArrayInputStream;
@WebService (endpointInterface = "mime.server.Hello")
public class HelloImpl {
...
public ClaimFormTypeResponse claimForm(ClaimFormTypeRequest data){
ClaimFormTypeResponse resp = new ClaimFormTypeResponse();
resp.setResponse(data.getRequest());
return resp;
}
...
}
Example 20-4 shows a sample web service client that calls the claimForm
operation. Note that the client request data that will be transmitted as an attachment is mapped to the DataHandler
data type.
Example 20-4 Example Web Service Client With MIME Attachments
package mime.client; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.Source; import javax.activation.DataHandler; import java.io.ByteArrayInputStream; import java.awt.*; public class MimeApp { public static void main (String[] args){ try { Object port = new HelloService().getHelloPort (); testSwaref ((Hello)port); } catch (Exception ex) { ex.printStackTrace (); } } private static void testSwaref (Hello port) throws Exception{ DataHandler claimForm = new DataHandler (new StreamSource( new ByteArrayInputStream(sampleXML.getBytes())), "text/xml"); ClaimFormTypeRequest req = new ClaimFormTypeRequest(); req.setRequest(claimForm); ClaimFormTypeResponse resp = port.claimForm (req); DataHandler out = resp.getResponse(); ... } private static final String sampleXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \n" + "<NMEAstd>\n" + "<DevIdSentenceId>$GPRMC</DevIdSentenceId>\n" + "<Time>212949</Time>\n" + "<Navigation>A</Navigation>\n" + "<NorthOrSouth>4915.61N</NorthOrSouth>\n" + "<WestOrEast>12310.55W</WestOrEast>\n" + "<SpeedOnGround>000.0</SpeedOnGround>\n" + "<Course>360.0</Course>\n" + "<Date>030904</Date>\n" + "<MagneticVariation>020.3</MagneticVariation>\n" + "<MagneticPoleEastOrWest>E</MagneticPoleEastOrWest>\n" + "<ChecksumInHex>*6B</ChecksumInHex>\n" + "</NMEAstd>"; }