jueves, 24 de junio de 2010

XML con PostgreSQL

En el artículo Alternativas EAV con XML expliqué cómo se podía implementar una mejora del modelo Entity Attribute Value (Entidad-Atributo-Valor) usando XML. Este artículo es, en alguna medida, una continuación de aquél, cubriendo ciertos aspectos importantes sobre la consulta a éstos campos o cualquier otro campo que contenga xml. El uso de las características de este artículo requiere que la instalación de postgresql se haya realizado con el soporte xml (configure --with-libxml).

Serialización/deserialización XML de campos varchar
Hay ocasiones en que necesitamos que los campos que contienen XML sean de tipo caracter y no de tipo xml nativo. Una razón para hacer eso, por ejemplo, es que estemos usando un ORM. En algunos casos, pongamos por ejemplo PostgreSQL con Toplink Essentials (incluído de serie en Glassfish 2.1), no hay forma (al menos yo no la he encontrado) de que el ORM haga mapping de campos de tipo xml. Para estos casos, en primer lugar, debemos producir un valor de tipo xml a partir de datos carácter, para lo que podemos usar la función xmlparse o realizar un type cast a xml usando la sintaxis tradicional de PostgreSQL expression::type o bien usando la sintaxis SQL-92 estándar CAST ( expression AS type ), así:

SELECT XMLPARSE( DOCUMENT campo)
FROM tabla
WHERE campo  is not null
<=>
SELECT cast(campo as xml)
FROM tabla
WHERE campo is not null
<=>
SELECT campo::xml
FROM tabla
WHERE campo is not null



Consultas: la función xpath

Para procesar valores de tipo xml, PostgreSQL ofrece la función xpath, que evalúa expresiones XPath 1.0.

xpath(xpath_expr, xml_value[, nsarray])

La función xpath evalúa la expresión XPath xpath_expr contra el valor XML xml_value (debe ser un documento XML bien formado), devolviendo un array de valores XML correspondiente al conjunto de nodos producidos por la expresión XPath. El tercer argumento, opcional, es el array bidimensional de espacios de nombress (nombre espacio de nombres,URI espacio de nombres) que use el documento XML xml_value.


Por ejemplo, dado un campo campo de la tabla tabla, de tipo varchar(2048), podríamos consultar el contenido así (a partir de este momento usaremos la sintaxis del último ejemplo, la tradicional de PostgreSQL, por ser la más sencilla):

Consulta
Resultado
SELECT campo::xml
FROM tabla
where campo is not null
campo
----------------------------------------------------------
<xmlData><data name="incidencia">
<data  value="tiempo"  name="motivo"/></data></xmlData>
<xmlData><data name="incidencia">
<data value="hardware"  name="motivo"/></data></xmlData>
<xmlData><data name="incidencia">
<data value="hardware"  name="motivo"/></data></xmlData>
<xmlData><data name="cantidad" value="2"></xmlData>
<xmlData><data name="cantidad" value="3"></xmlData> 



Es importante recordar que la función xpath devuelve un array de valores XML. Por ejemplo, si deseamos consultar sólo el contenido de aquellos valores de elementos data cuyo name es "motivo", por eso la siguiente consulta nos devuelve 4 filas. Es decir, de las cuatro filas en las que campo tiene valores, sólo dos de ellas tiene un elemento data con name igual a 'motivo', pero como xpath devuelve un array de valores, en las los dos últimas filas se devuelve un array vacio.


Consulta
Resultado
SELECT  xpath('//data[@name=''motivo'']/@value',campo::xml) as motivos
FROM  tabla
where campo is not null
motivos
----------
{tiempo} 
{hardware}
{}
{}


Para evitar lo anterior, podemos hacer:


ConsultaResultado
SELECT  xpath('//data[@name=''motivo'']/@value',campo::xml) as motivos
FROM tabla
where campo is not null
and  array_upper(xpath('//data[@name=''motivo'']',campo::xml),1) is not null
motivos
------------
{tiempo}
{hardware}



La consulta anterior elimina aquellas filas con array vacío. No obstante, xpath() nos sigue devolviendo un array que tendremos que procesar posteriormente. Para que nos devuelva valores de tipo xml (u no un array) tendremos que tratar la respuesta de xpath como array y pedir el primer elemento del mismo. Así:



ConsultaResultado

SELECT  (xpath('//data[@name=''motivo'']/@value',campo::xml))[1] as motivos
FROM tabla
where campo is not null
and  array_upper(xpath('//data[@name=''motivo'']',campo::xml),1) is not null
motivos
-----------
tiempo
hardware



