Crear un Handler para Web Services en Apache CXF


Los handler que son propios de los Web Services, no son la forma mas adecuada para Apache CXF. La mejor forma, por que te da muchas mas opciones, son los interceptors. Pero como vamos a ver a continuación, no hay ningún problema en añadir un handler a un Web Service creado con Apache CXF.

Lo primero de todo es crear el Handler. Queremos mostrar por el log, los mensajes de entrada y salida.

package mi.paquete.ws.cxf.handler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@SuppressWarnings("restriction")
public class LogHandler implements SOAPHandler<SOAPMessageContext> {

	private static final Logger LOGGER = LoggerFactory.getLogger(LogHandler.class);
	
	public boolean handleMessage(SOAPMessageContext mc) {
		logMessage(mc);
		return true;
	}

	public boolean handleFault(SOAPMessageContext context) {
		return true;
	}

	public void close(MessageContext context) {
	}

	public Set<QName> getHeaders() {
		return null;
	}

	private Boolean isResponse(SOAPMessageContext mc) {
		Boolean isReponse = (Boolean) mc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		return isReponse;
	}

	private void logMessage(SOAPMessageContext mc){
		boolean isResponse = isResponse(mc);
		
		String type = isResponse ? "XML RESPONSE : " : "XML REQUEST: ";
		String strMessage = "";
		
		try {
			strMessage = messageToString(mc.getMessage());
		} catch (SOAPException e) {
			LOGGER.warn("SOAPException: ", e);
		} catch (IOException e) {
			LOGGER.warn("IOException: ", e);
		}
				
		LOGGER.info("WS "+ type + strMessage);
	}
	
	private String  messageToString(final SOAPMessage message)
			throws SOAPException, IOException {

		ByteArrayOutputStream out = new ByteArrayOutputStream();
		message.writeTo(out);
		return out.toString();
	}

}

Ahora simplemente configuramos cxf para que ejecute el handle a su momento.
Hay varias maneras de hacerlo:
1 – con un fichero handler.xml ubicado:
1.1 – en la siguiente ruta: /src/main/resources/mi/paquete/ws/cxf/spi/handler.xml, asi en la creacion del jar el fichero handler.xml estará en la misma carpeta que la clase que lo llama. La anotacion en la clase que implementa el web service (la clase que lo llama) seria @HandlerChain(handler.xml)
1.2 – o en una ruta cualquiera ya que la anotacion tiene una ruta absoluta: @HandlerChain(file=”../../common/handlers/myhandlers.xml”).
2 – en la configuracion de cxf (fichero applicationContext.xml de spring), que a todas luces no es nada intrusiva y por configuracion indicas si pones un handler dos, tres o ninguno.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:cxf="http://cxf.apache.org/core"
	xsi:schemaLocation="
	http://cxf.apache.org/core 
	http://cxf.apache.org/schemas/core.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://cxf.apache.org/jaxws 
	http://cxf.apache.org/schemas/jaxws.xsd">

	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<context:annotation-config />
	<context:component-scan base-package="mi.paquete.ws.cxf" />

	<bean id="busqueda" class="mi.paquete.ws.cxf.spi.WebServiceImpl" />

	<jaxws:endpoint id="busquedaService" implementor="#busqueda" address="/busqueda">
		<jaxws:handlers>
			<bean class="mi.paquete.ws.cxf.handler.LogHandle" />
		</jaxws:handlers>
	</jaxws:endpoint>
	
</beans>

LIMITACIONES: si hay un error, una excepcion, el mensaje de salida no se loguea, es null. Supongo que para los handler hay fases de cuando quieres que se ejecute. Pero encontre los interceptors de CXF y no busque mas informacion sobre los handlers.

VENTAJAS: Los interceptors tienen la limitacion que solo se pueden usar con CXF, no se pueden llevar a jax-ws. Mientras que los handlers son extrapolables a todos los webservices.

Anuncios
Crear un Handler para Web Services en Apache CXF