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

Buenas practicas para desarrollar servicios web SOAP

12 comentarios
Como complemento a mi último post, Arquetipo de WSDL interoperable, he decidido publicar este post con varias buenas prácticas para desarrollar servicios web SOAP. Como siempre, son sólo buenas prácticas según mi criterio, conocimiento y experiencia.

  • Analiza qué servicios web y con qué operaciones hay que desarrollar. Parece de perogrullo, pero es uno de los fallos más repetidos. Según mi experiencia suelen darse 2 esquemas a la hora de desarrollar servicios web: (i) el servicio web dios con todas las operaciones para él y (ii) un servicio web por operación. Ambos son malos. El primero incluso peor. Así que piensa y diseña servicios web con las responsabilidades bien repartidas, que sean cohesivos, extensibles, escalables y reutilizables.
  • Escribe tu mismo el fichero WSDL (Contract-First). Es el interfaz, el contrato y, en definitiva, la clave para una interoperabilidad real e independiente de la tecnología. Además los generadores de WSDL pueden introducir dependencias con una tecnología concreta. Por eso merece la pena aprender a escribir WSDL (aquí) y schemas XSD (aquí).
  • A la hora de diseñar el interfaz de las operaciones, ten siempre en cuenta que es mucho más eficiente un único mensaje enorme que el equivalente en multiples mensajes.
  • Sé coherente con la nomenclatura de namespaces de la organización. No hay nada que de peor impresión que un servicio web que no ha cuidado los namespaces.
  • El WSDL debe ser compatible con el WS-I Basic Profile. El WS-I Basic Profile es un conjunto de especificaciones y buenas practicas definidas por la industria para obtener servicios web interoperables. Actualmente la última versión final publicada es la 1.1. Como mínimo, evita siempre los estilos RPC y sus tipos de datos no XML (SoapArrays), en su lugar usa el estilo Document/literal.
  • Usa http://localhost:puerto como dirección url del endpoint y deja que sea el motor de webservices el encargado de sustituirla por la real. Así evitarás tener un fichero WSDL por entorno.
  • Separa la definición de los mensajes del fichero WSDL. Para ello, diseña por separado un schema XSD donde se definan los mensajes y que sea importado por el fichero WSDL. Las principales ventajas son (1) reduce el tamaño/complejidad del WSDL, (2) permite utilizar editores especializados para el diseño del schema XSD y (3) permite reutilizar schemas y namespaces.
  • Define los mensajes de forma detallada mediante las restricciones de los schemas XSD. De esta forma podrás validar los mensajes a nivel de XML mediante el api XML u OXM que uses, sin necesidad de implementar código propio.
  • A la hora de diseñar el schema XSD, crea tipos y elementos globales (a nivel raíz) para poder reutilizarlos, tanto a nivel de elementos XML como clases del lenguaje de implementación del servicio web.
  • Además, usa minOccurs=0 para definir un elemento como opcional y nillable=true para indicar que un elemento puede ser vacío pero siempre estará presente en el mensaje XML. Ojo, no es lo mismo.
  • Si necesitas enviar ficheros adjuntos (attachments), hazlo a nivel de http attachment y no como un elemento del mensaje XML.
  • Automatiza el proceso de generar el Skeleton y las clases OXM de mensajes del servicio web a partir del WSDL (wsdl2code).
  • Para realizar pruebas unitarias del servicio web no necesitas desplegarlo, puedes programar tus tests a nivel de la clase Skeleton. Ahorraras mucho tiempo y ya desplegarás para las pruebas de integración o alguna demo.
  • Guarda log de los mensajes de entrada y salida junto con datos del cliente (ip, usuario), a nivel de fichero o base de datos.
  • Redacta un documento Guía de pruebas de integración que sea completo e incluya casos de error y no sólo los casos básicos.

Arquetipo de WSDL interoperable compatible con WS-I Basic Profile 1.1

3 comentarios
En este post voy a publicar un WSDL de ejemplo que cumple con el WS-I Basic Profile 1.1.

La clave de la interoperabilidad entre servicios web SOAP está en su interfaz WSDL. El WS-I Basic Profile es un conjunto de especificaciones y buenas prácticas definidos por la industria para desarrollar servicios web interoperables independientemente de la tecnología con que fueron desarrollados. Su última versión final es la 1.1 y debería ser un must-know para todos aquellos que tengan que definir un WSDL.

