Mostrando entradas con la etiqueta axis2. Mostrar todas las entradas
Mostrando entradas con la etiqueta axis2. Mostrar todas las entradas

Historia de una integración (iii): El desarrollo

2 comentarios
El entorno de desarrollo estaba implantado, la arquitectura estaba definida, el análisis estaba en marcha. Era el momento de iniciar el desarrollo, antes de que el tiempo (y el cliente) se echara encima.

Pero pronto quedó claro que los servicios web SAP iban a tardar más de lo previsto. De hecho, ni siquiera disponiamos de los ficheros WSDL que describen el interfaz, que empezaron a llegar por cuenta gotas un par de meses después. Por supuesto, más de uno tuvo que ser modificado y remodificado. Esta situación nos obligó a ser extremedamente ágiles, cambiando la prioridad de los módulos, reconstruyendo los clientes webservices y modificando el modelo de la aplicación a menudo.

Metodología

No hemos seguido ninguna metodología concreta al pie de la letra. Aunque sí es cierto que nuestra forma de trabajar está ampliamente inspirada en Scrum y las prácticas ágiles que promueve. Sobre Scrum podeis leer más aquí y aquí.

Os dejo algunas notas de la estrategia que utilizamos:

  • Desarrollo incremental con una versión mayor por módulo. Empezando por el módulo de Administración.
  • Los requisitos fueron traducidos en nuestro JIRA a tareas de tipo New Request dentro de la versión correspondiente. Los cambios en los requisitos fueron añadidos como tareas de tipo Improvement. Desgraciadamente cuando la versión estaba cerrada no siempre se añadían como tareas hijas...
  • Simulación de los servicios web SAP mediante Mocks de los clientes webservices. Como ya he dicho los servicios no estaban, pero nosotros necesitabamos ya disponer de datos que pintar en las pantallas! Así que simplemente implementamos los interfaces de los servicios con unas clases tontas que devolvian datos más tontos aún. Mocking manual pero efectivo.
  • Testing de la capa Middleware. Toda la lógica de la aplicación está en nuestras clases service que son llamadas desde las pantallas mediante DWR. Los controladores web (Actions de Struts) practicamente sólo realizan navegación y precarga de campos de formularios. Focalizar el testing en la capa Middleware permitió independizarse totalmente de la capa Presentación y el servidor de aplicaciones, aumentando así la velocidad de desarrollo global.
  • Testing de la capa Acceso a base de datos. Para probar los distintos daos de esta capa usamos un script sql para inicializar la bbdd a un estado conocido junto con los tests transaccionales de Spring que automaticamente hacen rollback evitando la modificación del estado y la fácil configuración entre datasources dependientes e independientes del servidor de aplicaciones. Una más del montón de cosas que te facilita Spring.
  • Integración contínua. Básico en cualquier fase de test seria. Además de actuar como control de calidad de nuestro código. Pero de Hudson ya hablé en su día...
  • Estructura del proyecto. Para atajar la dificultad en un proyecto es básico tener una estructura inteligente y ordenada del mismo. Nuestra estructura de código fuente estaba formada por un gran paquete por módulo, más un paquete comun. Luego dentro de cada módulo, los subpaquetes web, dao, ws, modelo y services.
  • Tags, branches y merges. El cambio de prioridades entre módulos que sufrimos más el desarrollo incremental por módulos podrían habernos costado más de un disgusto serio sin una buena estrategia de control de versiones.

Dificultades

