viernes, 14 de diciembre de 2012

2012: El fin de los magufos


“Windows NT addresses 2 Gigabytes of RAM, which is more than any application will ever need.”
(Microsoft, on the development of Windows NT, 1992)

Este año que termina es el año favorito de los magufos. Tras las bobadas del fallido fin del mundo del año 2000, llega el siguiente fin del mundo: el 21 de Diciembre de 2012. Ya veremos cuando será el próximo...

Ayer se me ocurrió escribir sobre esto pensando en el pasado 12-12-12, al que se le atribuyeron no pocas insensateces cuando todo el mundo sabe que lo único importante de ese día es que es el cumpleaños de uno de mis hermanos. Con las profecías chorradas de Nostradamus ya cubiertas de polvo, a los charlatanes cuentistas y demás inventores de tonterías, les dió por mirar, mira tú, nada más y nada menos que a uno de los calendarios Maya... ¡Y dio hasta para una película!

En fin. Queridos lectores, lamento ser yo quien os fastidie el magno espectáculo, pero el 21 de diciembre de 2012 a las 11:12 UTC no va a ser el fin del mundo. Ocurrirá lo que todos los años en torno al mismo momento aproximadamente: el solsticio. El universo no se rige por nuestras formas de contar las cosas. La verdad es que el fin del mundo será un impresionante espectáculo, pero aún nadie sabe cuando sucederá porque, obviamente, no depende de ningún adivinador. No hay problema. La humanidad tiene butacas reservadas para ese espectáculo. Y es seguro que sucederá antes de los próximos 3.000 millones de años... Me apuesto una cena. En todo caso, a los engañabobos les quedará el refugio del próximo año, un 13, que dará para más bobadas que ayuden a sus ingenuos cŕedulos a olvidar sus "predicciones" anteriores.

En medio de esta agitada crisis, la comunidad científica nos regaló este año con el que probablemente será el primer descubrimiento más significativo de este siglo: una nueva partícula que concuerda con el bosón de Higgs. Si se confirma el descubrimiento de la maldita partícula ("The goddamn particle", no the "God Particle", como el editor de Leon Lederman transformó con disparatado desatino), la física podría corroborar el modelo estándar en los próximos años o, en todo caso, permitirá extraordinarios avances en física.

Más prosaico pero no menos importante: Blade Runner cumple su 30 aniversario este año. Ya conocen mis lectores habituales mi devoción por esa película.

Este segundo semestre del año mi actividad en el blog ha sido muy poca por razones diversas que no vienen a cuento ahora, pero soy consciente de ello. Y es que este año está siendo francamente difícil para mi en términos de tiempo libre para el blog (y también en otros que tampoco vienen al caso ahora).

Con suerte, el 21 de Diciembre se podrían acabar las magufadas de una vez por todas, aplastadas por la tozuda y sencilla realidad... pero no se debería a los mayas, sino al uso de nuestro cerebro con la mejor de las herramientas: el pensamiento científico... y a falta de ello, el sentido común.

A por el 13!!

Feliz año nuevo.


Referencias y más información:

miércoles, 17 de octubre de 2012

Comparar y actualizar esquemas de PostgreSQL



"1f y0u c4n r34d 7h15, y0u r34||y n33d 70 637 41d."

Al pasar a producción nuevas versiones de software empresarial necesitamos automatizar la "actualización" del sistema con el objeto de que sea repetible y pueda realizarse lo más rápidamente posible y sin errores. Uno de los elementos críticos es el esquema de nuestra base de datos sobre el cual, en la mayor parte de los casos, descansa la estructura vertebral de nuestro sistema.

Si la comparación y obtención de diferencias (comparison/diffing) entre el esquema antiguo y el nuevo es una tarea tediosa que está sujeta a numerosos errores, la generación de un script SQL de actualización es aún más compleja, ya que requiere un tratamiento inteligente y ordenado de dichas diferencias.

Para ayudarnos en esta tarea con PostgreSQL, me encontré una excelente herramienta: Another PostgreSQL Diff Tool (apgdiff). Agpdiff es una herramienta gratuita de comparación y obtención de diferencias de esquemas de bases de datos (database schema diff tool) específica para PostgreSQL. La he probado y he de decir que quedé realmente impresionado. Tan sólo tuve que añadir las lógicas modificaciones al script de actualización generado relacionadas con los datos (actualización de filas con valores NULL en campos que pasan a ser NOT NULL, etc...).

En el sitio de la herramienta viene información suficiente sobre su funcionamiento y cómo usarlo. Sólo añadir, como recomendación, la utilización de la opción --add-transaction que nos permitirá probarlo con comodidad y corregir los errores.

Una herramienta imprescindible si usas PostgreSQL.

Referencias y más información:

domingo, 1 de julio de 2012

JBoss Open Forum 2012, 6-06-12, Madrid


El pasado 6 de Junio asistí al JBoss Open Forum 2012 en el que Red Hat presentaba muchos avances en sus soluciones de middleware empresariales (JBoss EAP 6, JBoss EDS, etc) así como casos de éxito en implementaciones de soluciones presentadas por las propias empresas cliente.

La verdad es que, de los últimos eventos de este tipo a los que he asistido, ha sido el que más me ha satisfecho. Tengo que destacar la excelente organización, sesiones con contenidos de enorme interés y ponentes a la altura de dichas ponencias.

