jueves, 30 de mayo de 2013

MetaModel y BeanShell propuestos para Apache™ Incubator

Apache™ Incubator

Es posible contabilizar más de 100 proyectos en el ecosistema de la Apache Software Foundation. El Apache™ Incubator es el punto de partida en el camino a convertirse en un proyecto oficial de la fundación. Recientemente se han propuesto dos proyectos interesantes. La primera propuesta que quería mencionar es la de BeanSheall, uno de los lenguajes de programación utilizado para escribir macros en Apache™ Open Office™. Este último ya es un proyecto oficial de la fundación; razón por la cual se podría justificar la incorporación directa a este proyecto en vez de pasar por todo el proceso de incubación. Quizás se justifique más incorporarlo en Apache™ Commons debido a que este proyecto ha estado relacionado con Apache™ Maven y Apache™ JMeter desde hace varios años.

La segunda propuesta es MetaModel; un framework muy interesante que provee una interfaz común para acceso, exploración y consulta de diferentes tipos de fuentes de datos. Entre los objetivos iniciales del proyecto se menciona establecer vínculos con otros proyectos de primer nivel como POI, Gora, HBase y CouchDB. Resulta interesante saber que estas dos tecnologías podrían incorporarse próximamente al ecosistema de la ASF, por lo que les invito a suscribirse mediante RSS a este blog si está interesado en conocer más acerca del futuro de ambos.

miércoles, 29 de mayo de 2013

Proyectos de Apache™ Bloodhound en el Google Summer of Code 2013

GSoC 2013

El 27 de mayo de 2013 es la fecha en que se determinaron las propuestas que se aceptarían como parte del Google Summer of Code. En total este año se han aceptado 1,192 propuestas de proyectos de estudiantes de varias latitudes. Hasta el momento se han confirmado tres proyectos relacionados con Apache™ Bloodhound

Los proyectos son :

  1. Customizable time series reports
    por Pranay B. Sudre
    • en este caso espero poder estar apoyando el trabajo con fuentes de
      datos que permitan representar las tendencias en líneas de tiempo
      anotadas.
  2. Embeddable tickets/objects por Antonia Horincar
    • Esta es una oportunidad muy buena para continuar el trabajo de José Angel Franco
      acerca de una API de servicios REST para los recursos de Trac y
      Bloodhound
  3. Add time series reports for Bloodhound por Hua Xiang
    • mi colaboración en este caso puede ser relativamente similar a la
      del primer proyecto.

Le invito a suscribirse mediante RSS a este blog si está interesado en conocer los que acontece con estos proyectos. Espero que haya más noticias pronto acerca de las propuestas restantes.

PS: Otras organizaciones han propuesto proyectos interesantes como este acerca de RTEMS un sistema operativo de tiempo real y código abierto; o las propuestas del W3C. Sospecho que hay más detalles en la lista completa de proyectos aceptados.

lunes, 27 de mayo de 2013

Knockout.js ... lo que Usted no vió

KnockoutJs banner

Le dediqué un tiempo a conocer más acerca del patrón MVVM . Me agrada, así que se suma a la lista de tecnologías relacionadas con Microsoft que realmente recomiendo. Este es un enfoque propuesto por la compañía que consiste, según sus propios autores, en una especialización del enfoque Modelo Vista Controlador para tecnologías como Windows Presentation Foundation y Silverlight. En la ingeniería de software este tipo de soluciones resulta muy útil para construir interfaces de usuario. Su ámbito de aplicación se ha extendido también al framework ZK (del cual tengo muy buenas referencias) y a HTML5. Incluso existe Google mdv, una variante relacionada con estos temas. En mi caso particular puse mi atención en la implementación para Javascript conocida como KnockuotJs. En esta ocasión no pretendo comentarles las peculiaridades de su uso . Para esto les recomiendo leer este artículo y la documentación de KnockoutJs. Más bien pretendo comentarles algunos detalles que me llamaron la atención al probar los tutoriales.

Dependencias y <select />

KnockoutJs tutorial 1

Al terminar con el primer tutorial debe quedarnos como resultado un modelo más o menos como el que se muestra a continuación.

// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");

    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();    
    }, this);

    this.capitalizeLastName = function() {
        var currentVal = this.lastName();        // Read the current value
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    };
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

A continuación se muestra la vista relacionada después de añadir un elemento <select /> conectado con el atributo lastName del modelo.

<!-- This is a *view* - HTML markup that defines the appearance of your UI -->

<p>First name: <strong data-bind="text: firstName">todo</strong></p>
<p>Last name: <strong data-bind="text: lastName">todo</strong></p>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<p>Full name: <strong data-bind="text: fullName"></strong></p>
<button data-bind="click: capitalizeLastName">Go caps</button>

<p>Last name: 
  <select data-bind="value: lastName" >
      <option value="x">Pérez</option>
      <option>Suárez</option>
      <option value="z">García</option>
      <option>Bertington</option>
      <option>BERTINGTON</option>
  </select>
</p>

En este punto me resultó muy interesante que la librería preserva automáticamente la consistencia del modelo teniendo en cuenta los bindings. Esta es la razón por la cual el botón Go caps solo funciona cuando el apellido es Bertington . La razón es que el binding con el combobox limita el número de valores que se le puede asignar al atributo del modelo. En el ejemplo el valor mencionado es el único que tiene también una opción con las letras mayúsculas.

Las listas y <select /> ... otra vez …

KnockoutJs tutorial 2

Pasando la página (literalmente ;) llegamos al segundo ejemplo que trata sobre los bindings para listas y colecciones de objetos. Lo que se muestra es impresionante y se completa cada paso satisfactoriamente; pero ... hay (al menos) un detalle muy sutil que se escapa. Utilizando Firebug, DragonFly o una herramienta similar es posible constatar que el atributo value de los elementos <option /> utilizados para escoger el menú siempre está asignado a una cadena vacía (al menos en las versiones de Opera, Firefox y Google Chrome que utilicé para probar ...). Con el fin de enviar los datos hacia el servidor es posible que sea útil asignar ciertos identificadores. Para lograr ese objetivo en la versión final es posible añadir en el model el atributo mealId

// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
    var self = this;
    self.name = name;
    self.meal = ko.observable(initialMeal);

    self.formattedPrice = ko.computed(function() {
        var price = self.meal().price;
        return price ? "$" + price.toFixed(2) : "None";        
    });
}

// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
    var self = this;

    // Non-editable catalog data - would come from the server
    self.availableMeals = [
        { mealId: "s", mealName: "Standard (sandwich)", price: 0 },
        { mealId: "p", mealName: "Premium (lobster)", price: 34.95 },
        { mealId: "u", mealName: "Ultimate (whole zebra)", price: 290 }
    ];    

    // Editable data
    self.seats = ko.observableArray([
        new SeatReservation("Steve", self.availableMeals[0]),
        new SeatReservation("Bert", self.availableMeals[0])
    ]);

    self.addSeat = function() {
        self.seats.push(new SeatReservation("", self.availableMeals[0]));
    }

    self.removeSeat = function(seat) { self.seats.remove(seat) }

    self.totalSurcharge = ko.computed(function() {
       var total = 0;
       for (var i = 0; i < self.seats().length; i++)
           total += self.seats()[i].meal().price;
       return total;
    });
}

ko.applyBindings(new ReservationsViewModel());

Después es necesario utilizar el binding optionsValue en la vista como se muestra a continuación:

<h2>Your seat reservations</h2>

<button data-bind="click: addSeat">Reserve another seat</button>

<table>
    <thead><tr>
        <th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
    </tr></thead>
    <!-- Todo: Generate table body -->
    <tbody data-bind="foreach: seats">
        <tr>
            <td><input data-bind="value: name" /></td>
            <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName', optionsValue: 'mealId'"></select></td>
            <td data-bind="text: formattedPrice"></td>
            <td><a href="#" data-bind="click: $root.removeSeat">Remove</a></td>
        </tr>
    </tbody>
</table>

<h3 data-bind="visible: totalSurcharge() > 0">
    Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>

Al aplicar estos cambios se logra generar unos elementos como los siguientes:

<select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName', optionsValue: 'mealId'">
  <option value="s">Standard (sandwich)</option>
  <option value="p">Premium (lobster)</option>
  <option value="u">Ultimate (whole zebra)</option>
</select>

¡Urra! ... pero no todo es color de rosa. Como resultado la columna Surcharge deja de actualizarse . Por consiguiente no se muestra el sub-total que se calcula en el último paso. Sin embargo el comando Remove introducido en esa misma etapa sí sigue funcionando. Esto me hace pensar que haya algún problema al calcular alguno de los diferentes tipos de bindings involucrados.

Quizás existe una forma de hacer que vuelvan a funcionar las actualizaciones, pero hasta este momento no la he encontrado. Tampoco he tenido mucho tiempo para profundizar en el tema.

Conclusiones

KnockuotJs es una librería excelente. Sinceramente preferiría que algunos detalles de los bindings fueran más parecidos al estilo de Genshi. De todas maneras los própositos son diferentes; quizás ni siquiera sea apropiado o posible realizarlo.

Me da la impresión de que no voy a poder dejar de utilizarlo después que lo pruebe en alguna aplicación. La recomiendo. Le invito a suscribirse a este blog mediante RSS si desea conocer si descubro algo más en el resto de los tutoriales . En próximos artículos comentaré cómo utilizar esta solución para enriquecer la experiencia de usuario de sus aplicaciones. A pesar de estas pifias los resultados son impresionantes.

miércoles, 15 de mayo de 2013

Apache™ Bloodhound 0.6 : Bootstrap handlers

Apache™ Bloodhound

Rumbo a la próxima liberación de la versión 0.6 de Apache™ Bloodhound en este artículo comienzo una serie con el objetivo de presentar las diferentes características que marcan pautas con respecto a las versiones precedentes . Explicaré brevemente su utilidad y funcionamiento. Estimo tener tiempo también para redactar algún que otro tutorial . Espero que me perdonen si no logro satisfacer todas las expectativas . Comprendan que todavía hay muchas cosas por hacer y estoy increíblemente ocupado . Tod@s l@s interesad@s en estos temas pueden mantenerse informados del desarrollo de la serie . Solo deben suscribirse mediante RSS .

Hasta el presente la arquitectura que me robó tantas noches de sueño ha probado satisfacer el 95% de los requisitos que se plantearon inicialmente . Para conocer los detalles , empezamos por el principio ...

¿Qué son los bootstrap handlers?

Una aplicación web consta de múltiples funcionalidades , secciones y opciones de navegaciones. Por lo tanto todo framework de desarrollo de aplicaciones web contiene un subsistema que se encarga de seleccionar el componente (e.g. clase) responsable por procesar las peticiones HTTP que se envían hacia el servidor. Trac y por consiguiente Apache™ Bloodhound no son la excepción . En las versiones anteriores (i.e. Bloodhound<0.6 ) el manejo de las peticiones web de ambos gestores de incidencias lo realizaban exactamente las mismas clases exactamente de la misma forma.

En pocas palabras a partir de la versión 0.6 de Apache™ Bloodhound el manejo de peticiones web varía un poco ... y para mejor :) . El siguiente diagrama muestra cómo es que todo esto se lleva a cabo.

Bloodhound bootstrap handlers explained

El primer actor que interviene en el lado del servidor es siempre un servidor web e.g. Apache httpd , Nginx , tracd, ... en fin , cualquier servidor que sea capaz de correr sitios implementados con Python. Posteriormente , de ser necesario, se ubican los frontends (gateways) responsables de adaptar las tecnologías del servidor web (e.g. CGI, FastCGI, ...) al estándar WSGI . En todos los casos se llega a la función trac.web.main.dispatch_request , el punto de entrada del manejo de peticiones web de Trac . Hasta este punto Bloodhound solo introduce cambios menores relacionados con el middleware de autentificación de tracd ; nada en especial.