El WSDL de ejemplo está diseñado para que use un schema XSD donde definir los mensajes de petición y respuesta de las operaciones. De esta forma se puede usar un editor de XSD como ayuda para diseñar la estructura de los mensajes, que es la parte más importante del WSDL y que requiere el verdadero esfuerzo intelectual. Dejando de esta forma el proceso de definir el fichero WSDL a un mero trámite de copy&paste.Además es una buena práctica en una SOA publicar los schemas xsd para reutilizar sus elementos.

Este WSDL sólo tiene 1 operación. Además usa los siguientes literales como ejemplo:
  • Nombre del servicio: nombreServicio
  • Nombre de la operación: nombreOperacion
  • TargetNamespace del servicio: http://dominio/ws/nombreServicio
  • TargetNamespace del schema xsd: http://dominio/ws/nombreServicio/schema/msg

El fichero schema xsd nombreServicio_msg.xsd sería el siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:tns="http://dominio/ws/nombreServicio/schema/msg"
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://dominio/ws/nombreServicio/schema/msg">
<element name="nombreOperacionRequest">
<complexType>
<sequence>
<element name="campo1" type="string"/>
<element name="campo2" type="string"/>
</sequence>
</complexType>
</element>
<element name="nombreOperacionResponse">
<complexType>
<sequence>
<element name="campo1" type="string"/>
<element name="campo2" type="string"/>
</sequence>
</complexType>
</element>
</schema>
La operación del servicio tiene 2 elementos de entrada y 2 de salida, todos de tipo string, a modo de ejemplo. Puedes modificar los mensajes existentes o crear mensajes para nuevas operaciones a tu gusto. No olvides modificar el targetNamespace.
Si el schema xsd se complica puedes plantearte dividirlo por operaciones o por entrada y salida.
Este fichero puede ser descargado aquí.

El fichero wsdl nombreServicio.wsdl sería el siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="nombreServicio"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:tns="http://dominio/ws/nombreServicio"
xmlns:msg="http://dominio/ws/nombreServicio/schema/msg"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/"
targetNamespace="http://dominio/ws/nombreServicio">
<!-- Importacion de schemas -->
<import namespace="http://dominio/ws/nombreServicio/schema/msg"
location="./nombreServicio_msg.xsd"/>
<!-- Definicion de mensajes -->
<message name="nombreOperacionRequest">
<part name="body" element="msg:nombreOperacionRequest"/>
</message>
<message name="nombreOperacionResponse">
<part name="body" element="msg:nombreOperacionResponse"/>
</message>
<portType name="nombreServicio">
<!-- Relacion Mensaje-Operacion -->
<operation name="nombreOperacion">
<input message="tns:nombreOperacionRequest"
wsaw:Action="urn:nombreOperacion"/>
<output message="tns:nombreOperacionResponse"
wsaw:Action="urn:nombreOperacion"/>
</operation>
</portType>
<binding name="nombreServicioBinding" type="tns:nombreServicio">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<!-- Definicion de operaciones -->
<operation name="nombreOperacion">
<soap:operation soapAction="urn:nombreOperacion"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="nombreServicio">
<port name="nombreServicioPort" binding="tns:nombreServicioBinding">
<soap:address location="http://localhost:8080"/>
</port>
</service>
</definitions>

Lo primero sería modificar los nombres del servicio, operación y targetNamespaces de ejemplo. Puedes añadir nuevas operaciones a tu gusto. Como puedes ver, he puesto comentarios indicando los sitios que deberían ser modificados.
No cambies la url del endpoint. Por lo general, los servidores de webservices detectarán la url y realizarán la modificación de forma automática. De este modo te evitas tener una copia del WSDL por entorno (desarrollo, pruebas, producción, etc.).
Este fichero puede ser descargado aquí.

Una vez realizadas las modificaciones convenientes no olvides validarlo todo, el schema xsd y el wsdl.

Historia de una integración (iv): Colaboración

1 comentarios
La complejidad de un proyecto también radica en las personas involucradas, y no sólo en la tecnología. A más personas, mayor complejidad.

Personajes