Hasta aquí parece que ha sido un paseo, pero en realidad hemos sufrido lo nuestro también. A parte del tema de la colaboración con el resto de equipos, tuvimos que hacer frente a varias dificultades en:

  • Integración mediante webservices. Se veía venir. Sinceramente e IMHO, los servicios web SAP están, como mucho, diseñados regularmente. Abundan los datos duplicados e innecesarios, no existen namespaces ni schemas comunes y aún nadie me ha podido explicar por qué existe un servicio web por cada operación! Además los WSDLs son generados por alguna herramienta SAP de forma automática que no cumple el WS-I. Lo que nos obligó a usar XMLBeans como OXM (Databinding Java-XML), aunque esto no tiene nada de malo, y también a tener que modificar a mano un par de WSDLs. Y luego está el tema de la infraestructura de red del cliente en producción y sus proxys, pero ésto también lo he contado ya.
  • Pruebas de los servicios web. Descubrimos muchos bugs en los servicios web SAP. Yo diría que sus equipos de desarrollo los probaban poco. Las modificaciones, a veces, ocasionaban nuevos bugs donde antes funcionaban. Pronto quedó claro que no tenían una fase seria de test. Al final tuvimos que programar nosotros las baterias de tests para los servicios web SAP.
  • Gestión de requisitos. Sabiamos que los requisitos iban a cambiar. Pero no tanto. El sistema de gestión de requisitos antes comentado no favorece el control de cambios en los requisitos, es demasiado frágil y requiere demasiado trabajo en mantener la descripción de la tarea inicial y las hijas, además de mezclarse aspectos de descripción de funcionalidad con pura implementación. En el futuro probaremos con una Wiki para los requisitos y el JIRA para las tareas exclusivamente con referencias al Wiki.
  • Formación. Inicialmente, y para mi sorpresa, el nivel de dominio del equipo en Spring e Hibernate era más bajo de lo esperado. Esto nos dió problemas especialmente en mapeos avanzados de Hibernate que provocaban que (1) algunas operaciones fallaran y (2) se realizaran más consultas de las necesarias. También destacar la dificultad, al principio, de trabajar con multiples ficheros de configuración Spring debido al número de módulos y las necesarias configuraciones para mocks y testing.
    Luego la cosa mejoro. Aunque a día de hoy Hibernate sigue sin convencer a más de uno pero con Spring todos han caido rendidos.
  • Proceso de sincronización. Todas las noches debe actualizarse una estructura de 7 tablas con PKs y FKs compuestas con casi 100 mil registros obtenidos mediante cientos de llamadas a 2 servicios web. Es una operación compleja y costosa, con o sin Hibernate. Fue necesario rediseñar los servicios web SAP para operaciones de consultas masivas que minimizaran el número de llamadas y optimizar los mapeos Hibernate así como los algoritmos usados. Al final pasamos de más de 1 hora de ejecución (tiempo inaceptable) a apenas 10 minutos.
  • Testing en la capa de presentación. En su momento no conseguimos hacer funcionar los tests funcionales web basados en Selenium en nuestro servidor de integración contínua, así que esta parte de test se hizo de forma manual. Como la aplicación era una aplicación web RIA bastante grande que tenía que funcionar en IE6, sumado a los cambios de requisitos y modificaciones en los servicios web, os podeis imaginar lo que hemos pasado...

Creo que no me dejo nada. Los temas de colaboración e implantación proximamente...

Historia de una integración (ii): La arquitectura

7 comentarios

El inicio de un proyecto siempre es un pequeño caos. Donde no había nada, ahora hay una multitud de cosas por hacer. Entre ellas, definir la arquitectura de la aplicación con la que guiar el posterior desarrollo. Para obtener la información necesaria, de forma paralela se debe iniciar también el análisis de los requisitos y contexto del proyecto.

La aplicación

La aplicación de esta historia -os recuerdo- es un front-end web Java que permite realizar acciones concretas sobre varios módulos de un sistema SAP.

Para no aburrir, resumiré los requisitos y el contexto del proyecto en
  • (i) aplicación dividida en módulos (uno por cada módulo SAP más un módulo Administración),
  • (ii) integración mediante webservices SOAP,
  • (iii) multiples servicios y todos, inicialmente, sin desarrollar ni definir su interfaz,
  • (iv) pantallas basadas en formularios web y tablas RIA,
  • (v) dos pantallas más complejas basadas en un potente grid de datos que permita manejar una gran cantidad de registros (alrededor de 200) sin paginación, ordenación por todas las columnas, modificación de algunos campos de forma inline y multiselección para ejecutar acciones sobre los registros seleccionados,
  • (vi) mantenimiento de una réplica sincronizada en base de datos de la estructura de centros y catálogo de materiales de SAP,
  • (vii) elevado número de usuarios, varios miles registrados, con picos de más de cien usuarios conectados simultaneamente,
  • (viii) ejecutable en IE6 y
  • (ix) equipo de desarrollo con dedicación parcial y formado principalmente en Hibernate y Struts.

Principios