JBoss fue durante un tiempo nuestro (me refiero en mi trabajo) Servidor de Aplicaciones "por defecto". Las versiones 3.x de JBoss funcionaban bien. Era rápido y tenía un motor de JMS francamente bueno. Aún a pesar de sus conocidos inconvenientes en cuanto a la gestión de configuración y el complicado ajuste de los class loaders, el servidor era de lo mejorcito no sólo entre los servidores Open Source, sino en general.

Sin embargo, a partir del año 2006, en el que se lanzó la especificación JEE 5, no veíamos avances consistentes en el Servidor de Aplicaciones en cuanto a dicha especificación. La compra ese mismo año, de JBoss por parte de Red Hat tampoco ayudó a agilizar el despegue de versiones y el lanzamiento de una nueva versión certificada JEE 5.... La verdad es que JBoss 4 nos decepcionó y, volvimos a realizar un examen a otros servidores. 2006 fue el año en el que coincidió una especie de pausa en JBoss (supongo que debida a la reestructuración e integración en Red Hat tras su compra), con el lanzamiento de Glassfish, el primer Servidor de Aplicaciones que soportaba JEE 5 y que era, además, la RI (Implementación de Referencia). Con lo que nos "pasamos" a Glassfish.


... Y hasta ahora. Llevamos trabajando con Glassfish como "nuestro" servidor de aplicaciones "por defecto" desde 2006. Pero las cosas pueden cambiar. Glassfish tenía novedades de las que JBoss adolecía: consola web, una configuración única... sin embargo, su motor JMS era menos configurable que el de JBoss, y tampoco tenía (y sigue sin tener) un browser JNDI. Por tanto, que JBoss llegara a tener las cosas que carecía e igualar o superar a Glassfish era una cuestión de tiempo que, al parecer, ha concluido.

En el JBoss Open Forum 2012 comprobé que JBoss había recuperado su ritmo, su innovación y su buen hacer y me enseñaron cosas que, la verdad, me impresionaron mucho y gratamente:
  • El nuevo servidor de aplicaciones se había reescrito por completo, según Pilar Bravo (JBoss Solution Architect, Red Hat). Y nos presentaban un renovado servidor JEE 6 certificado con mejoras aparentes a las que tenemos en Glassfish:
    • Configuración única
    • Varias consolas: además de la consola web, hay otras como REST o consola muy interesantes
    • Nuevo servidor JMS
    • Classloader más sencillo de configurar
    • ... y otras maravillas de clustering que habrá que probar detenidamente.
  • En cuanto a middleware, lo que más me llamó la atención fue:
    • Nuevas versiones
      • de su magnífico JBoss Rules
      • de JBPM
    • Productos (¿nuevos?) que desconocía:
      • JBoss EDS
      • JBoss ON

Imagen (tomada con mi móvil ;-) de una sesión
JBoss ON (Operations Network)  es una aplicación de monitorización de servicios. Una especie de Nagios+Caqti, para entendernos, pero especializado en servicios JBoss. Además, se puede combinar con Nagios para un control mucho más pormenorizado de los aspectos de cada servicio.

JBoss EDS (Enterprise Data Services Platform) es una plataforma de virtualización de datos que permite integrar datos de diversas fuentes y exponerlos en bases de datos virtuales accesibles a través de interfaces estándar como JDBC. 

La presentación de este producto corrió a cargo de Karoly Nagy (Senior Solution Architect, Red Hat). Debo decir que fue una presentación excelente: concisa, al grano y con ejemplo/demo rotundo. Este producto realmente me ha impresionado mucho, mucho. ¡Ya me hubiera gustado tener a mano este producto hace algunos años...! Considero que un caso de uso típico (y a mi profesionalmente se me han dado unos cuantos) es el clásico caso de migración de subsistema (backoffice, frontoffice...) o de tecnología en el que te encuentras con que existen múltiples fuentes de datos cuya migración simultánea se hace compleja de implementar y, sobre todo, de poner en producción. JBoss EDS me parece un fantástico "pegamento" y entre los sistemas nuevos y los antiguos, sirviendo de carretera provisional mientras se realizan migraciones parciales de una gran implantación escalonada que puede durar muchos meses o años.

Las ponencias sobre casos de éxito fueron, la mayoría, muy interesantes. Salvador Santander, del Departamento de Desarrollo de Tecnologías de Información de la Empresa Pública del Suelo de Andalucía (EPSA) puso la nota simpática y desenfadada a una buena exposición, muy cercana y realista, sobre su experiencia con Red Hat. De ésta y otras exposiciones de "Casos de éxito" me quedo con dos conclusiones:
  1. La satisfacción con el nivel de servicio de soporte por parte de Red Hat es buena. Tanto, que continuarán con ellos para proyectos de clustering y misión crítica
  2. Da la sensación de que ya (por fin) hay en España consultores y servicio de soporte suficiente y de calidad.



En resumen, me quedé con una buena impresión en general tanto de los nuevos productos de JBoss en el aspecto técnico, como de la aparente consolidación de Red Hat en España como compañero de viaje a la hora de afrontar nuevos proyectos y retos.