Esta historia tiene muchos personajes. Además de los usuarios, el cliente, mi equipo y mi jefe, están los distintos equipos de cada módulo SAP con su consultor a la cabeza. Y por supuesto el analista interlocutor del cliente, el llamado Product owner de Scrum, como nexo de todos.

Él es el verdadero héroe de esta historia. Trabajador, comprometido, eficaz, comprensivo, dialogante mediador y afable. Rompe con todos las ideas preconcebidas que se pueden tener del cliente funcionario.

La clave para vencer la complejidad humana está en la colaboración. Parece fácil, al fin y al cabo todos teniamos el mismo objetivo: sacar el proyecto adelante.

Pero no sólo fue difícil, en algunos casos ha sido absolutamente agotador. Las personas mediocres tienden a adoptar una postura defensiva y esquiva, están más preocupados por salvar su culo que por el proyecto. Convierten cualquier asunto en una crisis y no se dan cuenta de que así sólo ponen más de manifiesto su ineptitud.

Afortunadamente también había buenos profesionales con los que ha sido una satisfacción trabajar. En realidad me voy a ahorrar los detalles. Supongo que lo entenderéis.

Comunicación

En cualquier caso la mejor forma de colaborar de forma productiva es cuidando la comunicación y las relaciones interpersonales. No hay por qué llevarse mal sólo por ser de diferentes empresas.
Respecto a la comunicación me gustaría hacer una serie de observaciones/recomendaciones:

  • Usa el medio de comunicación más adecuado. Cara a cara, teléfono o correo electrónico. El correo electrónico es el más flexible pero también es el más frio y propenso a malentendidos, tanto de significado como de actitud.
  • Evita discusiones por correo, usa el teléfono y luego mandas un correo resumen.
  • Comunícate con la persona adecuada directamente. Evita los intermediarios, simplemente ponles en copia o al tanto.
  • Asegúrate 2 veces antes de señalar el fallo de otro.
  • Incluye siempre toda la información relativa que puedas, como mensajes, capturas de pantalla, fecha y hora, etc.
  • Ser amable o pedir disculpas no es pecado.
  • Sé comprensivo. Ponte siempre en el lugar del otro. Piensa que no eres el único que tiene trabajo y que tú también te equivocas.

Problemática de un proyecto de integración

Los problemas técnicos de colaboración en un proyecto de integración se resumen en disponibilidad de entorno y de juegos de datos de pruebas. El entorno de desarrollo/pruebas no siempre está disponible. Y aún con el entorno disponible, no siempre existe el juego de datos requerido.

Para minimizar esto lo mejor es usar Mocks que simulen el entorno y devuelvan los datos requeridos. De esta forma te independizas del entorno hasta el último momento, las pruebas de integración. Es la evolución del llamado hardcodeo.

Pero para que los Mocks sean realmente eficaces es necesario que los interfaces estén clara y explicitamente definidos. No sólo el nombre, tipo y orden de los campos de entrada y salida. También los formatos (fechas, cantidades, etc.). Esta definición debe hacerse en un lenguaje formal y procesable por una máquina para (1) evitar errores de interpretación y (2) automatizar la construcción de clientes y servicios. En el caso de los servicios web SOAP se usa el estándar WSDL.

Finalmente me gustaría destacar la importancia del documento Pruebas de integración. Debe estar actualizado y contener un completo juego de casos de prueba que cubra toda la casuística de entrada y salida. Incluidos los posibles errores. Además estas pruebas deben automatizarse cuanto antes para poder usarse como pruebas de regresión.


En resumen, las personas somos más difíciles que la tecnología. Por lo que colaborar no es sencillo. Pero es la única forma de sacar un proyecto adelante. Haz más fácil el trabajo de los demás y el tuyo será más fácil. No seas mezquino.

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

Historia de una integración (i): El principio

9 comentarios
Esta es la historia de un proyecto de desarrollo software. Como toda buena historia tiene momentos difíciles, personajes complejos, un final féliz y más de una lección que aprender.

Antecedentes

En enero del 2008 comenzó una nueva etapa profesional para mi, cambié de compañía en búsqueda de nuevos retos y proyectos donde trabajar, y continuar aprendiendo, en lo que verdaderamente me apasiona, las nuevas tecnologías de desarrollo software. Atrás dejé una cómoda posición como Analista en una factoria de software al cargo de varios aburridos y antediluvianos proyectos de mantenimiento de una importante TELCO.