A partir de este punto aparecen las diferencias . El algoritmo de Trac funciona de la manera siguiente:

  1. Trac determina la configuración de los directorios donde están los environments,
    estableciendo si se corren varios dentro de una misma carpeta o uno solo .
  2. Trata de extraer del camino de la URL el nombre del environment al que va
    dirigido la petición e.g. si la URL fuera http://dominio.com/env/something/else
    entonces el camino de la URL sería /env/something/else y el primer componente
    seria el nombre del environment (env en el ejemplo).
    • En caso de no conseguirlo e.g. si la URL fuera http://dominio.com/
      entonces muestra un índice de los proyectos disponibles.
  3. Se instancia el environment al que va dirigida la petición.
  4. Se crea un objeto del tipo trac.web.api.Request
  5. Se utiliza el resto del camino e.g. /something/else para determinar dentro
    de ese environment la instancia de la interfaz trac.web.api.IRequestHandler
    que es responsable de procesar la petición y dar
    una respuesta al cliente.

En la práctica los pasos (2) , (3) y (4) son un poco limitados . La razón por la cual Apache™ Bloodhound introduce los objetos llamados bootstrap handlers es exactamente poder implementar algoritmos personalizados para realizar estos pasos. Como consecuencia los pasos anteriores varían de la siguiente manera :

  1. Bloodhound determina la configuración de los directorios donde están los environments,
    estableciendo si se corren varios dentro de una misma carpeta o uno solo .
  2. En la variable WSGI trac.bootstrap_handler se busca una
    definición de entry point (e.g. package.module:object.attribute)
    con el módulo y la referencia al objeto bootstrap handler
    • si no se encuentra dicha instancia se utiliza trac.hooks.default_bootstrap_handler
      como valor predeterminado.
  3. Se ejecuta el método open_environment() del objeto determinado en el paso anterior.
    Como resultado se obtiene :
    • El nombre del environment incluído en la variable trac.env_name
      del entorno WSGI
      • Nótese que el procedimiento puede ser completamente diferente a los pasos
        (2) y (3) de la secuencia anterior
    • El environment debidamente inicializado
      • La implementación predeterminada en trac.hooks.default_bootstrap_handler
        analiza el camino de la URL de manera similar a cómo se hace en Trac .
        La diferencia más notoria consiste en el hecho que las que comienzan con
        /products/ se asocian a environments de un producto
        e.g. http://dominio.com/env/products/P1/wiki/TitleIndex se procesaría
        en el contexto del environment del product P1 en el environment env
        mientras que la URL http://dominio.com/env/wiki/TitleIndex es procesada
        por el environment env (global) directamente.
  4. Se ejecuta el método create_request para obtener un objeto
    del tipo trac.web.api.Request o equivalente
  5. Se utiliza el resto del camino e.g. /something/else para determinar
    la instancia de la interfaz trac.web.api.IRequestHandler dentro
    de ese environment que es responsable de procesar la petición y dar
    una respuesta al cliente.

Variantes existentes de bootstrap handlers

El framework Routes , inspirado en Ruby on Rails , se ha convertido en el estándar para este tipo de enrutamiento de peticiones . En un proyecto que será publicado próximamente se están preparando unas variantes que permiten el uso de este framework para implementar bootstrap handlers para Apache™ Bloodhound. De especial interés resultan los casos en que se utiliza el encabezamiento HTTP Host para identificar los environments a partir del dominio al que va dirigida la petición e.g. http://dominio.com/wiki/TitleIndex para el environment global y http://P1.dominio.com/wiki/TitleIndex para el environment del producto P1 . Otro campo de aplicación es la integración con otros frameworks e.g. Pylons , Turbogears 2 , ...

Conclusiones

Apache™ Bloodhound ofrece una versión mejorada del mecanismo que facilitaría tanto despliegues similares a los de Trac como otros basados en sub-dominios , más parecidos al dominio edgewall.org (i.e. babel.edgewall.org, genshi.edgewall.org, trac.edgewall.org) . Todo esto es posible gracias a la arquitectura multi-productos ; que ha probado satisfacer el 95% de los requisitos que se plantearon inicialmente para Apache™ Bloodhound .

Solo me queda invitar a tod@s l@s interesad@s en estos temas a suscribirse mediante RSS a este blog para estar al tanto de las mejoras que propone este gestor de incidencias .