Obviamente, podemos usar la función xpath no sólo para seleccionar valores (uso en la select list de la sentencia SELECT) sino también en la cláusula WHERE, para filtrar filas. En este último caso, tendremos que realizar una conversión de tipo para poder realizar ciertas comparaciones (comparación de valores enteros, de fechas, etc...). La conversión a realizar debe ser un poco especial, ya que deberemos convertir de xml a varchar y de éste al tipo deseado. Por ejemplo:

SELECT (xpath('//data[@name=''cantidad'']/@value',campo::xml))[1]::varchar::int4
FROM step
where campo is not null
and array_upper(xpath('//data[@name=''cantidad'']',campo::xml),1) is not null
and (xpath('//data[@name=''cantidad'']/@value',campo::xml))[1]::varchar::int4 > 2

Con lo que conseguiríamos todas aquellas filas con xml que tengan un elemento data con nombre "cantidad" cuyo valor sea superior a 2.


Con esto, podemos usar un modelo más flexible (especialmente para valores de poca densidad) al modelo EAV y con consultas más asequibles.

Referencias:

miércoles, 19 de mayo de 2010

WSTX-SERVICE-5002: A JTA Transaction MUST NOT exist entering WS-TX Service Pipe procesing for binding... SOLUCIONADO

JAX-WS representó una revolución en la implementación de SOAP Web Services en JEE. Su aparición en JEE 5 nos permitió publicar como Web Service un Stateless Session EJB automáticamente, de forma declarativa, añadiendo simplemente la anotación @WebService. Sin embargo, bajo determinadas condiciones, nuestro cliente se puede encontrar con un error que, a priori, nos puede resultar desconcertante:

WSTX-SERVICE-5002: A JTA Transaction MUST NOT exist entering WS-TX Service Pipe procesing for binding '{http://jdialer.sgi.gesif/}dataproviderPortBinding' and operation 'getContacts'. JTA Transaction is  J2EETransaction: txId=51 nonXAResource=null jtsTx=com.sun.jts.jta.TransactionImpl@d419b987 localTxStatus=0 syncs=[]....


Tras este error suelen producirse otros dos igualmente desconcertantes: "HTTP transport error: java.net.UnknownHostException: host_cliente" o el clásico SSL Handshake "HTTP transport error: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". Es decir, es como si nuestro servidor estuviese intentando contactar con nuestro cliente por HTTPS. ¿Por qué lo hace?

Una pista: las condiciones en las que se da este error es si el cliente es un EJB. Sólamente en ese caso. Si es un servlet, o una aplicación standalone, funciona perfectamente. ¿Esto te da una idea o aún te confunde más?

La explicación es, en realidad, muy sencilla: los EJB's tienen el atributo de transacción establecido por defecto a REQUIRED (@TransactionAttribute(TransactionAttributeType.REQUIRED)). El código cliente del Web Service lo tiene en cuenta y añade un contexto transaccional al mensaje SOAP. Si EJB "servidor" ha declarado que no necesita transacciones (@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)), ya tenemos el problema servido. La solución en estos casos es también sencilla, debemos indicar a nuestro cliente que no use un contexto transaccional en la petición, anotándolo con @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), y así el servidor no usará el coordinador WSTX (Web Service Transactions).

miércoles, 14 de abril de 2010

La galaxia en un campo de fútbol

Cuando veas un gigante, examina antes la posición del sol; no vaya a ser la sombra de un pigmeo.

- Novalis (1772-1801) Friedrich von Hardenberg. Poeta y filósofo alemán.


En el artículo Magnitudes astronómicas describía mi fascinación por los enormes tamaños de algunos cuerpos astronómicos. La mejor forma de "entender" realmente cómo eran de grandes era, obviamente, ubicándolos en nuestro mundo cotidiano, es decir, comparándolos con objetos conocidos.
Como prometí en dicho artículo, hoy voy a comentar el libro "La Galaxia en un campo de fútbol".

En mi artículo me limité al tamaño de algunos cuerpos de forma singular. "La Galaxia en un campo de fútbol", en cambio, es una exposición sistemática, pero al mismo tiempo muy amena, en la que se nos plantea un método que nos permite imaginar las distancias astronómicas para comprender (e imaginar también, en definitiva) el universo. Desde nuestro "entorno" más cercano, la tierra y sus satélites (artificiales y naturales), donde las distancias se miden en miles de Km, hasta abarcar la visión global del Universo conocido, donde las distancias se miden en millones de años luz, la obra desarrolla el método de forma muy ilustrativa y con ejemplos, de forma que nos permite por primera vez "imaginar" realmente dichas distancias. Así, los que nos hemos leído el texto, podemos entender realmente noticias como las del pasado 8 de Abril sobre un asteroide que pasó rozando la tierra, comprendiendo realmente las distancias que se indican y realizando cada uno nuestra propia valoración sobre lo "cerca" o "lejos" que está algo según el sistema de referencia y dependiendo con qué distancias comparemos (desde luego, un objeto como el 2009 VA del pasado Noviembre sí que pasó "cerca"... cualquier día de éstos se llevan un satélite geoestacionario por delante).

