Resolviendo problemas de interoperabilidad Axis2-SAP R/3

Actualmente me encuentro sumido en una de las experiencias profesionalas más exigentes que he vivido, al frente de un equipo encargado de desarrollar una aplicación web Java que hará de front-end para varios módulos de un entorno SAP R/3 que está implantando nuestro cliente. La integración se está haciendo mediante webservices SOAP, con las tecnologías Axis2 para nuestra aplicación Java y XI para el entorno SAP. Sin duda una buena prueba para la supuesta interoperabilidad de los servicios web.

El primer problema técnico lo sufrí generando los clientes webservices con WSDL2Java. En principio iba a usar ADB como databinding XML pero el WSDL2Java dió errores con algunos WSDLs, así que decidí cambiarlo por XMLBeans. En comparación es un poco más complejo a la hora de usarlo, tanto el API en sí como los artefactos generados, pero mucho más potente y fiable. Además permite aprovechar todas las restricciones que había definidas en los WSDLs y que seguramente sería lo que fallaba con ADB.

El segundo y auténtico problema vino a la hora de invocar los servicios web SAP con los clientes webservices generados. Los servicios usaban autenticación HTTP Basic y ya los había probado previamente con la herramienta SoapUi. Pero a la hora de invocarlos con los clientes que había generado desde código Java fallaban inexplicablemente, devolviendo el siguiente AxisFault:

org.apache.axis2.AxisFault: problem accessing the parser. Parser already accessed!
at org.apache.axis2.AxisFault.makeFault(AxisFault.java:417)
at org.apache.axis2.transport.http.SOAPMessageFormatter.writeTo(SOAPMessageFormatter.java:72)
at org.apache.axis2.transport.http.AxisRequestEntity.writeRequest(AxisRequestEntity.java:84)
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:495)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:1973)

Resultaba increible, no eran precisamente los primeros clientes webservices que usaba y había comprobado que el XML enviado era el mismo con SoapUi que con mis clientes.
Después de mucho Google, dí con la solución, o eso creía yo, usar autenticación Preemptive. El código es sencillo:


HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername(username);
auth.setPassword(password);

auth.setPreemptiveAuthentication(true);

Modifiqué mi código y volví a ejecutar, sólo para obtener un nuevo AxisFault:


Caused by: org.apache.axis2.AxisFault: Server Error
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:486)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:343)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:389)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:211)

Esta vez sí que parecía chungo, sin 1 pista en el mensaje de error Google no podía ayudarme mucho.

Volví a comparar los mensajes que enviaba SoapUi con los de mi cliente Java y encontré la diferencia en la cabecera HTTP de autenticación. Como ya estaba usando autenticación Preemptive decidí repasar que más podía modificar de la configuración HTTP que estaba usando mi cliente. Probé y probé hasta que dí con la tecla, desactivar el http chunking:


Options options = new Options();
[...]
options.setProperty(HTTPConstants.CHUNKED, "false");

De hecho, con el http chunking desactivado ya no necesito autenticación Preemptive.
Aun no tengo muy claro cúal era la causa. En la misma dmz del servidor SAP hay otros servicios web que usamos y con ninguno ha habido problemas nunca. Lo que me inclina a pensar que el causante es el propio servidor SAP y su configuración http. Lo cierto es que vamos con el tiempo justísimo todos y no nos sobra para indagar más.
En total, un par de horas perdidas, una cosa nueva aprendida y prueba superada.

6 comentarios :: Resolviendo problemas de interoperabilidad Axis2-SAP R/3

  1. Caramba, lo del chunked me ha pasado a mí la semana pasada, aunque a mí al menos me daba un mensaje de error más explícito (411 - Length required). Igual va por ahí.

  2. Hola Julio, tuve una experiencia similar pero trabajando con Intalio BPMS, los clientes se generaban usando Axis2 pero fallaban al momento de utilizarlos, por una cuestión de premura se buscó una alternativa: justamente utilizando soapUi se estudió los mensajes soap (soapRequest y soapResponse)y se parseaba el soapRequest utilizando JDOM para obtener los datos necesarios y ordenarlos en clases java tal y como lo devolvería un cliente generado con Axis2 a partir del WSDL.

    Todo bien salvo por un servicio que devuelve una lista de objetos basada en una lista que por su naturaleza siempre crecerá, es decir con el paso del tiempo el soapResponse de este servicio devolverá una mayor cantidad de datos y al parsear con JDOM se consumirá mas memoria del servidor, lo cual podría ser un problema en el mediano o largo plazo, para ello estoy evaluando si usar Axis2 o Spring WebService para mejorar la performance.

    Por ello, dada la experiencia que comentas con SAP y considerando que el volumen de datos manejados probablemente sea alto, te consultaría:

    * Realmente sería un problema el tema de la memoria en el servidor, considerando que los objetos de la lista POJOS (clases con atributos y sus respectivos getters y setters).

    * Cambiaría el escenario si en lugar de JDOM para el parseo se utiliza clases de Axis2 o Spring WebService. He estado leyendo sobre AXIOM de Axis 2 pero ¿cómo puedo utilizarlo 'manualmente', osea sin usar el plugin Code Generator Wizard para eclipse? ¿Cómo trabaja Spring WebService con grandes volúmenes de datos como en el escenario señalado?

  3. Lek, si el chunked tiene que ver con la longitud de los paquetes troceados a nivel tcp. Tendría que revisar mis apuntes de redes pero el caso es que el servidor SAP no daba ninguna pista. Contra que servidor atacabas tu?

    Angel, los temas de rendimiento siempre son muy delicados y complejos. Entiendo tu preocupación, pero sin un verdadero análisis (con números) es díficil hacer algo más que conjeturar. Usar JDom como motor OXM puede consumir mas memoria que otras alternativas, pero eso va a hacer que tu aplicacion se venga abajo? No lo se, deberás hacer pruebas de stress lo más realistas posibles.
    También puedes probar a monitorizar el servidor a ver si agota la memoria que tiene asignada.
    Desde luego si se puede arreglar dandole más memoria y sin tocar el código yo lo dejaría así ya que funciona y seguramente ya habreis invertido más tiempo del planificado implementando vuestro propio motor soap.
    De todas formas, ejemplo rápido de usar Axiom -> http://willyxoft.wordpress.com/articulos/comienzo-rapido-axis2/

  4. Pues no estoy seguro, porque no es nuestro y sabemos muy poco sobre "el otro lado"...

  5. Hoy ha saltado el mismo problema en el cliente de otro servicio (no de SAP) que usamos. Por lo visto han añadido un proxy a la infraestructura de red, seguimos investigando...

  6. Muchísimas Gracias

Publicar un comentario