WSO2 proxy con secuencias

Tenemos un WS que tienen tres operaciones insertar, consultar(query) y actualizar. Cuando damos de alta, no devuelve todos los datos que quisieramos. Muchos de estos datos se encuentran en la consulta. Lo que vamos a hacer, es, en un mismo proxy, realizar dos llamadas: insertar y consultar. Elmensaje de salida sera un compendio de las dos acciones.

1.- Consumidor del BUS de WSO2 realiza una llamada de inserccion.
2.- El proxy realiza la llamada de inserccion, recupera el xml resultante.
3.- El proxy recupera datos del xml resultante.
4.- El proxy crea un nuevo xml de peticion de consulta.
5.- El proxy lanza la consulta y recupera el xml de respuesta.
6.- El proxy recupera datos del xml de respuesta del apartado 5 y 3
7.- El proxy crea y envia un xml de respuesta para la llamada 1.

para todo esto necesitamos dar de alta:
– Endpoint
– Secuencias
– Proxy

Definicion del Endpoint

<endpoint xmlns="http://ws.apache.org/ns/synapse" name="pepe.crud">
   <address uri="http://host:port/pepe/crudws" format="soap11">
      <suspendOnFailure>
         <progressionFactor>1.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
         <retriesBeforeSuspension>0</retriesBeforeSuspension>
         <retryDelay>0</retryDelay>
      </markForSuspension>
   </address>
</endpoint>

Definicion del proxy

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="pepe.crud.proxy"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target faultSequence="fault" endpoint="pepe.crud">
<!-- definimos una secuendcia de entrada. Aqui vamos a indicar que queremos hacer -->
      <inSequence>
<!-- Recuperamos el tipo de operacion que se esta ejecutando. Pueden ser: insertRegisty, updateRegistry, queryRegistry -->
         <property name="Operation" expression="get-property('Action')"/>
<!-- filtramos por el resultado de la operacion. Si es igual al patron regex=".*newRegistry" -->
         <filter source="get-property('Operation')" regex=".*newRegistry">
            <then>
<!-- incvocamos la secuencia añadir -->
               <sequence key="crud.addRegistry.sequence"/>
            </then>
            <else>
<!-- Sino es la operacion de añadir, continuamos por aqui -->
               <send>
<!-- enviamos al WebService la peticion-->
                  <endpoint key="wspepe.crud"/>
               </send>
            </else>
         </filter>
      </inSequence>
<!-- Tratamos la respuesta del servidor -->
      <outSequence>
         <filter source="get-property('Operation')" regex=".*newRegistry">
            <then>
<!-- Si era una operacion de insercion en registro. Realizamos la siguiente secuencia de operaciones. -->
               <sequence key="crud.outRegistry.sequence"/>
            </then>
            <else>
<!-- Sino, logeamos -->
               <log level="full">
                  <property name="Operation" expression="get-property('Operation')"/>
               </log>
            </else>
         </filter>
<!-- enviamos el mensaje a nuestro consumidor -->
         <send buildmessage="true"/>
      </outSequence>
   </target>
   <publishWSDL key="conf:/WSDL/crud.crudws/crudWS.wsdl">
      <resource location="typeapplicant.xsd"
                key="conf:/WSDL/crud.crudws/typeapplicant.xsd"/>
      <resource location="typeattachment.xsd"
                key="conf:/WSDL/crud.crudws/typeattachment.xsd"/>
      <resource location="typecommon.xsd"
                key="conf:/WSDL/crud.crudws/typecommon.xsd"/>
      <resource location="typecrud.xsd"
                key="conf:/WSDL/crud.crudws/typecrud.xsd"/>
   </publishWSDL>
   <description/>
</proxy>

Definicion de las secuencias

<sequence xmlns="http://ws.apache.org/ns/synapse" name="crud.addRegistry.sequence">
<!-- logeamos -->
   <log level="full">
      <property name="SEQ" value="Accediendo a la secuencia ADD"/>
   </log>
   <!-- invocamos a otro endpoint  -->
   <send receive="crud.queryRegistry.sequence" buildmessage="true">
      <endpoint key="pepe.crudws"/>
   </send>
</sequence>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="crud.outRegistry.sequence">
   <log level="full">
      <property name="SEQ" value="Accediendo a la secuencia OUT"/>
      <property xmlns:ns="http://org.apache.synapse/xsd" name="RegistryCode" expression="get-property('RegistryCode')"/>
      <property xmlns:ns="http://org.apache.synapse/xsd" name="IdRegistry" expression="get-property('IdRegistry')"/>
   </log>