El libro está escrito pensando en lectores interesados por el tema, pero no presupone conocimiento alguno sobre astronomía, de forma que un lector curioso y lego en la materia podrá disfrutar tanto o más que un aficionado. De hecho, el autor, en un esfuerzo (supongo) por mantener un lenguaje cercano y ameno, dota el libro de un estilo de redacción en la que entabla un diálogo con el lector, consiguiendo un resultado entretenido y accesible aunque quizá de forma desmedida, resultando al final (en mi modesta opinión y por poner alguna pega) un poco pueril e ingenuo (eso de pedir al lector que haga algo y luego felicitarlo por hacerlo me parece un poco excesivo).

Por lo demás, el ejemplar está editado en un tamaño muy cómodo e impreso en un papel excelente, permitiéndonos disfrutar de las maravillosas fotografías astronómicas que incluye.

En definitiva, una obra muy atractiva que volveré a releer y disfrutar para asimilar bien "el método" y continuar "imaginando" el universo. Os la recomiendo.


Referencias:

jueves, 25 de marzo de 2010

Generación de código JAXB con Maven

Si tu intención es describir la verdad, hazlo con sencillez y la elegancia déjasela al sastre.
- Albert Einstein.

Al hilo de lo que comentaba en el artículo "Desarrollo en equipo con SVN, Maven y Nexus", una de las maravillas de usar Maven es que te facilita la reproducibilidad, por ejemplo, de la gestión de la configuración de un proyecto. El caso que voy a exponer es un estupendo ejemplo: la generación de código JAXB a partir de esquemas XML (XSD).

La generación de código JAXB se ha venido haciendo típicamente de dos formas: a través de una herramienta o utilidad (wizard, plugin, etc...) de nuestro IDE, o "manualmente" usando la tarea xjc de ant, o el compilador xjc por línea de comando directamente. Personalmente, nunca me ha gustado usar las herramientas automáticas de los IDE, porque ocultan la configuración del proyecto: los settings que se configuran en un wizard del IDE se acaban perdiendo porque no se suben al repositorio de código o si se hace, atas el proyecto a una herramienta que puede que no uses (tú u otro compañero a quien le toque modificarlo) varios meses después cuando te encuentras con el mantenimiento de un proyecto cuya configuración no es reproducible. Además, esa tarea suele ser repetitiva y necesita ser ejecutada a menudo, especialmente en las fases iniciales donde se va ajustando nuestro esquema XML a los tipos de dato que vamos necesitando, de modo que acabo haciendo "a mano" una tarea ant que realice la generación o un shell script que realice la llamada al compilador xjc con los parámetros que quiero.

Afortunadamente, podemos hacer que Maven realice esta tarea automáticamente como parte de sus labores de construcción, y como tenemos nuestro pom.xml subido a svn, todas nuestras preferencias de generación permanecen autocontenidas en el proyecto: simple, sencillo y sin ataduras a ningún IDE.

Iba a poner aquí los trozos necesarios a incluir en el pom.xml extraído de uno de los módulos del proyecto en el que estoy trabajando pero, la verdad, sería redundante porque está perfectamente explicado en el sitio del plugin JAXB XJC de Maven.

En mi caso, que uso Eclipse con m2eclipse (plugin de maven para eclipse), la integración con Maven es tal, que basta con realizar una modificación el XSD y salvarlo para que se regenere y recompile la clase automáticamente y tenga disponibles los nuevos métodos en mis clases "cliente" de forma instantánea (m2eclipse ejecuta el "generate" de Maven integrado con el propio build de Eclipse).

Otra razón más para continuar recomendando usar Maven.

Referencias:

domingo, 7 de marzo de 2010

Balteus cumple un año

“Yo…he visto cosas que vosotros no creeríais. Naves de guerra ardiendo más allá de Orión. He visto rayos-c resplandecer en la oscuridad, cerca de la puerta de Tanhäuser. Todos esos…momentos se perderán…en el tiempo. Como…lágrimas…en la lluvia. Es hora…de morir”.

--Roy Batty, Blade Runner.