Así me encontré al frente de un equipo de desarrollo de 3-6 personas, residente en un importante cliente del sector sanitario público, y dirigiendo un buen número de proyectos Java, consistentes en nuevos desarrollos y mantenimientos.

Pero no sólo yo tenía ganas de cambios para el 2008. En una decisión tan valiente como inesperada, el cliente decide implantar un completo sistema SAP R/3 para sustituir la gran mayoría de sus sistemas de gestión.

Para esta obra faraónica se ha confiado en la típica pirámide de empresas, compuesta por (i) la super multinacional que aporta el nombre, más la élite, (ii) la cárnica el grupo hispano líder que aporta referencias de éxito en proyectos similares más la clase media y (iii) la empresa regional con aspiraciones que aporta el toque local, instalaciones y una masa de programadores a buen precio. Una organización digna de un imperio persa.

El proyecto

Mi parte en la historia sería la de dirigir un proyecto consistente en desarrollar una aplicación web Java que hiciera de front-end para varios módulos del futuro SAP R/3 del cliente. El proyecto empezó oficialmente en junio con la idea de llevarlo de forma paralela a la implantación de SAP. El objetivo era poner en funcionamiento una primera versión para el 1 de enero del 2009 para un número de usuarios controlado y poco a poco ir difundiendo su uso. A día de hoy la aplicación está implantada de forma completa y funcionando estable y eficázmente.

Como os imaginaréis ha sido una experiencia apasionante pero también muy exigente. Aunque me ha hecho pasar más de un trago amargo, en general estoy satisfecho con su resultado final y sobretodo con lo aprendido por el camino. Un camino que intentaré plasmar en esta serie de posts que espero se conviertan en un útil ejercicio de retrospectiva al que estais todos invitados.

Ecosistema software

No quería cerrar el post sin contar algo de verdad. Así que describiré las distintas partes que forman el ecosistema software que he ido construyendo desde mi llegada.
  • Eclipse. Una de las primeras decisiones que tomé fue usar Eclipse JEE como ide principal, por su potencia como editor e integración con el resto de herramientas y librerias que usamos. Anteriormente se usaba una antiquísima versión del IntelliJ IDEA pero no entraba en los planes corporativos adquirir licencias más modernas.
  • CVS. Es el sistema de control de versiones que tiene implantado nuestro cliente para todos sus proyectos. No hay más. Mi parte aquí se redució a fomentar algunas buenas prácticas de uso, principalmente a incorporar las dependencias de cada proyecto en su estructura.
  • Tomcat. Las aplicaciones se implantan en un servidor JBoss 3.2.6 y en un 4.2.2 las más recientes, pero en desarrollo usamos un Tomcat 6 como servidor individual por su mayor velocidad de arranque y fácil integración con Eclipse. Nuestras máquinas de desarrollo no son ninguna maravilla y Eclipse no se integra con JBoss 3.2.6 por si solo (sí con el 3.2.3), para ello necesitabamos las JBoss Tools. Pero entonces todo el entorno iba a pedales, cuando con Tomcat 6 vuela.
  • ANT. El cambio a Eclipse-Tomcat y el hecho de incoporar las dependencias a la estructura de proyecto obligó a crear nuevos scripts Ant para automatizar las tareas de construcción de los proyectos. Aunque sólo los nuevos proyectos y los antiguos más significativos han sido migrados al nuevo entorno.
  • Hudson. No fue hasta el último trimestre cuando conseguimos implantar Hudson como servidor de integración continua. Actualmente realiza las tareas de construcción, testing unitario y análisis de código Java con los plugins de Emma, Checkstyle y Findbugs.
  • JIRA. Como herramienta de gestión de proyectos/tareas continuamos usando una antigua versión de JIRA. Es una maravilla y eso que no creo que estemos aprovechando todas sus posibilidades. Sólo echo de menos un wiki principal para todos los proyectos o individual por proyecto.