</sequence>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="crud.queryRegistry.sequence">
   <!-- Obtenemos los datos del alta del nuevo registro para poder realizar la consulta  -->
   <property name="IdRegistry" expression="$body/ns6:RIResponse/body/idcrud" xmlns:ns2="http://ws.pepe.com/types/attachment" xmlns:ns4="http://ws.pepe.com/types/common" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns5="http://ws.pepe.com/types/crud" xmlns:ns6="http://ws.pepe.com/crudws" />
   <property name="RegistryCode" expression="$body/ns6:RIResponse/body/crudcode" xmlns:ns2="http://ws.pepe.com/types/attachment" xmlns:ns4="http://ws.pepe.com/types/common" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns5="http://ws.pepe.com/types/crud" xmlns:ns6="http://ws.pepe.com/crudws" />
   <log level="full">
      <property name="SEQ" value="Accediendo a la secuencia QUERY 1"/>
      <property name="RegistryCode" expression="get-property('RegistryCode')" xmlns:ns="http://org.apache.synapse/xsd" />
      <property name="IdRegistry" expression="get-property('IdRegistry')" xmlns:ns="http://org.apache.synapse/xsd" />
   </log>
   <!-- creamos un xml a medida para enviar al endpoint -->
   <payloadFactory media-type="xml">
      <format>
         <reg:RQRequest xmlns:reg="http://ws.pepe.com/crudws" xmlns:reg1="http://ws.pepe.com/types/crud">
            <header xmlns="" version="0"/>
            <body xmlns="">
               <crudcode>$1</crudcode>
               <input>1</input>
            </body>
         </reg:RQRequest>
      </format>
      <args>
         <arg xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('RegistryCode')" evaluator="xml"/>
      </args>
   </payloadFactory>
   <!-- enviamos el xml creado al endpoint -->
   <header name="Action" value="http://ws.pepe.com/crudws/queryRegistry"/>
   <send>
      <endpoint key="pepe.crudws"/>
   </send>
   <log level="full">
      <property name="SEQ" value="Accediendo a la secuencia QUERY 2"/>
   </log>
</sequence>

Este codigo ha sido elaborado por Rafael Udaondo. Con su permiso he publicado esta entrada.

Anuncios
WSO2 proxy con secuencias

Diferencias Soap1.1 vs Soap 1.2

Sobre las peticiones que estoy haciendo en mis servicios:

---------------------------
ID: 1
Address: https://host:port/services/cargos.otrasconsultasws
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], Connection=[Keep-Alive], SOAPAction=["consultarMaestrosGenericos"]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>...</soap:Body></soap:Envelope>
--------------------------------------
---------------------------
ID: 1
Address: https://host:port/services/cargos.otrasconsultasws
Encoding: UTF-8
Content-Type: application/soap+xml; action="consultarMaestrosGenericos"
Headers: {Accept=[*/*], Connection=[Keep-Alive]}
Payload: <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Body>....</soap:Body></soap:Envelope>
--------------------------------------

DIFERENCIAS

Estas dos lineas son las mismas para ambos:
SOAP1.1 = SOAP1.2 = Address: https://elb.esb.wso2.com:8243/services/cargos.otrasconsultasws
SOAP1.1 = SOAP1.2 = Encoding: UTF-8

SOAP1.1 = Content-Type: text/xml
SOAP1.2 = Content-Type: application/soap+xml; action=”consultarMaestrosGenericos”

SOAP1.1 = Headers: {Accept=[*/*], Connection=[Keep-Alive], SOAPAction=[“consultarMaestrosGenericos”]}
SOAP1.2 = Headers: {Accept=[*/*], Connection=[Keep-Alive]}

SOAP1.1 = xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/&#8221;
SOAP1.2 = xmlns:soap=”http://www.w3.org/2003/05/soap-envelope&#8221;

Diferencias Soap1.1 vs Soap 1.2

Cliente Socket Web Service

No es lo mas recomendable ni lo mas refactorizable, escalable, etc. Pero quiza si es lo mas rapido.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import javax.net.ssl.SSLSocketFactory;
import sun.misc.BASE64Encoder;

public class SendSMS_Soap {

	public static void main(String[] args) { 
		try { 
			String driver = "DRIVER-DATA; 
			String number = "NUMER-DATA"; 
			String login = "USER:PASS"; 
			String aut = (new BASE64Encoder().encodeBuffer(login.getBytes())).trim(); 

			String mensaje = "Probando envio de SMS con SOAP.."; 

			// ******************* Construimos el XML ******************* 
			String xmldata = //"<?xml version="1.0" encoding="UTF-8"?>"+ 
					"<soap:Envelope " +
					"xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" " + 
					// "xmlns:xsd="http://www.w3.org/2001/XMLSchema"  " +
					// "xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"" +
					">"+ 
			"<soap:Body>"+ 
			"<ns2:OPERACION xmlns:ns2="http://www.dominio.es/ruta/schemas">"+ 
			"<Version>1.0</Version>"+ 
			"<Authorization>"+aut+"</Authorization>"+ 
			"<Sender>"+driver+"</Sender>"+ 
			"<Recipients>" + 
			"<To>"+number+"</To>" + 
			"</Recipients>"+ 
			"<SMSText>"+mensaje+"</SMSText>"+ 
			"</ns2:OPERACION>"+ 
			"</soap:Body>"+ 
			"</soap:Envelope>"; 

			System.out.println("Mensaje a enviar: " + xmldata);
			// ******************* Creamos el Socket ******************* 
		
			System.setProperty("javax.net.ssl.trustStore", "trustStore.jks");
			SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
		    Socket s = ssf.createSocket(SERVIDOR, PUERTO);
		    OutputStream outs = s.getOutputStream();
		    InputStream ins = s.getInputStream();

			// ******************* Enviamos la cabecera ******************* 
			BufferedWriter wr = new BufferedWriter(new 
					OutputStreamWriter(outs,"UTF-8")); 

			wr.write("POST /RUTA HTTP/1.1rn"); 
			wr.write("Content-Type: text/xml; charset=utf-8rn"); 
			wr.write("Accept: */*rn"); 
			//wr.write("Authorization: Basic "+aut+"rn"); 
			wr.write("User-Agent: Java/1.7rn"); 
			wr.write("Host: https://SERVIDOR:PUERTO/RUTA" + "rn"); 
			wr.write("Cache-Control: no-cachern"); 
			wr.write("Pragma: no-cachern"); 
			wr.write("SOAPAction: ''rn"); 
			wr.write("Connection: keep-alivern"); 
			wr.write("Content-Length: " + xmldata.length() + "rn"); 
			wr.write("rn"); 

			// ******************* Enviamos el XML ******************* 
			wr.write(xmldata); 
			wr.flush(); 
			
			// ******************* Esperamos respuesta y la sacamos por pantalla ******************* 
			BufferedReader rd = new BufferedReader(new InputStreamReader(ins)); 
			String line; 
			while((line = rd.readLine()) != null){
				System.out.println(line); 
			}

		} catch (Exception e) { 
			System.err.println(e.getMessage()); 
		} 
	}
	
}
Cliente Socket Web Service