La experiencia me ha enseñado la importancia de unas pocas reglas básicas que he convertido en los principios sobre los que procuro diseñar y desarrollar mis proyectos. Son estos:
  • Simplicidad (KISS, Keep it simple, stupid). En realidad una aplicación web no es nada compleja. Normalmente basta con aplicar el patrón de diseño MVC más una lógica y ordenada estructura de paquetes y clases. Y si la cosa se complica, no tener miedo de realizar los refactoring necesarios para volver a tener la complejidad controlada.
    Cuidado con la sobreingeniería. No te vuelvas loco con los patrones GoF si no estás creando un framework. Para una aplicación son más importantes los patrones GRASP.

  • Reutiliza, no repitas (DRY, Dont repeat yourself). Mucho cuidado con el copypaste y con el código pegamento y boilerplate. Utiliza detectores de código duplicado (pej. Checkstyle y PMD), crea componentes reutilizables y usa clases template para evitar el código boilerplate. El ejemplo más típico y dañino sería la gestión de conexiones y transacciones en base de datos.

  • Reutiliza, no reinventes (evita el sindrome NIH, Not invented here). Apache, Springsource, Eclipse, JBoss, Codehaus, Sun,... ¿de verdad no existe una solución éficaz a tu problema ya creada, documentada, probada y mantenida?

  • Diseña software facilmente testeable (TDD, Test Driven Design). Al menos las capas de negocio y datos deben poder ser probadas de forma sencilla, automatizada y sin necesidad de desplegar la aplicación en un servidor. No confundir con la metodología Desarrollo guiado por pruebas.

La arquitectura

La aplicación utiliza una arquitectura en N capas, estructurada en las capas de (i) integración con SAP, (ii) acceso a base de datos, (iii) lógica de negocio o middleware y (iv) presentación. A continuación pasaré a describir cada una de las capas y las tecnologías utilizadas en ellas.

Integración con SAP

El sistema SAP contaría con un XI, o infraestructura de intercambio, donde estarían definidos los distintos servicios web que usaría nuestra aplicación para realizar acciones concretas en los módulos SAP implantados.

Es la capa más importante. Al fin y al cabo es un proyecto de integración. No podía haber fallos ni improvisaciones. Así que para implementar los clientes webservices decidí usar Axis2. Es un framework que conozco muy bien, destaca por su madurez, rendimiento y sus altas capacidades de configuración y compatibilidad con casi todos los OXMs (Mapeador Objeto-XML) existentes.

Acceso a base de datos

La aplicación debía contar con su propia base de datos para la gestión de usuarios, datos propios y mantener una réplica sincronizada periódicamente de la estructura de centros y el catálogo de materiales gestionado en SAP.

A pesar de que el catálogo era enorme (cerca de 100 mil registros), el schema en sí no iba a contar con muchas tablas y era bastante sencillito. Por lo que el Oracle9 del cliente no iba a ser ningún cuello de botella.
Así que no ví mayor problema en usar Hibernate, con la esperanza de que nuestro supuesto dominio en él nos permitiera despreocuparnos relativamente de esta capa y ganar tiempo de desarrollo.

Middleware

Para implementar la capa de lógica de negocio no tuve muchas dudas, Spring como framework principal y dominante. Spring permite (i) integrar el resto de tecnologías que ibamos a usar y (ii) cumplir con los principios antes comentados, ambos de forma natural y sencilla. Además de aportar su motor de inyección de dependencias y sistema de AOP. En mi opinión, características básicas de cualquier desarrollo enterprise.

También hemos utilizado Spring Security como solución de seguridad, Quartz para las tareas programadas, la útil Commons Lang y el binomio Commons Logging/Log4j para el logging.

Presentación

Intentaré ser breve, como framework web decidí usar Struts1 (los motivos más abajo) para controlar la navegación hasta las pantallas principales.

Como sistema de plantillas para las pantallas, otro veterano, Tiles. Usar un sistema de plantillas es básico para mantener lo más simple posible las distintas jsps que formaban cada pantalla.

Dentro de cada pantalla está prohibido usar código Java, usamos Jakarta Taglibs como librería de etiquetas implementación de la estupenda especificación JSTL, la última gran especificación.

La parte RIA viene en 2 sabores, DWR y jQuery. DWR es un framework Ajax no muy conocido que permite invocar métodos de clases Java de la aplicación desde código Javascript en el navegador cliente. Es potentisimo, sencillo y muy configurable. Además cuenta con soporte para Reverse Ajax.

Mientras que JQuery aporta toda la magia visual con su legión de plugins y el tan necesario toque cross-browser. Destacar los widgets de jQuery UI y los plugins jQuery Validation y jQuery Grid.

