CXF jaxb send string as CData

From http://cxf.547215.n5.nabble.com/CXF-jaxb-send-string-as-CData-td5524523.html
Finalmente no he necesitado usarlo, pero lo guardo por si algún día…

public class CdataWriterInterceptor extends AbstractPhaseInterceptor<Message> { 

        public CdataWriterInterceptor() { 
                super(Phase.PRE_STREAM); 
                addAfter(AttachmentOutInterceptor.class.getName()); 
        } 

        @Override 
        public void handleMessage(Message message) { 
                message.put("disable.outputstream.optimization", Boolean.TRUE); 
                XMLStreamWriter writer = 
StaxUtils.createXMLStreamWriter(message.getContent(OutputStream.class)); 
                message.setContent(XMLStreamWriter.class, new CDataXMLStreamWriter(writer)); 
        } 
} 
public class CDataXMLStreamWriter extends DelegatingXMLStreamWriter { 

        private String currentElementName; 

        public CDataXMLStreamWriter(XMLStreamWriter del) { 
                super(del); 
        } 

        @Override 
        public void writeCharacters(String text) throws XMLStreamException { 
                boolean useCData = checkIfCDATAneededForCurrentElement(); 
                if (useCData) { 
                        System.out.println("WritingCData" + text); 
                        super.writeCData(text); 
                }else { 
                super.writeCharacters(text); 
                } 
        } 

        private boolean checkIfCDATAneededForCurrentElement() { 
                if("MessageBody".equals(currentElementName)) return true; 
                return false; 
        } 

        public void writeStartElement(String prefix, String local, String 
uri) throws XMLStreamException { 
                currentElementName = local; 
                super.writeStartElement(prefix, local, uri); 
        } 
}
Anuncios
CXF jaxb send string as CData

Como modificar el mensaje SOAP que entra

Te llega un mensaje SOAP, y lo tienes que modificar porque hay una coma que esta en mal sitio. Vamos a usar Interceptors para ello.
Este es el mensaje que me llega y que quiero modificar:

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <soapenv:Body>
                <soapenv:Fault>
                        <faultcode>env:Server</faultcode>
                        <faultstring>0301 - Organismo no autorizado 'XXXXXXXX' 'CDISFWS01'</faultstring>
                        <faultactor>CDISFWS01</faultactor>
                        <detail>
                                <Atributos xmlns="http://www.map.es/scsp/esquemas/V2/soapfaultatributos">
                                        <IdPeticion>1390410889105</IdPeticion>
                                        <NumElementos>1</NumElementos>
                                        <TimeStamp>2014-01-22T18:14:20.651+01:00</TimeStamp>
                                        <Estado>
                                                <CodigoEstado>0301</CodigoEstado>
                                                <CodigoEstadoSecundario />
                                                <LiteralError>Organismo no autorizado 'XXXXXXXX' 'CDISFWS01'</LiteralError>
                                                <TiempoEstimadoRespuesta>0</TiempoEstimadoRespuesta>
                                        </Estado>
                                        <CodigoCertificado>CDISFWS01</CodigoCertificado>
                                </Atributos>
                        </detail>
                </soapenv:Fault>
        </soapenv:Body>
</soapenv:Envelope>

Lo que esta mal:
env:Server
Como debiera esta bien:
soapenv:Server

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <soapenv:Body>
                <soapenv:Fault>
                        <faultcode>soapenv:Server</faultcode>
                        <faultstring>0301 - Organismo no autorizado 'XXXXXXXX' 'CDISFWS01'</faultstring>
                        <faultactor>CDISFWS01</faultactor>
                        <detail>
                                <Atributos xmlns="http://www.map.es/scsp/esquemas/V2/soapfaultatributos">
                                        <IdPeticion>1390410889105</IdPeticion>
                                        <NumElementos>1</NumElementos>
                                        <TimeStamp>2014-01-22T18:14:20.651+01:00</TimeStamp>
                                        <Estado>
                                                <CodigoEstado>0301</CodigoEstado>
                                                <CodigoEstadoSecundario />
                                                <LiteralError>Organismo no autorizado 'XXXXXXXX' 'CDISFWS01'</LiteralError>
                                                <TiempoEstimadoRespuesta>0</TiempoEstimadoRespuesta>
                                        </Estado>
                                        <CodigoCertificado>CDISFWS01</CodigoCertificado>
                                </Atributos>
                        </detail>
                </soapenv:Fault>
        </soapenv:Body>
</soapenv:Envelope>

Utilizo esta clase que algun compañero de profesion dejo en stackoverflow.com. Yo simplemente he modificado el uso del log.

package una.ruta.a.un.paquete;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.LoggerFactory;