Message Queue vs. Web Services?

En este post de stackoverflow. Copio y pego literalmente, para no perder esta informacion.

When you use a web service you have a client and a server:
– If the server fails the client must take responsibility to handle the error.
– When the server is working again the client is responsible of resending it.
– If the server gives a response to the call and the client fails the operation is lost.
– You don’t have contention, that is: if million of clients call a web service on one server in a second, most probably your server will go down.
– You can expect an immediate response from the server, but you can handle asynchronous calls too.
When you use a message queue like RabbitMQ, ActiveMQ, IBM MQ Series, Tuxedo you expect different and more fault tolerant results:
– If the server fails, the queue persist the message (optionally, even if the machine shutdown).
– When the server is working again, it receives the pending message.
– If the server gives a response to the call and the client fails, if the client didn’t acknowledge the response the message is persisted.
– You have contention, you can decide how many requests are handled by the server (call it worker instead).
– You don’t expect an immediate synchronous response, but you can implement/simulate synchronous calls.
Message Queues has a lot more features but this is some rule of thumb to decide if you want to handle error conditions yourself or leave them to the message queue.

En programmers.stackexchange.com encontre este otro post buscando cuando implementar RabbitMQ.

When to use Advanced Message Queuing Protocol like RabbitMQ?
Imagine that you have a web service that can accept many requests per second. You also have a accounting system that does a lot of things, one of which is processing the requests coming from the web service.
If you put a queue between the web service and the accounting system, you will be able to:
have less coupling between the two applications, because now both applications have to know the configuration parameters of the queue management system and the name of the queue. Here the catch is that usually you are more likely to move to another server some application than move the queue management system
if you have a lot of requests coming in a short amount of time, the accounting system will be able to process them all anyway
persist some requests if their number becomes really huge
Of course, you could have more complex situations where the number of your applications is much bigger than two and you need to manage the communication between them.
Message Queue vs. Web Services?

WSDL definicion

El WSDL es el contrato para la comunicaciones entre aplicaciones web services.

Componentes del WSDL:
TYPE: definición de los tipos de datos que se van a utilizar
MESSAGES: definición del formato de los mensajes de entrada y salidas, así como de sus tipos.
OPERATION: definición de acciones soportadas por el servicio.
PORT TYPE: conjunto de operaciones soportadas por uno o mas endpoints. Las Interfaces.
BINDING: especificación del protocolo y formato de datos para un PORT TYPE, en particular.
PORT: es un endpoint definido como un conjunto de BINDING Y NET ADDRESS
SERVICE: es un o una colección de endpoints.

