Ir al contenido principal

Manipulando mensajes SOAP en Java con CXF: Una guía práctica 💻

¡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 booleano isRequest 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 el Handler.


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

Entradas Populares

Renombrar una columna en Oracle: Guía rápida y sencilla 💻

¡Hola a todos! En el mundo de las bases de datos, es común necesitar hacer ajustes en la estructura de las tablas, y una de las tareas más frecuentes es renombrar una columna. Ya sea por un error tipográfico, una mejora en la nomenclatura o un cambio en los requisitos, saber cómo hacerlo de manera eficiente es fundamental. Afortunadamente, Oracle facilita esta tarea con una sintaxis simple y directa. A continuación, te muestro cómo puedes renombrar una columna de una tabla en un solo paso. La sintaxis para renombrar una columna Para cambiar el nombre de una columna, utilizamos la sentencia ALTER TABLE . Esta es la forma más segura y recomendada de modificar la estructura de una tabla sin afectar los datos existentes. ALTER TABLE <nombre_de_la_tabla> RENAME COLUMN <nombre_antiguo_del_campo> TO <nuevo_nombre_del_campo>; COMMIT; Análisis de la sintaxis: ALTER TABLE <nombre_de_la_tabla> : Esta parte de la sentencia le indica a Oracle que vas a modificar la estructur...

¿Tu PC no puede instalar la actualización KB5034441? No te preocupes, aquí tienes la solución y la explicación

Sabemos que iniciar el 2024 con problemas técnicos no es lo ideal. Si has intentado instalar la reciente actualización KB5034441 y te has encontrado con el frustrante error 0x80070643 , no estás solo. Este problema ha afectado a muchos usuarios y puede causar una gran confusión, especialmente cuando la descarga parece ir bien, pero la instalación se detiene en 0%. En este artículo, vamos a desglosar qué es lo que está causando este error, por qué no es tan grave como parece y qué pasos puedes seguir para manejarlo. Mensaje de Error Entendiendo el error 0x80070643 en la actualización KB5034441 La actualización KB5034441 está diseñada para reforzar la seguridad de tu entorno de recuperación de Windows (Windows Recovery Environment, WinRE), especialmente para aquellos que utilizan la función de cifrado de disco BitLocker. La intención es buena, pero la implementación ha revelado un problema para ciertos sistemas. El código de error 0x80070643 se traduce como ERROR_INSTALL_FAILURE , y e...