Alternativas desestimadas

Ahora lo leo y parece sencillo. No lo fue. Dejaré las valoraciones para otro día...
Lo que sí voy a hacer es nombrar algunas alternativas que descarté durante el proceso de diseño y porqué.
  • Cualquier otro framework web. Sí, ya sé que Struts1 está pasadísimo, más muerto que SOA y el propio Java juntos, y hay otros frameworks web mejores. Pero eso no lo convierte en un mal framework y es él que domina mi equipo y yo mismo. Tampoco había tiempo para aprender otro y aunque lo hubiera, personalmente, no tengo claro cúal debería ser su sucesor, ¿Struts2, Spring MVC, GWT, Seam, JSFs, Wicket,...?
    Como ya he dicho sólo lo ibamos a usar para la navegación, así que nos sobraba.
  • OSGI. Sí es una aplicación modular, pero en realidad la necesidad de activar y desactivar módulos es practicamente nula.
  • JPA. ¿Para qué? Si vamos a usar Hibernate y punto. Y encima con características específicas como el Criteria o el delete_orphan. IMHO esta especificación llega tarde y además mal.
  • Ext-Js. No sólo es una delicia visual, es realmente eficiente en comparación con el resto de clones que han ido saliendo. De hecho, lo estabamos evaluando en otro proyecto más pequeño cuando nos pilló el cambio de licencia. Ahora usamos jQuery y estamos más que contentos.

Así que ya teniamos el entorno de desarrollo y el diseño general de la aplicación definidos. Era el momento de empezar el desarrollo. Pero eso ya será otro post...

Cliente webservice Axis2, Http version y Squid

1 comentarios
Este ha sido mi último marrón. Un cliente webservice con Axis2 que habia desarrollado hacía tiempo como parte de un evolutivo de una importante aplicación. El software estaba probado en los entornos de desarrollo y pruebas. El proyecto validado, entregado y cerrado. Sólo que por esas cosas que pasan, habían ido pasando los meses y aún no se habia puesto en producción.

Al final llega el gran día y toma AxisFault:

Unable to sendViaPost to url[http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
org.apache.axis2.AxisFault: Transport error: 501 Error: Not Implemented
at org.apache.axis2.transport.http.HTTPSender.handleResponse(HTTPSender.java:298)
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:192)
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:77)
...

Investigando el error descubrí que lo de Not Implemented se refiere a la versión 1.1 del protocolo HTTP. Me encantan los mensajes de error descriptivos!

Pero, ¿qué era lo que no soportaba HTTP/1.1? Resultó ser un Squid que habian introducido en la infraestructura de red durante estos meses de espera para hacer de proxy de salida del servidor de la aplicación.

Al final, y como solución de compromiso mientras los de Sistemas miran cómo hacer que soporte HTTP/1.1, hemos modificado la aplicación para hacer configurable la versión de HTTP a usar por el cliente webservice. El código es muy sencillo. A continuación un ejemplo de cómo configurar las opciones del stub para usar HTTP/1.0:


...
options.setProperty(
org.apache.axis2.transport.http.HTTPConstants.HTTP_PROTOCOL_VERSION
, org.apache.axis2.transport.http.HTTPConstants.HEADER_PROTOCOL_10);
...

Vistos los problemas que estamos sufriendo ultimamente, he decidido mantener siempre configurables la versión de HTTP y el Chunked. De hecho, usando Chunked a false y HTTP/1.1 el Squid tampoco se quejaba.

Aquí podeis encontrar más información sobre cómo configurar estas y otras opciones HTTP de un cliente webservice, como el timeout y el character set encoding.

Resolviendo problemas de interoperabilidad Axis2-SAP R/3

6 comentarios
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.

Autenticación HTTP Basic en cliente webservice con Axis2

1 comentarios
Es más que habitual encontrarse con que el uso de los servicios web está restringido. La forma más común y sencilla de implementar (y de romper) es la autenticación HTTP Basic, consistente en el típico par usuario, password.

Usar la autenticación HTTP Basic en un cliente webservice con Axis2 es inmediato. Supongamos que ya hemos generado el stub mediante wsdl2java y tenemos la url del endpoint más el par usuario, password. El código para inicializar el cliente webservice sería el siguiente:


Options options = new Options();
EndpointReference targetEPR = new EndpointReference(urlEndpoint);
options.setTo(targetEPR);
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername(usuario);
auth.setPassword(password);
options.setProperty(HTTPConstants.AUTHENTICATE, auth);
stub._getServiceClient().setOptions(options);