TYPE
MESSAGES input, output
PORT TYPE (interfaz)
         OPERATION/S
BINDING (definicion del protocolo a utilizar (TCP, HTTP, SMTP...) y como se usa)
        SOAP
        SOAP OPERATION/S
SERVICE
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/">
   <types>
     <xs:schema targetNamespace="http://example.org/math/types/" 
       xmlns="http://example.org/math/types/" 
       elementFormDefault="unqualified" attributeFormDefault="unqualified">
         <xs:complexType name="MathInput">
            <xs:sequence>
               <xs:element name="x" type="xs:double"/>
               <xs:element name="y" type="xs:double"/>
            </xs:sequence>
         </xs:complexType>
         <xs:complexType name="MathOutput">
            <xs:sequence>
               <xs:element name="result" type="xs:double"/>
            </xs:sequence>
         </xs:complexType>
         <xs:element name="Add" type="MathInput"/>
         <xs:element name="AddResponse" type="MathOutput"/>
         <xs:element name="Subtract" type="MathInput"/>
         <xs:element name="SubtractResponse" type="MathOutput"/>
         <xs:element name="Multiply" type="MathInput"/>
         <xs:element name="MultiplyResponse" type="MathOutput"/>
         <xs:element name="Divide" type="MathInput"/>
         <xs:element name="DivideResponse" type="MathOutput"/>
      </xs:schema>
   </types>
   <message name="AddMessage">
      <part name="parameters" element="ns:Add"/>
   </message>
   <message name="AddResponseMessage">
      <part name="parameters" element="ns:AddResponse"/>
   </message>
   <message name="SubtractMessage">
      <part name="parameters" element="ns:Subtract"/>
   </message>
   <message name="SubtractResponseMessage">
      <part name="parameters" element="ns:SubtractResponse"/>
   </message>
   <message name="MultiplyMessage">
      <part name="parameters" element="ns:Multiply"/>
   </message>
   <message name="MultiplyResponseMessage">
      <part name="parameters" element="ns:MultiplyResponse"/>
   </message>
   <message name="DivideMessage">
      <part name="parameters" element="ns:Divide"/>
   </message>
   <message name="DivideResponseMessage">
      <part name="parameters" element="ns:DivideResponse"/>
   </message>
   <portType name="MathInterface">
      <operation name="Add">
         <input message="y:AddMessage"/>
         <output message="y:AddResponseMessage"/>
      </operation>
      <operation name="Subtract">
         <input message="y:SubtractMessage"/>
         <output message="y:SubtractResponseMessage"/>
      </operation>
      <operation name="Multiply">
         <input message="y:MultiplyMessage"/>
         <output message="y:MultiplyResponseMessage"/>
      </operation>
      <operation name="Divide">
         <input message="y:DivideMessage"/>
         <output message="y:DivideResponseMessage"/>
      </operation>
   </portType>
   <binding name="MathSoapHttpBinding" type="y:MathInterface">
      <soap:binding style="document" 
         transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="Add">
         <soap:operation soapAction="http://example.org/math/#Add"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
      <operation name="Subtract">
         <soap:operation soapAction="http://example.org/math/#Subtract"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
      <operation name="Multiply">
         <soap:operation soapAction="http://example.org/math/#Multiply"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
      <operation name="Divide">
         <soap:operation soapAction="http://example.org/math/#Divide"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
   </binding>
   <service name="MathService">
      <port name="MathEndpoint" binding="y:MathSoapHttpBinding">
         <soap:address location="http://localhost/math/math.asmx"/>
      </port>
   </service>
</definitions>

Este articulo es un Copia/Pega de msdn.microsoft.com, asi como sus imagenes.

WSDL definicion

java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()

Trabajando con Web Services me he encontrado con el siguiente error:

ERROR [http-apr-8080-exec-115][render_portlet_jsp:154] java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()Ljava/lang/String;

En dos proyectos identicos tengo un test en el cual en un proyecto se ejecuta sin problemas y en el otro ocurre lo de arriba. El problema proviene de las librerias que usan. En el que funciona, usa la 2.0 y en el que no funciona, la 2.7.0.

Solucion en este script:

cd $JAVA_HOME/jre/lib
mkdir endorsed
cd endorsed
wget http://repo1.maven.org/maven2/javax/xml/bind/jaxb-api/2.2.7/jaxb-api-2.2.7.jar
wget http://repo1.maven.org/maven2/javax/xml/ws/jaxws-api/2.2.7/jaxws-api-2.2.7.jar

Puedes mirar en el siguiente articulo si tienes problemas con tomcat y los web services.

java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()

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.

Crear un Handler para Web Services en Apache CXF