Ya ha pasado un año desde mi primer artículo. Una primera entrada impetuosa que escribí sin presentación, casi por rabia, tras perder demasiado tiempo en un error absurdo, de ésos que te vuelven loco, y de los que sólo te sirven para aprender que debes cuestionarlo todo y no dar nada por sentado. Fue en ese estado de rabia contenida y aliviada, tras solucionar el error, cuando decidí que debía compartir estas experiencias con otros desarrolladores, tal y como hacen miles de compañeros alrededor del mundo, de cuyos trabajos y generosidad me he ido aprovechando durante años, ahorrándome muchas horas y disgustos. Tras ése primer post, escribí realmente la presentación del blog con mis motivos y objetivos.

He querido comenzar este post con la que es, probablemente, la cita más conocida de todos los locos entusiastas del cine de ciencia ficción... Parece una entrada melancólica, pero nada de eso en absoluto: simplemente es un homenaje a Ridley Scott y a la película. Yo creo que no hay desarrollador que no haya dicho o pensado algo así tras una puesta en producción... ¿eh? ;-)

1 año. 25 Entradas. 2 entradas al mes, de media. Menos de lo que me gustaría... pero no encuentro tiempo para mucho más. "La falacia de la Ingeniería del Software" y los artículos de la serie "Banco de experiencias" son probablemente las entradas de las que me siento más satisfecho (aunque, curiosamente, no son las que más interés despiertan). De los datos y números que aporta Google Analytics, destacaría dos cosas:
  • La gente busca soluciones. Las entradas más consultadas son aquellas en las que comento cómo he solucionado un error o problema. Lo cual es lógico. En mi caso también ha sido así. Muchos de los blogs en los que he aterrizado ha sido vía google, buscando una determinada solución. En definitiva, cuando tenemos un problema, buscamos si a otra persona le ha pasado lo mismo antes de perder más tiempo. Como digo, constato una evidencia que ya suponía.
  • Realmente el blog tiene visibilidad en todas partes del mundo. Internet hace que todo el mundo sean un montón de ordenadores conectados sin importar localización, idioma o frontera. Parece evidente. Es evidente. Sin embargo, cuando lo confirmas con datos concretos da cierto vértigo. Asumes las lógicas visitas de España y países de habla hispana (al fin y al cabo escribo en español)... pero llaman la atención visitas de Estados Unidos, Alemania, Suiza, Rusia, Brasil, Polonia, India, Finlandia, Corea... ¿Hispanohablantes por el mundo? ¿O simplemente hay gente que busca su respuesta esté en el idioma que esté? (yo lo hago... quizá los angloparlantes, germanoparlantes, etc... también).
En fin, son un par de obviedades con las que todo el mundo cuenta... pero que nunca dejan de sorprender. Al fin y al cabo tenemos una dimensión local y finita... Que lo que escribes pueda ser de interés para alguien tan lejano, impresiona, la verdad.

En todo caso tendré en cuenta estas reflexiones para mis próximas entradas. Es posible que los localismos comentados en "Magnitudes astronómicas" no sean tan claros para gente que no conoce Madrid. Por otro lado, es difícil no hacer referencias al mundo que te rodea. Con respecto a la temática, mi trabajo diario suele darme material de sobra para seguir compartiendo "soluciones" y "experiencias". Así que seguiré en ello.

Gracias a los que visitáis el blog, seáis de donde seáis. Un afectuoso saludo.

lunes, 22 de febrero de 2010

Desarrollo en equipo con SVN, Maven y Nexus (parte II)

Banco de experiencias (V)

En la primera parte de este artículo, enumeraba los problemas de coordinación a los que se enfrenta un equipo de desarrollo diariamente y cómo la utilización de Maven los soluciona de un plumazo por el simple hecho de utilizarlo. Hay un problema sin embargo, inherente al desarrollo en equipo, para el cual se necesita una herramienta más: un gestor de repositorios.

Imaginemos el siguiente escenario de proyecto: un equipo está desarrollando una aplicación empresarial (ear) formada por un par de módulos web, otro par de módulos ejb (ejb-jar), un conector JCA (rar) y tres módulos de librerías comunes (jar).