También podriamos estar usando un cliente ServiceClient AXIOM a pelo. Una opción poco ortodoxa pero práctica para mensajes simples. En este caso sería todo igual salvo el último paso:


ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);

Cómo generar un cliente webservice con Ant y Axis2

2 comentarios
Crear un cliente webservice con Axis2 es relativamente sencillo. En el pasado ya realicé un tutorial donde expliqué cómo hacerlo con ayuda del plugin Codegen Wizard de Axis2 para Eclipse. Crear un cliente webservice con Ant también es muy sencillo a poco que sepas algo de Ant, una herramienta indispensable antes o después.

El proceso consiste en ejecutar la herramienta WSDL2Java de Axis2 sobre un fichero WSDL para generar el código Java del Stub y las clases OXM (mapeador objeto-XML) de los mensajes del servicio web para posteriormente copiar el código generado al proyecto. Y todo con un simple script de Ant.

Requisitos

Será necesario tener instalado Axis2, basta con bajarse la versión Standard y descomprimirla, y Ant, el propio eclipse ya lleva incorporada una versión de Ant.

Definición de propiedades

El script usará las siguientes propiedades:
  • axis2.home: directorio donde está instalado Axis2.
  • output.wsdl2java.dir: directorio donde el wsdl2java generará el código.
  • src.dir: directorio dentro del proyecto donde se copiará el código generado.
  • wsdl.uri: ruta hasta el fichero wsdl.
  • stub.package.name: nombre del paquete para la clase Stub.
  • xsd.namespacetopackages: equivalencia entre los namespaces de los schemas xsd que definen los mensajes y los correspondientes paquetes donde generar las clases OXM.
  • synconly: booleano para indicar si queremos generar un Stub sólo para peticiones síncronas y no asíncronas.

Las propiedades pueden definirse en el propio script o externalizarse a un fichero de propiedades (todas menos src.dir). Un ejemplo de lo primero:
<property name="axis2.home" value="/deps/axis2-1.4.1" />
<property name="output.wsdl2java.dir" value="build/codegen" />
<property name="src.dir" value="src" />
<property name="wsdl.uri" value="resources/wsdl/myWsdl.wsdl" />
<property name="stub.package.name" value="ws.client" />
<property name="xsd.namespacetopackages" value="http://myService/xsd=ws.client.xsd" />
<property name="synconly" value="true" />

Definición del task wsdl2java

El task wsdl2java no es un task incluido en la distribución de Ant, por tanto hay que importar su definición. Para ello hay que cargar en el classpath los jars de Axis2 y luego hacer la definición.

<path id="axis2.classpath">
<fileset dir="${axis2.home}/lib">
<include name="**/*.jar" />
</fileset>
</path>

<taskdef name="wsdl2java" classname="org.apache.axis2.tool.ant.AntCodegenTask"
classpathref="axis2.classpath" />

Ejecutar WSDL2Java

Finalmente llega el momento de definir el target que ejecutará el wsdl2java. Antes preparará el directorio de salida y después copiará el código generado al proyecto. Aquí está:

<target name="run-wsdl2java-client"
description="Genera un cliente webservice apartir de un wsdl">

<mkdir dir="${output.wsdl2java.dir}" />
<delete dir="${output.wsdl2java.dir}" includeemptydirs="true" />

<wsdl2java
output="${output.wsdl2java.dir}"
wsdlfilename="${wsdl.uri}"
synconly="${synconly}"
unpackClasses="true"
serverSide="false"
databindingName="adb"
packageName="${stub.package.name}"
namespacetopackages="${xsd.namespacetopackages}"
/>

<copy todir="${src.dir}" overwrite="true">
<fileset dir="${output.wsdl2java.dir}/src">
<include name="**/*.java"/>
</fileset>
</copy>
</target>

El parámetro unpackClasses="true" indica que las clases OXM deben generarse como clases independientes y no como clases internas de la clase Stub.
El parámetro serverSide="true" indica que queremos generar un cliente webservice.
El parámetro databindingName="adb" indica el motor databinding XML a usar para generar las clases OXM. En este caso es ADB (Axis DataBinding). No está parametrizado, este script sólo funciona con ADB.

