![]() | |
|
MTOM (Message Transmission and Optimization Mechanism) together with XOP (XML Binary Optimized Packaging) defines how an XML binary data such as xs:base64Binary or xs:hexBinary can be optimally transmitted over the wire.
XML type, such as xs:base64Binary is sent in lined inside the SOAP envelope. This gets quite in-efficient when the data size is more, for example a SOAP endpoint that exchanges images/songs etc. MTOM specifies how XOP packaging can be used to send the binary data optimally.
MTOM feature is disabled in JAX-WS by default. It can be enabled on the client and server. Once enabled all the XML binary data, XML elements of type xs:base64Binary and xs:hexBinary is optimally transmitted.
An schema element of type xs:bas64Binary or xs:hexBinary can be annotated by using attribute reference using xmime:expectedContentType. JAXB 2.0 specification defines xmime:expectedContentType to Java type mapping:
image/gif java.awt.Image image/jpg java.awt.Image text/plain java.lang.String text/xml javax.xml.transform.Source application/xml javax.xml.transform.Source multipart/* javax.activation.DataHandler all other types javax.activation.DataHandler
<element name="image" type="base64Binary" />is mapped to:
byte[]
<element name="image" type="base64Binary" xmime:expectedContentTypes="image/jpeg" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/>is mapped to:
java.awt.Image
How to enable MTOM in JAX-WS 2.0
Enabling MTOM on Server
Enable using @javax.xml.ws.soap.MTOM annotation on the endpoint (SEI) implementation class:
@javax.xml.ws.soap.MTOM @WebService (endpointInterface = "mtom.server.Hello") public class HelloImpl implements Hello { .... }
MTOM can be also be enabled on an endpoint by specifying enable-mtom attribute to true on an endpoint element in sun-jaxws.xml deployment descriptor:
<?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'> <endpoint name="Mtom" implementation="mtom.server.HelloImpl" url-pattern="/hello" enable-mtom="true"/> </endpoints>
Enable using @BindingType on the endpoint (SEI) implementation class:
@BindingType(value=javax.xml.ws.SOAPBinding.SOAP11HTTP_MTOM_BINDING) will enable MTOM on the deployed endpoint for SOAP 1.1 binding.
@BindingType(value=javax.xml.ws.SOAPBinding.SOAP12HTTP_MTOM_BINDING) will enable MTOM on the deployed endpoint for SOAP 1.2 binding.
Enabling MTOM on Client
To enable MTOM on client-side, pass javax.xml.ws.soap.MTOMFeature as WebServiceFeature parameter while crating the Proxy or Dispatch. Here is the code snippet from the client MtomApp.java of the MTOM sample:
Hello port = new HelloService().getHelloPort(new MTOMFeature()); - gives a proxy with MTOM enabled.
javax.xml.ws.Service.createDispatch( .... ,new MTOMFeature()); - gives a Dispatch instance with MTOM enabled.
JAX-WS 2.0 specification has defined API to enable and to check if the MTOM is enabled.
javax.xml.ws.soap.SOAPBinding.setMTOMEnabled(boolean enable) - enable or disable MTOM.
javax.xml.ws.soap.SOAPBinding.isMTOMEnabled() - returns true if MTOM is enabled otherwise false.
Hello port = new HelloService.getHelloPort(); //get the binding and enable mtom SOAPBinding binding = (SOAPBinding)((BindingProvider)port).getBinding(); boolean mtomEnabled = binding.isMTOMEnabled(); binding.setMTOMEnabled(true);
As defined by JAXB 2.0 specification xs:base64Binary and xs:hexBinary mapping to java is byte[]. JAXWS implementation has set a threshold of 1KB of byte[] size. This threshold can be modified using implementation specific property com.sun.xml.ws.developer.JAXWSProperties.MTOM_THRESHOLD_VALUE in the RequestContext on the client side and in the MessageContext on the server side.
If the byte[] that is being sent is less than this threshold (default is 1KB) then the binary data is base64 encoded by JAXB and in lined inside the SOAP Body otherwise the binary data is sent as attachment mime part in Multipart/Related package and XML infoset for the binary data is XOP encoded by JAXB - <xop:Include href=...> is used to reference the attachment. The XOP encoding and packaging is done as per described by the XOP packaging rules. The href is the the Content-ID of the attachment and is encoded as per CID URI scheme defined in RFC 2111. xmime:contentType attribute may appear on the element that includes binary data to indicate preferred media type as annotated on the corresponding schema.
What is MTOM
Perhaps the best way to understand the pros and cons of MTOM is to see an actual on-the-wire message. See an example below:
Content-Type: Multipart/Related; start-info="text/xml"; type="application/xop+xml"; boundary="----=_Part_0_1744155.1118953559416" Content-Length: 3453 SOAPAction: "" ------=_Part_1_4558657.1118953559446 Content-Type: application/xop+xml; type="text/xml"; charset=utf-8 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <Detail xmlns="http://example.org/mtom/data"> <image> <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:5aeaa450-17f0-4484-b845-a8480c363444@example.org" /> </image> </Detail> </S:Body> </S:Envelope> ------=_Part_1_4558657.1118953559446 Content-Type: image/jpeg Content-ID: <5aeaa450-17f0-4484-b845-a8480c363444@example.org> ... binary data ...
The noteworthy points are:
The binary attachment is packaged in a MIME multi-part message (the same mechanism used in e-mail to handle attachments).
An xop:Include element is used to mark where the binary data is.
The actual binary data is kept in a different MIME part.
MTOM is efficient, in the sense that it doesn't have the 33% size increase penalty that xs:base64Binary has. It is interoperable, in the sense that it is a W3C standard. However, MIME multipart incurs a small cost proportional to the number of attachments, so it is not suitable for a large number of tiny attachments.
Schema:
<element name="Detail" type="types:DetailType"/> <complexType name="DetailType"> <sequence> <element name="image" type="base64Binary" /> </sequence> </complexType>
JAX-WS and MTOM example
JAX-WS MTOM WSDL:
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://attachment.tip/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://attachment.tip/"> <types/> <message name="sendImage"> <part name="image" type="xsd:base64Binary"/> </message> <message name="sendImageResponse"/> <message name="sendOctet"> <part name="octet" type="xsd:base64Binary"/> </message> <message name="sendOctetResponse"/> <portType name="AttachmentTip"> <operation name="sendImage"> <input message="tns:sendImage"/> <output message="tns:sendImageResponse"/> </operation> <operation name="sendOctet"> <input message="tns:sendOctet"/> <output message="tns:sendOctetResponse"/> </operation> </portType> <binding name="AttachmentBinding" type="tns:AttachmentTip"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="sendImage"> <soap:operation soapAction=""/> <input> <soap:body namespace="http://attachment.tip/" use="literal"/> </input> <output> <soap:body namespace="http://attachment.tip/" use="literal"/> </output> </operation> <operation name="sendOctet"> <soap:operation soapAction=""/> <input> <soap:body namespace="http://attachment.tip/" use="literal"/> </input> <output> <soap:body namespace="http://attachment.tip/" use="literal"/> </output> </operation> </binding> <service name="AttachmentService"> <port binding="tns:AttachmentBinding" name="AttachmentTip"> <soap:address location="http://localhost:9080/MTOMService/services/AttachmentTip"/> </port> </service> </definitions>
The MTOM binding contains no MIME information. In fact, there's no way to tell, from the WSDL, that you're dealing with attachments; the WSDL's binding looks like a normal binding.
JAX-WS MTOM Java interface:
package tip.attachment; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; @WebService(name = "AttachmentTip", targetNamespace = "http://attachment.tip/") @SOAPBinding(style = SOAPBinding.Style.RPC) public interface AttachmentTip { @WebMethod public void sendImage( @WebParam(name = "image", partName = "image") byte[] image ); @WebMethod public void sendOctet( @WebParam(name = "octet", partName = "octet") byte[] octet ); }
Because the WSDL is a normal-looking WSDL with no hint of attachments, you end up with a Java interface that reflects that as well. Given parts of type base64Binary (or hexBinary), JAX-WS maps those to parameters of type byte[]. With MTOM, the MIME-ness of the types has all been extracted from the WSDL with the burden placed on the client or server run time to format the content appropriately.
The interface portion of both WSDLs shows that the data type in the operations is base64Binary, which maps to byte[]. In the JAX-RPC Sw/A WSDL, however, you know from the binding that the part types are a MIME image and a MIME octet stream. In the JAX-WS MTOM WSDL, this information is lost. This may seem like a bad thing, but the positive spin is that this completely cleans up the interface. No matter what the binding, the interface is always the same. In fact, the implementors of the client and the server codebases shouldn't be bothered with the notion of whether the parameter is an attachment. That's merely a detail of the SOAP message, and the writers of the WSDL-to-Java mappings have tried their best to abstract the programmer away from the details of the SOAP message.
However, if you really want to know what the MIME type is - if you want to get back to the information you lost - JAX-WS provides support for an attribute that you can inject into an XML element: expectedContentTypes.
JAX-WS MIME attribute:
<definitions ...> <types> <xsd:schema xmlns:tns="http://attachment.tip/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://attachment.tip/"> <xsd:element name="sendImage" type="tns:sendImage"/> <xsd:complexType name="sendImage"> <xsd:sequence> <xsd:element xmlns:ns1="http://www.w3.org/2005/05/xmlmime" ns1:expectedContentTypes="image/*" name="image" type="xsd:base64Binary"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendImageResponse" type="tns:sendImageResponse"/> <xsd:complexType name="sendImageResponse"> <xsd:sequence/> </xsd:complexType> <xsd:element name="sendOctet" type="tns:sendOctet"/> <xsd:complexType name="sendOctet"> <xsd:sequence> <xsd:element xmlns:ns1="http://www.w3.org/2005/05/xmlmime" ns1:expectedContentTypes="application/octet-stream" name="octet" type="xsd:base64Binary"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendOctetResponse" type="tns:sendOctetResponse"/> <xsd:complexType name="sendOctetResponse"> <xsd:sequence/> </xsd:complexType> </xsd:schema> </types> ... </definitions>
JAX-WS Java interface mapped from the MIME attribute:
package tip.attachment; import java.awt.Image; import javax.activation.DataHandler; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import javax.xml.ws.RequestWrapper; import javax.xml.ws.ResponseWrapper; @WebService(name = "AttachmentTip", targetNamespace = "http://attachment.tip/") public interface AttachmentTip { @WebMethod @RequestWrapper(localName = "sendImage", targetNamespace = "http://attachment.tip/", className = "tip.attachment.SendImage") @ResponseWrapper(localName = "sendImageResponse", targetNamespace = "http://attachment.tip/", className = "tip.attachment.SendImageResponse") public void sendImage( @WebParam(name = "image", targetNamespace = "") Image image ); @WebMethod @RequestWrapper(localName = "sendOctet", targetNamespace = "http://attachment.tip/", className = "tip.attachment.SendOctet") @ResponseWrapper(localName = "sendOctetResponse", targetNamespace = "http://attachment.tip/", className = "tip.attachment.SendOctetResponse") public void sendOctet( @WebParam(name = "octet", targetNamespace = "") DataHandler octet ); }
One of the of additional benefits of MTOM is the fact that you can turn it on or off. In the case of Sw/A, if one side or the other doesn't support sending Sw/A attachments, then the contract defined by the WSDL cannot be honored. On the other hand, a client could choose to send data as an MTOM attachment or inline in the SOAP message. No matter what the client chooses, it can still interact with the Web service. MTOM is just an optimization of sending content, not a mandate like Sw/A.
JAX-WS still supports the Sw/A model. By default, JAX-WS maps a Sw/A attachment to a byte[] on the Java interface. To get the mapping you are used to in JAX-RPC, you can use the enableMIMEContent WSDL binding definition. Listing below shows the JAX-WS version of the Java interface.
![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() |