En un proyecto de éstas características (proyecto con varios módulos) cada desarrollador trabaja en uno o varios módulos (en función de la funcionalidad, de su perfil, habilidades o experiencia...), pero no suele participar en todos... Al menos, eso es lo habitual. Sin embargo necesita tener las actualizaciones y los progresos de todos (o la mayoría) de los módulos, debido a las dependencias entre ellos. Estas dependencias inter-proyecto o inter-módulo son las que denominé como dependencias internas en la primera parte de este artículo. Pero ¿ćomo estar actualizados y poder tener las nuevas funcionalidades y servicios que han desarrollado nuestros compañeros para poderlos usar en los módulos que estamos desarrollando? Típicamente esto se hace de dos formas:
  1. Todos los desarrolladores tienen todos los proyectos creados en su IDE y vinculados con SVN o, al menos, los proyectos en los que está trabajando, los proyectos dependientes, y los dependientes de los dependientes (dependencias transitivas), y así sucesivamente... es decir, típicamente todos. Esto es lógicamente un engorro, porque cada vez que alguien realice una refactorización que suponga la creación de un nuevo proyecto, afectará a todo el equipo de desarrollo. Todos los cambios impactan a todos (cambios en la configuración, dependencias, nuevos proyectos, etc...), favoreciendo, además, la incidencia de errores dada la exposición de todos los fuentes a todo el equipo.
  2. Los desarrolladores que trabajan en proyectos que son requeridos por el resto "publican" sus artefactos en SVN o un repositorio común en red. Esta segunda opción introduce complejidad de configuración y coordinación en el equipo y scripts adicionales que realicen esas tareas, ya que hay que "avisar" de cuando hay que actualizar las dependencias... en todo caso: la gestión de las dependencias (en este caso internas) se manejan manualmente vía scripts (típicamente de ant).

Software de gestión de repositorios Maven

El software para de gestión de repositorios Maven sirve precísamente para eso: para crear y gestionar nuestros propios repositorios de Maven. De esta forma tendremos la gestión de dependencias solucionada:
  • las dependencias externas, a través del mismo Maven, usando el repositorio Central. También podemos crear nuestros propios repositorios proxies de otros, reduciendo el tráfico de red.
  • las dependencias internas (o inter-proyecto) con nuestro repositorio.
Veamos el siguiente ejemplo: tenemos un equipo de tres desarrolladores que está desarrollando una aplicación que tiene un módulo JAR, que a su vez es usado por un módulo EJB y otro módulo WAR que usa (necesita) los dos anteriores.
  • El desarrollador A participa en el desarrollo del módulo EJB, y es el único que desarrolla el módulo JAR. Este desarrollador no tiene que resolver dependencias internas, digamos que es un "productor" y debe "publicar" su trabajo para los demás.
  • El desarrollador B sólo trabaja en el módulo WAR: por tanto debe disponer de los otros proyectos. Sería el caso del "consumidor" exclusivo.
  • El desarrollador C trabaja en los módulos WAR y EJB: es decir, es consumidor y productor a la vez. Debe publicar su trabajo, pero también requiere del trabajo del desarrollador A.



En el caso anterior, usando un repositorio remoto con un software de gestión de repositorios, Maven realizará todos los trabajos de sincronización de forma transparente, realizando la publicación de artefactos al repositorio (mvn deploy) para los desarrolladores A y C, y la actualización automática para todos. Lo único que hay que hacer es especificarle la URL del repositorio en los pom.xml de los proyectos, simplificando enormemente la coordinación en proyectos reales típicos (más grandes, complejos y con más desarrolladores).

El software repositorio que yo conozco es Nexus, de la compañía que creó Maven (Sonatype), y la verdad, estoy muy satisfecho con su funcionamiento. No obstante, hay otros también bastante usados como Apache Archiva, o Artifactory. En general, todos parecen cumplir correctamente su misión principal y tienen una instalación sencilla. Al final del artículo puedes encontrar algunas referencias útiles con datos y opiniones sobre Archiva y Nexus. Con independencia de la elección, el objetivo del artículo es dejar claro para qué sirve y por qué nos es tan útil un software de gestión de repositorios. En nuestro caso particular, nos decidimos por Nexus porque usamos eclipse y pensábamos que tendríamos menos problemas si todas las herramientas estaban bien integradas por ser de la misma compañía: Maven, Nexus y m2eclipse.

La verdad, he de decir, que m2eclipse nos ha dado algún problema que otro, especialmente alguno  bastante gordo que nos retrasó en el conocimiento del plugin y cómo funcionaba (p.e.: la opción "Enable Workspace resolution" ha dado problemas en sucesivas versiones del plugin), pero nada que decir sobre Nexus: hasta el momento, perfecto.

Finalmente, SVN, Maven y Nexus conforman una tríada perfecta para empezar cualquier proyecto pequeño adoptando buenas prácticas y un mínimo de coordinación automatizada, permitiéndonos poder escalar a proyectos y grupos más grandes afinando más hacia la integración continua con una buena base.

Referencias:




Related Posts Plugin for WordPress, Blogger...
cookieassistant.com