Este es un caso claro de éxito de los nuevos modelos de negocio del siglo XXI, basados en código abierto, apoyados en la comunidad y generando puestos de trabajo de calidad en empresas rentables.

Enhorabunena, Red Hat.

Referencias y más información:

martes, 12 de junio de 2012

Migrando a JEE 6 / EJB 3.1 (I)

“I’ve finally learned what ‘upward compatible’ means. It means we get to keep all our old mistakes.”
Dennie van Tassel

La especificación JEE 6 junto con la enorme lista de nuevas tecnologías que comporta (EJB 3.1, JAX-RS 1.1, JAX-WS 2.2, Java Servlet 3.0, etc...) está disponible desde diciembre de 2009. A pesar de haber pasado 2 años y medio, la verdad es que apenas he podido ponerla en funcionamiento en apenas un par de nuevos proyectos.
De esta nueva especificación destaca especialmente la especificación EJB 3.1 con muchas, potentes y útiles novedades. Sin embargo, en la adopción de esta especificación me he encontrado con algunos aspectos ásperos, incompatibilidades y diversos problemas indocumentados. Este artículo (y alguno que le sucederá) intentará ahorrar al lector interesado, al menos, el tiempo que yo he perdido intentando hacer funcionar cosas que teóricamente (en base a la documentación) deberían funcionar.

1. Incompatibilidad de la notación @Webservice con la vista sin interfaz (no-interface view)

Supongamos que tienes un EJB 3.0 publicado como Webservice, así:

 
/**
 * Stateless Session EJB 3.0
 * @author szarza
 */