public abstract class MessageChangeInterceptor extends AbstractPhaseInterceptor<Message> {

	private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(MessageChangeInterceptor.class);

	public MessageChangeInterceptor() {
		super(Phase.PRE_STREAM);
		addBefore(SoapPreProtocolOutInterceptor.class.getName());
	}

	protected abstract String changeOutboundMessage(String currentEnvelope);

	protected abstract String changeInboundMessage(String currentEnvelope);

	public void handleMessage(Message message) {
		boolean isOutbound = false;
		isOutbound = message == message.getExchange().getOutMessage()
				|| message == message.getExchange().getOutFaultMessage();

		if (isOutbound) {
			OutputStream os = message.getContent(OutputStream.class);

			CachedStream cs = new CachedStream();
			message.setContent(OutputStream.class, cs);

			message.getInterceptorChain().doIntercept(message);

			try {
				cs.flush();
				IOUtils.closeQuietly(cs);
				CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);

				String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
				csnew.flush();
				IOUtils.closeQuietly(csnew);

				LOGGER.debug("Outbound message: " + currentEnvelopeMessage);

				String res = changeOutboundMessage(currentEnvelopeMessage);
				if (res != null) {
					LOGGER.debug("Outbound message has been changed: " + res);
				}
				res = res != null ? res : currentEnvelopeMessage;

				InputStream replaceInStream = IOUtils.toInputStream(res, "UTF-8");

				IOUtils.copy(replaceInStream, os);
				replaceInStream.close();
				IOUtils.closeQuietly(replaceInStream);

				os.flush();
				message.setContent(OutputStream.class, os);
				IOUtils.closeQuietly(os);

			} catch (IOException ioe) {
				LOGGER.warn("Unable to perform change.", ioe);
				throw new RuntimeException(ioe);
			}
		} else {
			try {
				InputStream is = message.getContent(InputStream.class);
				String currentEnvelopeMessage = IOUtils.toString(is, "UTF-8");
				IOUtils.closeQuietly(is);

				LOGGER.debug("Inbound message: " + currentEnvelopeMessage);

				String res = changeInboundMessage(currentEnvelopeMessage);
				if (res != null) {
					LOGGER.debug("Inbound message has been changed: " + res);
				}
				res = res != null ? res : currentEnvelopeMessage;

				is = IOUtils.toInputStream(res, "UTF-8");
				message.setContent(InputStream.class, is);
				IOUtils.closeQuietly(is);
			} catch (IOException ioe) {
				LOGGER.warn("Unable to perform change.", ioe);
				throw new RuntimeException(ioe);
			}
		}
	}

	public void handleFault(Message message) {
	}

	private class CachedStream extends CachedOutputStream {
		public CachedStream() {
			super();
		}

		protected void doFlush() throws IOException {
			currentStream.flush();
		}

		protected void doClose() throws IOException {
		}

		protected void onWrite() throws IOException {
		}
	}

}

Y la clase que hereda de la anterior, y realiza el cambio requerido:

package una.ruta.a.un.paquete;

import org.slf4j.LoggerFactory;

public class InterceptorInSoapFaultBug extends MessageChangeInterceptor {

	private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(InterceptorInSoapFaultBug.class);

	@Override
	protected String changeOutboundMessage(String currentEnvelope) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	protected String changeInboundMessage(String currentEnvelope) {
		if((currentEnvelope != null) && (currentEnvelope.contains(">env:Server<"))){
			LOGGER.info("Debido a un bug en el mensaje SoapFault de este servicio. se procede a cambiar la etiqueta "env:Server" por "soapenv:Server".");
			currentEnvelope = currentEnvelope.replace(">env:Server<", ">soapenv:Server<");
		}
		
		return currentEnvelope;
	}

}

Posteriormente en el fichero de configuracion de Spring tendrias que invocarlo:

	<!-- ... -->
	<bean id="bugSoapFault" class="una.ruta.a.un.paquete.InterceptorInSoapFaultBug" />
	<!-- ... -->
	<jaxws:client id="clientPaxaseConsultaIdentidad" address="#{url}"
		serviceClass="es.map.xml_schemas.PeticionPortType">
		<!-- <jaxws:properties> -->
		<!-- <entry key="schema-validation-enabled" value="true" /> -->
		<!-- </jaxws:properties> -->
		<jaxws:inFaultInterceptors>
			<ref bean="logInbound" />
			<ref bean="bugSoapFault" />
		</jaxws:inFaultInterceptors>
		<jaxws:inInterceptors>
	<!-- cierra todas las etiquetas y rellena lo que falta -->
Como modificar el mensaje SOAP que entra