En un proyecto de mule con el componente CXF que permite consumir un servicio web utilizando el par de procesadores CXF-HTTP surgía el error Trying to write END_DOCUMENT when document has no root de forma recurrente. Para evitar probar sobre el desarrollo principal, lo mejor en estos casos es replicar el flujo problemático en un proyecto pequeño a parte. De este modo es posible hacer muchos cambios sin riesgo alguno, se pueden adaptar las interfaces (en este caso se consume una entrada cualquiera de fichero) y, al tratarse de un proyecto pequeño, se despliega más rápido al ser más liviano.
En el flujo de prueba:
- Se consume un fichero cualquiera de un directorio con el input endpoint File.
- Se adapta el contenido del fichero (payload del mensaje) mediante un Java Adapter el cual genera una petición XML que será enviada al WS a través del proxy cliente. Las clases java fueron son JAXB-client y fueron generadas con la herramienta de terceros wsdl2java de Apache CXF que también provee Mule.
- La petición anterior son instancias de clases Java con anotaciones, por lo que el transformer JABX Object to XML convierte esos objetos en una representación XML.
- Este choice realmente no hace nada, y su expresión MEL para que ejecute siempre la rama deseada es #[true]. Se puede ignorar en el flujo.
- El Transform message que lo único que hace es vuelca el payload y lo transforma a uno con MIME application/xml que pueda ser procesado internamente por el componente CXF (no entendemos todavía mucho porque esto tiene que ser así, pero parece que la característica DataSense influye).
- Finalmente CXF envuelve con SOAP la petición y se envía mediante POST a través del conector HTTP hacia un servicio web mock.
En los logs tras ejecutar pruebas, siempre obteníamos el mismo error:
ERROR 2016-05-09 22:03:39,808 [[ws-test].ws-testFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy: ******************************************************************************** Message : Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document). (javax.xml.stream.XMLStreamException) Type : org.mule.api.transformer.TransformerException Code : MULE_ERROR--2 JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html Transformer : XmlToXMLStreamReader{this=5f883d90, name='_XmlToXMLStreamReader', ignoreBadInput=false, returnClass=SimpleDataType{type=javax.xml.stream.XMLStreamReader, mimeType='*/*', encoding='null'}, sourceTypes=[SimpleDataType{type=java.lang.String, mimeType='*/*', encoding='null'}, SimpleDataType{type=[B, mimeType='*/*', encoding='null'}, SimpleDataType{type=javax.xml.transform.Source, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.xml.sax.InputSource, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.dom4j.Node, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.dom4j.Document, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.w3c.dom.Document, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.w3c.dom.Element, mimeType='*/*', encoding='null'}, SimpleDataType{type=java.io.InputStream, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.mule.api.transport.OutputHandler, mimeType='*/*', encoding='null'}, SimpleDataType{type=javax.xml.stream.XMLStreamReader, mimeType='*/*', encoding='null'}, SimpleDataType{type=org.mule.module.xml.transformer.DelayedResult, mimeType='*/*', encoding='null'}]} ******************************************************************************** Exception stack is: 1. Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document). (javax.xml.stream.XMLStreamException) com.ctc.wstx.sw.BaseStreamWriter:1537 (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/xml/stream/XMLStreamException.html) 2. Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document). (javax.xml.stream.XMLStreamException) (org.mule.api.transformer.TransformerException) org.mule.module.xml.transformer.XmlToXMLStreamReader:65 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html) ********************************************************************************
Lo primero es asegurarse mediante el modo depuración con sus correspondientes puntos de ruptura que el contenido (payload) del mensaje antes de llegar al componente CXF es un documento XML correcto (metainformación, etiqueta raíz y pares de etiquetas de apertura-cierre correctas):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ConversionRate xmlns="http://www.webserviceX.NET/"> <FromCurrency>EUR</FromCurrency> <ToCurrency>JPY</ToCurrency> </ConversionRate>
En este caso el XML que será enviado a través del cliente proxy es correcto, por lo que el error tiene que deberse a algún factor del procesado interno del componente CXF cuando intenta envolver el contenido con SOAP. Otro de los motivos por los que pueda fallar es que quizás alguna metainformación del paquete es incorrecta y eso hace fallar a mule. Metainformación como por ejemplo el tipo de MIME del contenido (debería ser de tipo application/xml), por lo que es necesario actualizar la configuración actual del proyecto:
<mulexml:jaxb-object-to-xml-transformer jaxbContext-ref="JAXB_Context" doc:name="JAXB Object to XML" mimeType="application/xml"/>
Finalmente la configuración del proyecto queda tal que así y ya se invoca al servicio web sin problema alguno:
<?xml version="1.0" encoding="UTF-8"?> <mule xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw" xmlns:metadata="http://www.mulesoft.org/schema/mule/metadata" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:quartz="http://www.mulesoft.org/schema/mule/quartz" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd http://www.mulesoft.org/schema/mule/quartz http://www.mulesoft.org/schema/mule/quartz/current/mule-quartz.xsd http://www.mulesoft.org/schema/mule/ee/dw http://www.mulesoft.org/schema/mule/ee/dw/current/dw.xsd http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd"> <http:request-config name="HTTP_Request_Configuration" host="localhost" port="8088" doc:name="HTTP Request Configuration"/> <mulexml:jaxb-context name="JAXB_Context" packageNames="net.webservicex.cc" doc:name="JAXB Context"/> <flow name="ws-testFlow"> <file:inbound-endpoint path="C:\Users\User\Desktop\Input" responseTimeout="10000" doc:name="File"/> <custom-transformer class="es.ejemplo.ConversionRateRequest" doc:name="Java"/> <mulexml:jaxb-object-to-xml-transformer jaxbContext-ref="JAXB_Context" doc:name="JAXB Object to XML" mimeType="application/xml"/> <choice doc:name="Choice"> <when expression="#[true]"> <dw:transform-message doc:name="Transform Message"> <dw:set-payload><![CDATA[%dw 1.0 %output application/xml --- payload]]></dw:set-payload> </dw:transform-message> <cxf:proxy-client payload="body" doc:name="CXF"/> <http:request config-ref="HTTP_Request_Configuration" path="/mockCurrencyConvertorSoap" method="POST" doc:name="HTTP"/> </when> </choice> </flow> </mule>