@Stateless(name="CacheService")
@TransactionManagement(TransactionManagementType.BEAN)
@WebService(serviceName="CacheService",name="CacheService")
public class CacheServiceBean implements CacheServiceLocal {

 

Si vas a migrar a EJB 3.1, puedes tener la tentación de eliminar la interfaz local y usar la vista sin interfaz para simplificar tu proyecto... pero, lamentablemente, al eliminar la interfaz local, en Glassfish 3.1 me encuentro con un desagradable mensaje en despliegue:

[#|2012-06-11T15:43:38.754+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=108;_ThreadName=Thread-2;|Cannot resolve reference Local ejb-ref name=cestel.services.cache.timer.CacheUpdaterTimedBean/cacheService,Local 3.x interface =cestel.services.cache.facade.CacheServiceLocal,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=cestel.services.cache.timer.CacheUpdaterTimedBean/cacheService,Local 3.x interface =cestel.services.cache.facade.CacheServiceLocal,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session...

En definitiva: simplemente no funciona. La notación @Webservice es incompatible con la vista sin interfaz. Puede parecer más o menos lógico... pero no lo he visto en la documentación por ninguna parte.

2. Incompatibilidad de la notación @Path@Produces en un módulo ejb

De la misma forma que se puede "publicar" de manera sencilla un EJB como un SOAP webservice JAX-WS simplemente añadiendo la notación @Webservice, podría ser igualmente sencillo publicarlo como un webservice RESTful (JAX-RS) añadiendo la notación @Path  y @Produces... pero no. Al menos en Glassfish 3.1.2 no es posible publicar un webservice REST en un módulo EJB. Esto me ha parecido un verdadero engorro, ya que nos obliga a realizar un módulo war sólo para esto.

En definitiva, si necesitáis un servicio REST, debes hacer un módulo war.

El próximo capítulo lo dedicaré a la adaptación a la nueva definición de JNDI portable y sus sorpresas inexplicables (por poco documentadas).


Referencias y más información:

viernes, 4 de mayo de 2012

Analizar y procesar los argumentos de línea de comandos en Java

(Parsing and processing command line arguments in Java)


“19 Jan 2038 at 3:14:07 AM”
(End of the word according to Unix–2^32 seconds after January 1, 1970)

Los límites tecnológicos son muy provisionales. Las cosas que aparentemente durarán mucho al final son más efímeras de lo que parece. El año pasado se agotaron oficialmente las direcciones IPv4 y me preguntaba, a propósito de la "cita" de hoy si, en el año 2038, aún existirán procesadores de 32 bits. El tema de este articulo, sin embargo, es una paradoja al inexorable paso del tiempo: seguimos necesitando realizar aplicaciones de consola que puedan invocarse a través de la línea de comandos.

En java, podemos procesar una línea de comandos sencilla a partir del argumento del método main. Pero, si necesitamos procesar una línea de comandos más compleja, podemos enfrentarnos a un arduo trabajo. Nuestra aplicación puede necesitar características de procesado más complejas como:
  • Argumentos con opciones
  • Análisis sintáctico (tipos de dato, restricciones, etc)
  • Valores por defecto en caso de omisión
  • Control de opciones obligatorias o requeridas
  • Generación de opción de ayuda
  • etc...

Por ejemplo, supongamos las siguientes opciones:

Option (* = required)                        Description
---------------------                        -----------
-?, -h                                       show help
-c <integer: count="">                       (default: 1)                           
--classpath, --cp <file: path1:="" path2:...="">                                                                   
* -d <mm dd="" yy="">                        some date
--output-file [File: file]
-q [Double: quantity]
-v, --chatty, --talkative                    be more verbose

Procesar las opciones mostradas anteriormente por nuestra cuenta sería reinventar la rueda. Para ayudarnos en esta tarea existen múltiples librerías que nos permiten realizar un procesado de opciones de argumentos muy complejo en unas pocas líneas de código, de las que expondré una recopilación al final. En este artículo comentaré la que he utilizado: JOpt Simple.


JOpt Simple
Es la librería usada en OpenJDK. JOpt Simple permite realizar análisis de argumentos compatibles con la sintaxis POSIX getopt() y getopt_long(), manteniendo toda la simplicidad posible. Como otras librerías, tiene opciones muy útiles:
  • generación automática del texto (formateado) de la opción de ayuda
  • control de parámetros obligatorios en argumentos
  • control de tipos de parámetros
  • control de opciones de argumentos
  • valores por defecto
  • etc...

A continuación, un ejemplo de uso:

 private static final String IMPORTED = "imported";
 private static final String A_H = "h";
 private static final String A_P = "p";
 private static final String A_U = "u";
 private static final String A_URL = "url";
 private static final String A_E = "e";
 private static final String A_I = "i";
 private static final String A_Q = "q";
 private static final String A_V = "v";
 private static final String A_GC = "gc";
 private static final String A_DR = "dry-run";

 public static void main(String[] args) {
  OptionParser parser = new OptionParser() {
            {
             acceptsAll( asList( "h", "?", "help" ), "Muestra la ayuda" );
             acceptsAll( asList( A_V, "verbose" ), "Muestra información detallada" );
                accepts( A_URL, "Url de conexión al repositorio" ).withRequiredArg().ofType( String.class ).defaultsTo( "//localhost:1099/jackrabbit.repository" );
                acceptsAll( asList( A_U, "user"), "Usuario" ).withOptionalArg().ofType( String.class ).defaultsTo( "gesif" );
                acceptsAll( asList( A_P, "password"), "Contraseña" ).withRequiredArg().ofType( String.class ).defaultsTo( "gesif" );
                acceptsAll( asList( A_E, "export"), "Exportación de consulta a directorio (requiere -q)" ).withRequiredArg().ofType( String.class ).defaultsTo( "." ).describedAs( "directorio" );
                acceptsAll( asList( A_I, "import"), "Importación de ficheros del directorio" ).withRequiredArg().ofType( String.class ).describedAs( "Path completo de ficheros a importar (se permiten comodines)" );
                acceptsAll( asList( A_Q, "query"), "Consulta a realizar" ).withRequiredArg().ofType( String.class ).describedAs("consulta XPATH");
                accepts( A_GC , "Ejecuta la limpieza de borrado (requiere -u y -p)" ).withRequiredArg().ofType( String.class ).describedAs("repository home");
                accepts( A_DR , "Ejecución de importación de prueba (no importa)");
            }
        };

        OptionSet options = parser.parse( args );
        Date time = new Date();

  try {
         if ( args.length < 1 || options.has( A_H ) ) {
             parser.printHelpOn( System.out );
             System.out.println("Ejemplos:\n" +
               " RTool -q \"//*[@gst:file and @g:stepId = 13872238]\" -e /home/szarza/tmp3\n" +
               " RTool -q \"//*[@gst:file and @g:stepId=20754674]\" -e . --url //192.168.20.12:1099/jackrabbit.repository\n" +
               " RTool --url //192.168.20.12:1099/jackrabbit.repository --import ./fc15099e-d586-4046-afd1-8fc9c03bdf17.0002.pdf");
             System.exit(0);
         }
                ....

Como se ve en este ejemplo, con Jopt Simple se puede realizar todo el control de opciones y argumentos de una forma rápida y sencilla. Sin embargo no es la única, hay realmente muchas:
Usé JOpt Simple por ser una librería muy versátil y muy sencilla de usar. Sin embargo, tengo que reconocer que, en mi búsqueda de librerías, JewelCli y JCommander me dejaron impresionado por su elegancia y limpieza. JOpt Simple es una librería al estilo clásico, donde la definición de sintaxis es programática. JewelCli y JCommander son librerías con un nuevo enfoque actualizado, que usan un estilo declarativo para la definición de sintaxis, usando anotaciones. Estas últimas librerías me parecieron más adecuadas para un proyecto mayor, con más opciones y/o que fuese a tener un mantenimiento mayor.

En todo caso, creo que en una próxima ocasión probaré JewelCli. Y tu, ¿has probado alguna? ¿qué opinión tienes?

P.D.: Por cierto, feliz Stars Wars Day a todos!! ... y  #maythe4thbewithyou.

Referencias y más información:

domingo, 15 de abril de 2012

Transacciones autónomas en PostgreSQL


The cheapest, fastest, and most reliable components are those that aren’t there.
Gordon Bell.

En algunos casos, necesitamos que ciertas operaciones de una transacción de base de datos sean realizadas aunque la transacción se deshaga con un rollback. Por ejemplo, imaginemos que tenemos una función o procedimiento almacenado en la que hemos agrupado 10 operaciones. Cuando dicha función se llame, se ejecutará en un contexto transaccional, es decir, se realizará una transacción con dichas 10 operaciones de forma atómica (o todas, o ninguna). Supongamos que queremos garantizar que un subconjunto de esas operaciones (por ejemplo un par de ellas que hacen auditoría de la propia llamada) se realicen siempre, con independencia de las demás: en este caso necesitamos una transacción autónoma.

Las transacciones autónomas (Autonomous Transactions) permiten suspender el contexto de la transacción en curso (llamante), realizar una transacción independiente y reanudar el contexto de la transacción llamante sin afectar su estado. Los casos de uso típicos de uso son funcionalidades cuyos cambios queremos que persistan con independencia de la transacción que las llama: trazado (logging), operaciones de auditoría, contadores, funciones de propósito general...etc.

Un caso que se me ha dado recientemente es el de realizar una transacción batch muy muy larga (de importación de gran cantidad de  datos), donde la unidad de importación supone operaciones de modificación (inserción o actualización) en varias tablas. Imaginemos que importamos usuarios con todos sus datos: dirección, provincia, datos bancarios, teléfonos, etc... Cada usuario puede suponer 8 o 10 operaciones en diversas tablas. Si tenemos que importar 30.000 usuarios, podemos encontrarnos con una transacción compuesta por 300.000 operaciones de inserción/actualización. Este tipo de transacciones tan grandes exige muchos recursos de un servidor de base de datos: crea ocupación de memoria y genera muchos puntos de bloqueos que podrían socavar el desempeño de un sistema en producción. Una forma de solucionar un problema así es realizar una confirmación de datos por cada unidad de importación. Es decir, que el bucle general de importación (que ya se ejecuta en un contexto transaccional) llame a una función que realiza y confirma la tarea de importación de una unidad (un usuario en el ejemplo) en una transacción autónoma, con lo cual cada usuario se procesaría de forma atómica, sin que la transacción general acumule trabajo.

Con Oracle, las transacciones autónomas se declaran sin mayor dificultad usando la directiva:

PRAGMA AUTONOMOUS_TRANSACTION;

Sin embargo, en PostgreSQL las transacciones autonomas no están soportadas. No hay forma de hacerlo de forma declarativa. Sólo hay una forma de hacerlo (con dos enfoques, como veremos enseguida): realizando la parte que queremos que sea autónoma en otro contexto transaccional, es decir, en otra conexión a la base de datos:
  1. Usando un lenguaje de programación externo (untrusted).  Es decir, reducir la función PL/PgSQL a la parte que queremos garantizar su ejecución (la parte que queremos que sea autónoma) y realizar el resto en un lenguaje de programación externo a la base de datos. La función se llamará en una nueva conexión
  2. Usando dblink. Esta opción, es parecida a la anterior, pero usando siempre PL/PgSQL. Es decir, realizamos la transacción autónoma en una nueva conexión usando dblink.


dblink

dblink es un módulo del contrib de PostgreSQL que permite realizar conexiones y realizar consultas a bases de datos locales o remotas dentro de una sesión. Con un ejemplo se verá más claro:

SELECT nombre, apellidos
FROM usuario INNER JOIN
    dblink('dbname=otrabasededatos port=5432 host=localhost_u_otro' ||
           'user=usuario password=password',
           'SELECT direccion, poblacion, provincia from usuario')
            AS u(direccion varchar, poblacion varchar, provincia varchar)
    ON usuario.id = u.id;

En el anterior ejemplo, realizamos un JOIN entre dos tablas de dos bases de datos distintas (en el mismo host u otro, eso da igual). Es decir, en la sesión en curso, y a través de las funciones de dblink, se crea una conexión sobre la que enviamos nuestra query. Si esto lo hacemos contra el mismo servidor y misma base de datos... voilá: ya tenemos una conexión nueva y, por tanto, un contexto transaccional diferente en el que podemos ejecutar nuestra transacción de forma independiente (es otra conexión).

Veamos un ejemplo de cómo usarlo. Supongamos el ejemplo del inicio, donde tenemos un cursor que recorremos en el que, para cada registro, debemos realizar un par de operaciones transaccionales de forma independiente (autónoma). Aprovecharemos el ejemplo también para ilustrar cómo se puede realizar una inserción y obtener la clave del elemento recién insertado para la siguiente sentencia.

for usuario in (select * from iusuarios) loop
   raise notice 'Procesando usuario->, %',usuario.id || '-' || usuario.nombre;

   PERFORM dblink_connect_u('dbname=dbname connect_timeout=5');
   PERFORM dblink_exec('begin;');

   l_dbl_sql :=
      'insert into u2 (name,edad) values (' ||
      quote_nullable(l_name) || ', ' ||
      coalesce(l_edad::varchar,'null') || ', ' ||
      '0) returning id;';
   raise notice '[ALTA] SQL INSERT u2: %', l_dbl_sql;

   select id into l_user_id from dblink(l_dbl_sql) as d(id int4);

   l_dbl_sql :=
      'update otra_tabla set date = now() where id_user = ' || l_user_id || ';';
   raise notice '[ALTA] SQL UPDATE otra_tabla: %', l_dbl_sql;
   PERFORM dblink_exec(l_dbl_sql);

   PERFORM dblink_exec('commit;');
   PERFORM dblink_disconnect();
end loop;

Examinaremos el ejemplo, porque hay cosas interesantes que quiero destacar:
  1. Linea 4: es importante especificar el timeout, para evitar efectos indeseables. Dado que se trata de la misma base de datos en el mismo servidor, no hay que especificar nada más.
  2. Linea 5: inicio de la transacción, ya que hay más de una sentencia
  3. Líneas 9 y 10: uso de las funciones quote_nullable() y coalesce() para garantizar el correcto escape de valores y la generación de 'null' cuando existan valores nulos.
  4. Línea 14: ejemplo de ejecución de sentencia INSERT con dblink para obtención del registro recién insertado.
  5. Línea 19: ejemplo de ejecución de sentencia UPDATE (o cualquier otra sentencia que no devuelva resultados)
  6. Línea 21: confirmación de la transacción
  7. Línea 22: desconexión
  8. Líneas 11 y 17: es muy importante asegurarse de que terminamos las sentencias que enviamos a dblink con el separador de terminación punto y coma (;). Un olvido puede hacer que nuestra función se detenga esperando la terminación.
Finalmente, recomiendo usar las funciones quote_nullable() para las fechas y cadenas y coalesce() para los valores numéricos para garantizar una correcta sintaxis y escapado de las sentencias. Si estás usando PostgreSQL 9.1 o superior puedes evitar ese engorro y usar la enormemente más cómoda función format().


Referencias y más información:

martes, 6 de marzo de 2012

Balteus cumple su tercer año

(Ilustración: Fran Barquero)

"¿Se acuerda de la araña que había en su ventana? Era naranja, con las patas verdes. La vio tejer una telaraña todo el verano. Un día puso un huevo. Luego el huevo eclosionó..." - Rick Deckard

"Y salieron de él cientos de arañas... que se la comieron." - Rachael
- Blade Runner.

Siguiendo con la tradición de los post de aniversario de este blog, comienzo el apunte con otra cita del único y excepcional film "Blade Runner". Si no habéis visto la película, este (como cualquier otro) es un buen momento para hacerlo. Si la habéis visto, volved a verla. Siempre descubriréis nuevos ángulos y elementos interesantes. Es una obra tremenda y absolutamente extraordinaria.

Este 6 de Marzo este blog cumple tres años. El hecho de mantener un blog durante tres años supone claramente que no es una ocurrencia momentánea, sino hay por mi parte un compromiso claro con él y que este proyecto mío del blog es algo consolidado. No obstante, un blog sin sus correspondientes actualizaciones no es nada, así que haré un esfuerzo por incrementar el número de artículos.

El número tres es un número especial para este blog. No en vano el título del blog está dedicado a 3 estrellas (ver Acerca de Balteus). Ese motivo, esas mágicas tres estrellas, han servido de base para la ilustración especialmente realizada para la ocasión por el genial ilustrador Fran Barquero. Gracias Fran (esto se va a convertir en otra tradición...).

Tengo un montón de temas y artículos en mente para este año que espero sean de tú interés.

Un saludo a todos.

martes, 28 de febrero de 2012

Orden y formato al código PL/pgSQL


“Any code of your own that you haven’t looked at for six or more months might as well have been written by someone else.”
Eagleson’s Law

Leer y entender un trozo de código de unas pocas líneas es fácil, aunque haya sido escrito como si se hubiese caído al suelo y esparcido por toda la habitación. Ahora bien, si tenemos que leer unos cuantos cientos o miles de líneas, la cosa cambia bastante. Es fundamental tener un código ordenado y bien identado para facilitar la legibilidad.

Existen muchas herramientas que facilitan o realizan directamente esta tarea. Son las llamadas herramientas de embellecimiento o formato ("code beautifiers/formatters tools"). La mayoría de los IDE's y editores tienen herramientas para una gran variedad de lenguajes... salvo para PL, donde me he encontrado bastantes carencias.

Si necésitáis una herramienta de este estilo, una de las mejores que me he encontrado es Pl/Sql tidy. Algunas de sus características son:
  • Identación por bloques
  • Compactación
  • Ajuste de mayúsculas/minusculas
  • Alineamiento vertical en asignaciones
El uso de la herramienta es a través de línea de comando, pero también podéis usar la interesante versión online disponible.

Funciona con PL/pgSQL.


Referencias y más información:

miércoles, 1 de febrero de 2012

Apache Commons DbUtils: sencillo, rápido, ligero


“Controlling complexity is the essence of computer programming”
Brian Kernigan

Hoy traigo aqui otra de las joyas de Apache Commons: DbUtils. Ya comenté en el artículo anterior "Librerías imprescindibles en Java" que, en cualquier projecto, antes de pensar en hacer nuestras utilities, debemos pasar por la página de Commons para ver las librerías existentes antes de ponernos a reinventar la rueda. Pues bien, Commons tiene otra pequeña joya que he descubierto y aplicado recientemente con éxito.

Hay ocasiones en las que no usamos un framework de mapeo tipo ORM (JPA/EclipseLink, Hibernate, Mybatis -antiguo iBATIS-) por varias razones: modelo muy cambiante, proyecto muy pequeño, necesitamos un control más fino de las consultas, generación dinámica, etc... En estos casos, no nos queda más remedio que usar directamente JDBC. Sin embargo JDBC es un API muy engorroso que requiere mucho código de limpieza de recursos y mucha fontanería a través de sus capas. Más del 80% de nuestro código JDBC es la instanciación de objetos del API, establecimiento de parámetros, liberación y cierre.


DbUtils es un pequeño conjunto de clases diseñadas para hacer mucho más fácil el trabajo que hacemos con JDBC centrándonos en lo que queremos: consultar, actualizar, insertar. Especialmente nos ayuda en:
  • Se encarga automáticamente de la fontanería previa (conexión y preparación) y de la limpieza, evitando posibles errores de liberación de recursos.
  • Rellena las propiedades de JavaBean automáticamente a partir de ResultSets. No es necesario copiar manualmente valores en instancias de beans.
Por todo la anterior, el uso de DbUtils reduce drásticamente la cantidad de código que necesitamos con JDBC. Por hacer una comparativa, yo díría que DbUtils es a JDBC lo que JDOM a javax.xml.

Usar DbUtils es muy sencillo. Hay dos clases/interfaces principales que constituyen el corazón de DbUtils: QueryRunner y ResultSetHandler. QueryRunner se encarga de realizar todo el trabajo: abre la conexión, ejecuta la consulta o actualización y devuelve el resultado. Para devolver el resultado de diferentes formas se usan las distintas implementaciones de la clase ResultSetHandler, que permite devolver el resultado en una lista de  POJO's, lista de arrays, lista de Map, etc...

A continuación pongo un ejemplo simple de una pequeña DAO de una aplicación que tuviese que acceder a una base de datos PostgreSQL y a un AS/400 simultáneamente. En el ejemplo se pueden observar características muy importantes de ahorro de código y, por tanto, de su consecuencia más valiosa, ahorro de tiempo:
  • No hay declaraciones de Connection, Statement y ResultSet.
  • No hay liberación de recursos (DbUtil lo hace automáticamente)
  • No es necesaria la engorrosa recolección de campos a través de la iteración del ResultSet. Podemos devolver las consultas en un Map<String, Object> (NombreCampo, Valor) o en un JavaBean cuyas propiedades coincidan con los campos que devuelva nuestra consulta.


/**
   Suponemos una clase DAO cualquiera de acceso a datos
*/
public class ASDao {
   
   private AS400JDBCDataSource asDataSource;
   private PGSimpleDataSource pgDataSource;
   private QueryRunner qr;

   public ASDao() throws Exception {
       // El datasource puede instanciarse...
       asDataSource = new AS400JDBCDataSource("host4.cestel.es","asuser","xxxxxx");
       // U obtenerse a partir de un JNDI de un contenedor
       pgDataSource = new InitialContext().lookup("java:comp/env/jdbc/pgDS");
       qr = new QueryRunner(asDataSource);
       qrp = new QueryRunner(pgDataSource);
   }


   /**
       Realiza una consulta parametrizada (que debe devolver una sóla fila) y 
       devuelve un Map<String,Object> con el nombre del campo
       y su valor. Se asume que la consulta devuelve una sóla fila.
       Son apenas dos líneas.
   */
   public Map<String,Object> findData(String clientCode, String debtCode) 
                                                                throws SQLException {
       MapHandler result = new MapHandler();
       return qrp.query(
               "select c.id, c.code, de.id, de.customer_debt_id, dos.id, dos.code\n" +
               "from debt de join dossier dos on de.dossier_id = dos.id \n" + 
               "join customer c on dos.customer_id = c.id\n" +
               "where customer_debt_id = ?\n" +
               "and c.code=?\n" +
               "and end_process_date is null", result,debtCode, clientCode);
   }

   /**
       Realiza una consulta parametrizada y devuelve el resultado como una lista de 
       JavaBeans "TablaAS". La creación de la lista y "llenado" de los objetos corre 
       por su cuenta. Lo único que tenemos que hacer es crear la clase TablaAS con 
       propiedades (getter, setter). Las propiedades de los POJO (JavaBeans) que 
       se "llenaran" serán aquellas cuyo nombre coincida con el campo devuelto.
       Dos líneas (más la clase)
   */
   public List<TablaAS> findByClient(String clientCode) throws SQLException {
       ResultSetHandler<list<TablaAS>> blh = new BeanListHandler<TablaAS>(TablaAS.class);
       return qr.query("select * from  CESQ.TABLA_AS where CODCLTE = ?", blh,clientCode);
   }

   /**
       Ejemplo de la misma consulta devuelto como un array 
       o como una lista de POJO's (JavaBean)
   */
   public void test() throws SQLException {
       ArrayHandler ah = new ArrayHandler();
       ResultSetHandler<list<TablaAS>> h = 
                       new BeanListHandler<TablaAS>(TablaAS.class);
       
       Object[] resultArray = 
           qr.query("select * from  CESQ.TABLA_AS FETCH FIRST 2 ROWS ONLY", ah);

       List<TablaAS> result = 
           qr.query("select * from  CESQ.TABLA_AS FETCH FIRST 2 ROWS ONLY", h);

   }
}

Como todas las cosas, obviamente DbUtils tiene un target concreto de aplicación, no es una bala de plata para todo. Ahora bien, si no devolvemos conjuntos de datos grandes, podría usarse como perfecto sustituto de JDBC con un mínimo impacto en el rendimiento y con una importante mejora en legibilidad y mantenibilidad.

Puedes ver más ejemplos en el sitio de DbUtils.


Referencias y más información:

miércoles, 18 de enero de 2012

Expo NASA: La aventura del espacio


Todo lo que una persona puede imaginar, otras podrán hacerlo realidad.
Julio Verne (1828-1905).


La exposición itinerante que la NASA ha traído a Europa está en Madrid desde el pasado Diciembre. Es una visita obligada para curiosos y amantes de la astronáutica y una ocasión excepcional para poder contemplar instrumentos, maquinaria y réplicas de la tecnología actual y la que llevó al hombre a la luna hace casi 43 años.

Pensaba ir a verla de todos modos, pero he tenido la suerte poder de ahorrarme los 16€ de la entrada entrada por ser uno de los ganadores del concurso promovido por amazings.es y la organización de la exposición, así que fui a verla el pasado domingo.

Yuri Gagarin afirmó en una ocasión que su decisión hacia la astronáutica se la debía al excepcional Julio Verne. Y no es para menos. Él es uno de los personajes destacados en la primera sala que nos encontramos en la exposición, la de los soñadores, tras pasar una réplica de la pasarela de acceso a la parte superior del Saturno V y que daba acceso a la nave Apollo.

No voy a detallar aquí el contenido de la exposición, que podéis encontrar en el propio dossier de prensa y en abundante información en la red, sino más bien mi impresión subjetiva y crítica de la misma.

Lo más fascinante de la exposición es poder contemplar in situ y a tamaño real muchas de las cosas que me han fascinado y de las que he visto fotos cientos de veces. Constatas que, hasta que no lo ves con tus propios ojos, no te haces una idea del aspecto y tamaños reales de ciertos artefactos. Por ejemplo, el interior del módulo de ascenso del L.M (Módulo Lunar), tan pequeño, tan frágil... con un aspecto más parecido a un batiscafo que a una nave espacial. Una cosa es que sepas que pilotaban de pie y otra cosa es que lo compruebes con tus propios ojos. Llama la atención especialmente el minúsculo tamaño de ciertas cápsulas espaciales, especialmente la Mercury, que cabría en una furgoneta: meterse ahí dentro sobre un misil Redstone modificado era realmente como estar dentro de la cabeza de un misil balístico. A medida que recorría la exposición reflexionaba sobre el tremendo esfuerzo tecnológico que se realizó en tan pocos años, partiendo totalmente de cero.

Cuando entras en la exposición, te ofrecen unas audioguías (iPod touch) que te presentan varias audiciones/videos por cada sala con información acerca de la misma en una cantidad claramente insuficiente y desproporcionada a las necesidades de información que requieren los objetos expuestos. Y aquí entramos en la parte más inacabada y decepcionante de la exposición: la información. Los objetos expuestos tienen unas etiquetas numéricas que puedes consultar en unos pequeños paneles (sobre los que nos agolpamos los visitantes), cuya brevísima y exigua descripción apenas te satisface y que, por si fuera poco, van apareciendo lentamente en presentación continua (no caben todos en las pantallas) en una desordenada mezcla entre inglés y español. Ya que ofrecen los iPods, la organización podría (por el mismo coste) haber añadido mucha más información multimedia de cada sala e incluso de cada artefacto, evitando así los corros que se forman sobre las pantallitas esperando que aparezca la descripción (que no información) del número que estamos buscando. En definitiva, el problema es que, salvo que sepas lo que estas viendo, me temo que la mayoría de la gente no puede "conocer" lo que está viendo, porque nadie se lo explica.

Por otro lado, los iPod touch cuentan con una excelente pantalla de 3,5 pulgadas que ni siquiera se ha aprovechado para hacer más accesible la exposición a personas con discapacidad auditiva añadiendo subtítulos a los audios y vídeos que ofrece. Vamos, aquí parece que tras todo el esfuerzo, parece que la parte más importante, la de la información, la hubieran dejado a medias. No hacen falta más carteles, ni más grandes. Hubiera bastado con cargar suficiente material en los iPod's. Por otro lado, si en información están suspensos, tienen un cero absoluto en accesibilidad, y no por falta de medios, sino más bien por pura desidia, cosa que me parece totalmente imperdonable, tratándose de una exposición de este calibre.

De hecho, la ausencia de información incluso en temas básicos es tan patente que la organización está constantemente respondiendo en twitter a la pregunta "¿Hasta cuándo está la exposición?", ya que esa información no está disponible ni siquiera en la web oficial. Por cierto: es hasta el 15 de Junio.

Para compensar esta falta de información, recomendaría leer algo sobre la carrera espacial y las misiones de la NASA, ver documentales al respecto, o ver la mini-serie "De la tierra a la luna" antes de ver la exposición, si tenéis ocasión, para poder disfrutar la exposición al completo conociendo lo que se está viendo.

Finalmente, me hubiera gustado llevarme algún recuerdo como alguna serie de maquetas de lanzaderas (titan, atlas, saturno, sts, etc...) oficial. De nuevo, absolutamente decepcionante: apenas algunos carísimos y atroces juguetes de goma, torcidos, que ni siquiera estaban a escala. No había forma de llevarse la famosa serie de lanzaderas o alguna maqueta más o menos decente de un Saturno V o de una lanzadera salvo pequeños pisapapeles metálicos monocolor con poco detalle.

Una excelente exposición mal rematada y poco cuidada en los detalles. En todo caso, una exposición totalmente recomendable por única y excepcional.


Referencias y más información:
Related Posts Plugin for WordPress, Blogger...
cookieassistant.com