Si se usa XMLBeans se genera además código Java para todos los tipos de datos XSD y unos ficheros binarios usados por las clases OXM. Cada cosa va en un directorio diferente y todos deben incluise en el classpath del proyecto. Lo ideal es compilar tanto las clases OXM como las clases de tipos XSD y crear un jar con los fuentes, los class y estos ficheros binarios para añadirlo al directorio lib del proyecto.

Ha sido fácil y rápido, ¿no? Ya sólo queda probarlo. En el directorio samples del Axis2 encontrareis varios ficheros wsdl para probar. Para ejecutar el script Ant a mi me encanta la vista Ant del Eclipse.

Cómo usar parametros para un webservice en Axis2

1 comentarios
Practicamente cualquier aplicación medio seria necesita usar parametros de configuración. Un webservice no iba a ser diferente.

Alternativas hay para todos los gustos o más bien para todas las necesidades, desde crear un fichero properties para ese par de parametros de configuración a uno xml para configuraciones algo más estructuradas. Incluso he llegado a ver usar el fichero properties-service.xml de JBoss. Una mala práctica que no aconsejo, mejor el properties o xml empaquetado dentro de la aplicación y evitamos ataduras innecesarias.

Pero en el caso de desarrollar un webservice con Axis2, el propio Axis2 nos ofrece otra alternativa: el fichero services.xml del propio webservice.

Veamos un ejemplo de cómo almacenar parametros de configuración simples y complejos dentro del fichero services.xml:

<service name="miWebservice">
<description>La descripcion de mi webservice</description>
<parameter name="ServiceClass">path.to.my.ServiceClass</parameter>
<parameter name="UnParametroSimple">UnValorSimple</parameter>
<parameter name="UnParametroComplejo">
<mailconfig>
<username>Raska</username>
<password>caracola</password>
<host>http://mail.mydomain.org</host>
</mailconfig>
</parameter>
<operation name="operacion">
</operation>
</service>

Y ahora para obtenerlos hay que hacer uso de la clase MessageContext, obtener el contexto actual y usar el método getParameter teniendo en cuenta que estamos recuperando objetos de tipo OMElement. Un código para el ejemplo anterior seria el siguiente:


MessageContext msgContext = MessageContext.getCurrentMessageContext();
Parameter parametroSimple = msgContext.getParameter("UnParametroSimple");
Parameter parametroComplejo = msgContext.getParameter("UnParametroComplejo");

System.out.println("Parametro Simple " + parametroSimple.getParameterElement().getText());
System.out.println("ParametroComplejo " + parametroComplejo.getParameterElement());

Cómo obtener la dirección IP de los clientes de tu webservice en Axis2

0 comentarios
Suele ser habitual realizar una auditoría sobre las invocaciones de nuestros webservices. Además de la operación, fecha y hora, petición y respuesta, una de las cosas más interesantes a guardar es la dirección IP del cliente. Este dato quizás no es tan trivial de obtener, hay que hacer uso del objeto MessageContext asociado al mensaje recibido. Por lo que aquí os dejo el código:


MessageContext msgCtx = MessageContext.getCurrentMessageContext();
String remoteAddress = (String)msgCtx.getProperty("REMOTE_ADDR");

Otras cosas interesantes que se pueden obtener son los objetos ServletContext y HttpServletRequest:


ServletContext servletContext = (ServletContext)msgCtx
.getProperty("transport.http.servletContext");

HttpServletRequest httpServletRequest = (HttpServletRequest)msgCtx.
getProperty("transport.http.servletRequest");

Cómo incluir el stacktrace dentro de un AxisFault en Axis2

1 comentarios

La vida da muchas vueltas y heme aquí de nuevo trabajando con Axis2, ueeee! (auto-ola para mi).

Una cosa que siempre me ha parecido muy molesta es que los AxisFault no incluyen la información relativa al stacktrace de la excepción que los generó. Esto puede llegar a ser muy molesto, especialmente durante las pruebas de integración donde no sueles disponer de acceso directo a los ficheros de log. Afortunadamente en Axis2 existe una solución muy sencilla.

Para incluir dentro de un AxisFault el stacktrace de la exception que lo generó, basta con cambiar estos dos parámetros del fichero de configuración de Axis2 (conf/axis2.xml) de false a true:
<parameter name="sendStacktraceDetailsWithFaults">false</parameter>
<parameter name="DrillDownToRootCauseForFaultReason">false</parameter>
y a continuación reiniciar o redesplegar el Axis2.