Mis planes para este año implican las siguientes mejoras:
  • Selenium. Hemos estado experimentando con Selenium para hacer testing funcional de aplicaciones web. Sin embargo estamos teniendo problemas a la hora de ponerlo en funcionamiento en el Hudson. Lo que está dificultando mucho su aceptación y uso generalizado. Aún así lo encuentro básico para dar el siguiente paso de calidad en nuestro modelo de desarrollo. Todos sabemos el infierno que es actualmente el desarrollo web...
  • Maven. Aunque Ant es una herramienta genial, el elevado número y hetereogeneidad de proyectos que llevamos hace difícil el mantenimiento de los scripts. Por eso y otras razones quiero probar Maven en uno o dos proyectos serios.
  • Mylyn. Mylyn es un plugin para integrar Eclipse con la mayoría de sistemas de control de tareas/tickets de forma avanzada. No sólo permite tener visibilidad de los tickets en Eclipse, también dota de memoría a Eclipse para recordar qué ficheros del proyecto están asociados con cada tarea. Con lo primero espero, sobretodo, mejorar la trazabilidad entre lo que hace el código realmente y lo que dice la descripción de la tarea.
  • Wiki. Tengo ganas de probar una wiki para gestionar la documentación interna que vamos generando, en lugar de, como hacemos ahora, crear y copiar documentos word a una carpeta compartida. También me gustaría probarla como herramienta de especificación de requisitos de los proyectos con capacidades reales de colaboración y control de versiones automatizado. La idea sería enlazar desde la descripción de las tareas en el Jira a las páginas del wiki.
Con ésto doy por terminada esta primera parte de introducción y ecosistema. En la segunda me centraré en la arquitectura de la aplicación.

Participación en el podcast Servicios Web de javaHispano

1 comentarios
La semana pasada fue publicado el podcast sobre SOA y Servicios Web (SOAP/REST) de javaHispano en el que tuve el privilegio de participar junto a Leonardo de Seta, Alfredo Casado y Jorge Rubira, como conductor y productor del podcast.

La experiencia me encantó. En cuanto pasaron los típicos primeros minutos de nerviosismo escénico, me sentí muy cómodo y disfruté mucho charlando durante más de una hora con estos 3 fenómenos de nuestro sector.

El podcast dió para mucho, sin duda el tema lo merecía. Lejos del debate fanático SOAP vs REST que recorre internet, el mensaje que intentamos transmitir es que ambas son tecnologías perfectamente válidas para integrar sistemas, y más que enfrentarse vienen a cubrir un ámbito diferente cada una, con un amplio solapamiento entre ambas. La dificultad radica, por tanto, en saber elegir cúal se adapta mejor a una situación particular.

Por tanto, en realidad la problemática de la integración de sistemas no es sólo una cuestión sobre tecnología (implementación) sino que cobra mucha más importancia la pericia de las personas que deben analizar y diseñar inteligentemente los servicios que poblarán la SOA de una organización.

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 invocar un webservice desde eclipse

1 comentarios
Otra herramienta que he descubierto en mi vuelta a los webservices es el Web Services Explorer de eclipse, una de las muchas aportaciones de IBM al ide que permite invocar servicios web de una forma visual y relativamente sencilla desde nuestro eclipse.

Para usarlo hay que tener instalada la Web Tools Plataform en tu eclipse (lo más cómodo es bajarse el all-in-one) y pulsar en la opción Run -> Launch the Web Services Explorer.

Lo siguiente será seleccionar el webservice a invocar, para ello podemos cargar su WSDL pulsando en el segundo botón de la derecha (WSDL Page) y luego en WSDL Main en Navigator.
A continuación debemos introducir la URL donde esté publicado el WSDL del servicio web y pulsar en Go.

Tras unos instantes, si todo va bien, se habrá generado un cliente para el webservice y podrás ver sus operaciones y sus endpoints. Estos últimos son editables.

A partir de aquí es tan sencillo como seleccionar una operación y rellenar los datos necesarios para invocar al servicio web. Las peticiones y respuestas se pueden ver tanto en el interfaz gráfico (modo Form) como en XML (modo Source).

Como punto negativo decir que a veces el interfaz gráfico no se genera correctamente con mensajes muy complejos y además no es que sea muy intuitivo. Aunque no lo parezca, si haces doble-click sobre los títulos de los paneles se maximizan.

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.