Apache CXF e MTOM

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

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.

Processamento utilizando MTOM

Figura 1: Processamento utilizando MTOM

Se você olhar as informações sobre MTOM no site do W3C (http://www.w3c.org) 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:

  • SOAP Transmission Optmization Feature: descreve de forma abstrata como se otimizar a transmissão e o formato de uma mensagem SOAP através da codificação seletiva de partes de suas partes sem falar exatamente qual o formato da serialização em si. Se uma mensagem é transmitida entre vários nós, os participantes podem escolher formas diferentes de otimizar a transmissão.
  • Optmized MIME Multipart/Related Serialization of SOAP Messages: é a implementação da funcionalidade descrita acima, mas sem estar amarrado a um binding específico (SOAP com HTTP ou outros). Para tanto, o XOP é utilizado. O XOP nada mais é do que uma convenção que define a melhor maneira de se serializar um XML Infoset. Mais detalhes em (http://www.w3.org/TR/2005/REC-xop10-20050125/).
  • HTTP SOAP Transmission Optimization Feature: usa a implementação de “Optmized MIME Multipart/Related Serialization of SOAP Messages” para descrever como é o “SOAP Transmission Optmization Feature” em HTTP. Em termos simples, descreve como transmitir dados binários utilizando SOAP e HTTP.

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 na página http://cxf.apache.org/docs/mtom.html.

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

Listagem 1: Serviço utilizando suporte MTOM

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) ;
}

A primeira coisa que nos chama a atenção é a anotação MTOM. Ao adicioá-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).

Listagem 2: Objeto que carrega informações binárias.

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;
	}
}

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 noso serviço.

Listagem 3: Cliente para serviço HelloService

		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();
		}

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.

Listagem 4: Requisição SOAP otimizada com MTOM

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)

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 em https://github.com/leogsilva/CxfMTOM.git. Até a próxima.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?