¡Hola a todos! En el mundo de los servicios web, a menudo necesitamos interactuar con los mensajes SOAP de forma programática. A veces, la lógica de negocio requiere que inspeccionemos o modifiquemos las cabeceras (headers
) o el cuerpo del mensaje antes de que la solicitud llegue al servicio. Una de las mejores maneras de lograr esto, especialmente con Apache CXF y Spring, es utilizando un Handler
(manejador).
En este artículo, te mostraré cómo implementar un Handler
para interceptar y manipular mensajes SOAP, basándome en un ejemplo funcional y bien estructurado.
Paso 1: Crea tu clase HandlerChain
Lo primero que haremos es crear una clase Java que implemente la interfaz SOAPHandler
. Este es el componente central que interceptará los mensajes.
import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;
import java.util.Set;
public class HandlerChain implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
System.out.println("Server: handleMessage()......");
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Se ejecuta solo para mensajes de respuesta (inbound)
if (!isRequest) {
try {
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
SOAPHeader soapHeader = soapEnv.getHeader();
System.out.println("Msg header: " + soapMsg.getSOAPHeader());
// Si no hay cabecera, agrega una y lanza una excepción
if (soapHeader == null) {
soapHeader = soapEnv.addHeader();
generateSOAPErrMessage(soapMsg, "No SOAP header.");
}
} catch (SOAPException e) {
System.err.println(e);
}
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
System.out.println("Server: handleFault()......");
return true;
}
@Override
public void close(MessageContext context) {
System.out.println("Server: close()......");
}
@Override
public Set<QName> getHeaders() {
System.out.println("Server: getHeaders()......");
return null;
}
private void generateSOAPErrMessage(SOAPMessage msg, String reason) {
try {
SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
SOAPFault soapFault = soapBody.addFault();
soapFault.setFaultString(reason);
throw new SOAPFaultException(soapFault);
} catch (SOAPException e) {
System.err.println(e);
}
}
}
Análisis del código:
handleMessage
: Este es el método más importante. Es llamado tanto para los mensajes de entrada (inbound
) como para los de salida (outbound
). El booleanoisRequest
nos ayuda a distinguir entre los dos. Aquí, el código se enfoca en los mensajes de respuesta (!isRequest
), imprimiendo la cabecera y lanzando un error si no existe.handleFault
: Se activa si ocurre un error en el mensaje.close
: Se llama cuando se cierra elHandler
.
Paso 2: Define el HandlerChain
en un XML
Para que CXF sepa qué Handler
usar, necesitamos un archivo de configuración XML. Este archivo define una cadena de Handlers
y la clase que implementamos en el paso anterior.
Crea un archivo llamado handler-chain.xml
y agrega el siguiente contenido, asegurándote de reemplazar class_path
con la ruta completa a tu clase HandlerChain
.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>class_path.HandlerChain</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
Paso 3: Agrega la anotación @HandlerChain
a tu servicio
Finalmente, conecta el archivo de configuración a tu servicio web. En la clase que implementa tu servicio (Web Service
), agrega la anotación @HandlerChain
con la ruta al archivo XML que creaste.
@HandlerChain(file="/handler-chain.xml")
// ... resto de la implementación del Web Service
Con esto, cada vez que un mensaje SOAP sea procesado por tu servicio web, pasará a través de tu clase HandlerChain
, donde podrás inspeccionar, modificar o rechazar el mensaje según tus necesidades.
Para agregar una cabecera SOAP, puedes usar el siguiente código, tanto en el cliente como en el servidor, dependiendo de si quieres añadirlo a la solicitud o a la respuesta.
// Agrega una cabecera SOAP en el lado del servidor
List<Header> headers = new ArrayList<>();
Header dummyHeader = new Header(new QName("uri:org.apache.cxf", "dummy"), "decapitated",
new JAXBDataBinding(String.class));
headers.add(dummyHeader);
context.getMessageContext().put(Header.HEADER_LIST, headers);
Este método es poderoso y muy flexible, y te permite tener un control total sobre el procesamiento de tus mensajes SOAP.
¿Qué otros trucos de servicios web has descubierto? ¡Déjanos un comentario y comparte tu experiencia!
Comentarios
Publicar un comentario