Apache CXF e MTOM

Veja neste artigo um mecanismo eficiente de envio de dados binários a Webservices conhecido por MTOM (Message Transmission Optimization Mechanism) e XOP (XML-Binary Optimization Packaging) e como é o suporte a eles dentro do Apache CXF.

Nesse artigo vamos examinar um mecanismo eficiente de envio de dados binários a Webservices conhecido por MTOM (Message Transmission Optimization Mechanism) e XOP (XML-Binary Optimization Packaging) e como é o suporte a essa funcionalidade dentro do framework Apache CXF.

Figura 1. Processamento utilizando MTOM

Se você olhar as informações sobre MTOM no site do W3C pode ficar realmente confuso com a quantidade de especificações e documentações. Mas como sempre, basta dar uma olhada com calma para perceber que é mais simples do que parece. Resumidamente, vamos identificar as 3 especificações que definem o que é MTOM e como ele deve funcionar:

Agora ficou fácil demais! Fica claro que os profissionais do W3C se preocuparam em criar definições cujas implementações pudessem ser evoluídas com o tempo, em novos protocolos ou formatos mais otimizados daí essa separação em várias camadas.

Agora vamos ver o que o framework Apache CXF tem para nós com relação ao MTOM. Para maiores detalhes, vale a pena dar uma olhada nessa página.

Antes de mais nada, vamos definir o nosso WebService utilizando JAX-WS.

package br.com.devmedia.helloworldservice; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.soap.MTOM; @WebService(targetNamespace = HelloService.NS) @MTOM(enabled=true) @org.apache.cxf.interceptor.InInterceptors(interceptors = { "org.apache.cxf.interceptor.LoggingInInterceptor" }) @org.apache.cxf.interceptor.OutInterceptors(interceptors = { "org.apache.cxf.interceptor.LoggingOutInterceptor" }) public interface HelloService { String NS = "http://devmedia.sayhello"; @WebResult(name = "response") public abstract PersonInfo digaOla(PersonInfo info) ; }
Listagem 1. Serviço utilizando suporte MTOM

A primeira coisa que nos chama a atenção é a anotação MTOM. Ao adiciona-la, informamos ao Apache CXF que esse serviço suporta o uso do padrão. Na nossa operação digaOla, recebemos um objeto complexo por parâmetro do tipo PersonInfo. É esse objeto que encapsula as informações binárias. Vamos ver como isso é implementado utilizando o JAXB (listagem 2).

import javax.activation.DataHandler; import javax.xml.bind.annotation.XmlMimeType; import javax.xml.bind.annotation.XmlType; @XmlType public class PersonInfo { private DataHandler binaryData; @XmlMimeType("application/octet-stream") public DataHandler getBinaryData() { return binaryData; } public void setBinaryData(DataHandler binaryData) { this.binaryData = binaryData; } }
Listagem 2. Objeto que carrega informações binárias

A classe PersonInfo é também muito simples e carrega apenas um atributo do tipo DataHandler. A classe DataHandler do pacote javax.activation é simplesmente uma abstração que representa uma transferência de dados entre várias origens e em qualquer formato. Dessa forma, programadores não precisam se preocupar como será utilizado o XOP ou qualquer outra codificação, pois isso fica por conta do Apache CXF.

O nosso serviço já consegue receber e transmitir grandes volumes de informação binária. Vamos examinar na listagem 3 para ver como é a implementação de um cliente simples para o nosso serviço.

HelloService hello = service.getPort(portName, HelloService.class); SOAPBinding binding = (SOAPBinding) ((BindingProvider)hello).getBinding(); binding.setMTOMEnabled(true); PersonInfo info = new PersonInfo(); File f; try { f = new File(SimpleNormalHelloService.class.getResource("/java.png").toURI()); DataSource ds = new FileDataSource(f); DataHandler dh = new DataHandler(ds); info.setBinaryData(dh); PersonInfo result = hello.digaOla(info); result.getBinaryData(); Assert.assertNotNull(result); } catch (URISyntaxException e) { e.printStackTrace(); }
Listagem 3. Cliente para serviço HelloService

No nosso cliente, vemos dois aspectos interessantes: primeiro o MTOM habilitado no Binding. Isso fará com que o cliente mande requisições com o formato otimizado. Em segundo, de forma bem simples criamos um DataHandler que encapsula as informações binárias que desejamos enviar para o serviço. Para finalizar, vamos dar uma olhada como ficou a requisição SOAP na listagem 4.

Address: http://localhost:9292/hello Encoding: UTF-8 Http-Method: POST Content-Type: multipart/related; type="application/xop+xml"; boundary="uuid:0b2e9c8c-3b23-49bc-a925-b2b0435616af"; start="<root.message@cxf.apache.org>"; start-info="text/xml" Headers: {Accept=[*/*], SOAPAction=[""]} Payload: --uuid:0b2e9c8c-3b23-49bc-a925-b2b0435616af Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"; Content-Transfer-Encoding: binary Content-ID: <root.message@cxf.apache.org> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:digaOla xmlns:ns2="http://devmedia.sayhello"> <arg0> <binaryData> <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:784823ae-1a42-4ed1-a07e-153fb671c7ef-1@cxf.apache.org"/> </binaryData> </arg0> </ns2:digaOla></soap:Body> </soap:Envelope> --uuid:0b2e9c8c-3b23-49bc-a925-b2b0435616af Content-Type: application/octet-stream Content-Transfer-Encoding: binary Content-ID: <784823ae-1a42-4ed1-a07e-153fb671c7ef-1@cxf.apache.org> Content-Disposition: attachment;name="java.png" ?PNG (binary data)
Listagem 4. Requisição SOAP otimizada com MTOM

Vemos claramente na requisição que o conteúdo representado pelo cabeçalho Content-Type é o xop+xml. No payload SOAP, vemos na seção body a tag binaryData com um ID: 784823ae-1a42-4ed1-a07e-153fb671c7ef. Esse ID é uma referência ao conteúdo binário que está um pouco mais abaixo do cabeçalho “Content-ID”.

Se é tão fácil e tão otimizado, por que não mandar tudo utilizando isso? O overhead do uso do MTOM é consideravelmente alto já que o conteúdo binário é codificado em base64, que faz com que o tamanho da mensagem aumente em cerca de 30%. Isso o torna ineficaz para mensagens pequenas. Além do mais, existe o XML FastInfoset que já é um padrão eficiente para mensagens menores.

Pessoal, com esse artigo conseguimos de uma maneira muito simples entender o que é MTOM e ver como é extremamente simples enviar conteúdo binário para um WebService. Não se esqueçam de dar uma olhada no projeto completo no GitHub.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados