Las aplicaciones web legacy son sincrónicas por naturaleza. El usuario interactua con la interfaz web que se muestra en el navegador, el navegador realiza peticiones de vuelta al servidor de acuerdo a la interacción del usuario, y el servidor responde a estas peticiones con una nueva presentación para el usuario - fundamentalmente es un proceso sincrónico.
Sin embargo, hoy en día existe una variante: las aplicaciones Web Asincronas. Esta nueva forma de encarar las aplicaciones web está iniciando una revolución que cambiará completamente a las soluciones web del futuro.
Sincrónico vs. Asincrónico
Como dijimos, las aplicaciones web legacy son sincrónicas. Esto significa que la presentación que se le entrega a los usuarios representa una "foto" de un momento específico de un sistema dinámico. Esta foto se vuelve obsoleta entre las interacciones del usuario, y no necesariamente brinda una vista exacta del estado actual del sistema. Incluso aunque se utilicen técnicas Ajax, el proceso sincrónico no cambia. Usando el objeto XmlHttpRequest y técnicas Ajax logramos tener un modelo de interacción de grano más fino que refrescar una página completa, pero las peticiones se siguen generando basándonos en interacciones del usuario, por lo que el proceso sigue siendo sincrónico, y persiste el problema de tener vistas potencialmente obsoletas.
La Web Asíncrona es fundamentalmente diferente, y es esta diferencia la que revoluciona el comportamiento de las aplicaciones web. En la Web Asíncrona es posible entregar al usuario cambios espontáneos en la presentación , a medida que cambia el estado de un sistema dinámico, sin la necesidad de que el usuario interactue con la interfaz.
Las ventajas son obvias, ya que ahora podemos mantener una representación exacta del sistema en el navegador del usuario. Hay varios ejemplos, como ser cualquier sistema que brinda una vista de un sistema dinámica, como ser un portolio de acciones, un inventario, o un calendario. Cuando hay muchos usuarios interactuando en el mismo sistema, las interacciones de un usuario pueden impactar espontáneamente lo que ven otros usuarios, creando así un sistema verdaderamente colaborativo - la esencia de la Web 2.0. Nuevamente, hay varios ejemplos, como un cliente de chat simple, o una subasta por eBay. En última instancia, la mayoría de los sistemas con las que interactúan los humanos son colaborativos por naturaleza, por lo que también debería serlo la interfaz que utilizan.
¿Cómo funciona la Web Asíncrona?
Para lograr una Web Asíncrona necesitamos poder enviar respuestas al navegador de manera espontánea, pero ¿cómo podemos lograr esto dentro de los límites del protocolo HTTP? No podemos enviar respuestas a peticiones inexistentes, por lo que va a ser necesario manipular el mecanismo de petición/respuesta para lograr el efecto deseado.
La forma más directa de lograr esto es usando un mecanismo de consulta (HTTP Polling). Se envian peticiones a intervalos regulares de tiempo, con lo que el sistema tiene continuas oportunidades de actualizar la presentación. Esta técnica, que se muestra a continuación, no es ideal, ya que no existe un intervalo de consulta ideal. Siempre hay un balance que mantener entre la frecuencia de actualización y la verbosidad del sistema. Como vemos, es posible que ocurran múltiples eventos entre cada consulta, pero también es posible que no ocurran eventos. En un análisis final, el mecanismo de consultas no es un mecanismo asíncrono real.
La próxima opción es considerar el streaming de HTTP (HTTP Streaming), en donde se envia múltiples respuestas a una única petición, como vemos a continuación. Este es un mecanismo eficiente, pero desafortunadamente no funciona en todas las configuraciones de proxy/firefall que existen, lo cual lo hace inconveniente para despliegues de propósito general.
La última opción para considerar es la consulta larga HTTP (HTTP Long Polling), en donde se realiza una petición por adelantado para una respuesta futura, y esta respuesta se bloquea hasta que ocurra un evento que la dispare. Este mecanismo, que vemos a continuación, es casi tan eficiente como el streaming de HTTP, y es totalmente compatible con las configuraciones de proxy/firewall ya que resulta indistinguible de un servidor que responde lento.
Entonces, la consulta larga brinda un mecanismo viable para implementar una Web Asíncrona, y de hecho es el mecanismo utilizado en varias implementaciones actuales, como Ajax Push y Comet. Aunque este mecanismo es relativamente simple, las ramificaciones de retener estas peticiones son importantes. Vamos a examinar estas consecuencias en detalle comenzando con un Servlet.
¿Existen los Servlets Asíncronos?
El procesamiento normal en un Servlet necesita un hilo por petición, por lo que si vamos a bloquear de forma indefinida a estos hilos, y si necesitamos a un hilo por cliente, muy rápidamente vamos a agotar los hilos del servidor de aplicaciones. La especificación Java EE está dispuesta a solucionar este problema en Servlet 3.0 (JSR-315), en donde aparece el Procesamiento de Peticiones Asíncronas (Asynchronous Request Processing - ARP), el cual está pensando para manejar el mecanismo de consulta larga. Mientras tanto, hay otras alternativas por fuera del estándar que brindan distintas soluciones ARP:
- Tomcat 6 Comet Processor
- Glassfish Grizzly Connector
- Jetty Continuations
- WebLogic Future Response Servlet
- WebSphere Asynchronous Request Dispatcher
Todos estos mecanismos funcionan bien con la consulta larga, pero son todos diferentes, lo que significa que cualquier solución tendrá que estar personalizada para el entorno de despliegue. Para los servidores de aplicaciones que no están en esa lista, va a ser necesario no usar Servlets para implementar una consulta larga escalable. Así que, desde el punto de vista de los Servlets, es posible crear una Web Asíncrona, pero hasta que no aparezca el estándard no existen soluciones únicas.
¿Qué procesamiento se necesita del lado del cliente?
La consulta larga es guiada por el cliente, por lo que se necesita cierta cantidad de procesamiento del lado del cliente para implementar la Web Asíncrona. Como mínimo, necesitamos un mecanismo que gestione las peticiones bloqueantes asociadas a las consultas largas, y un mecanismo que actualice la presentación cuando ocurra una respuesta, como vemos a continuación.
El proceso es el siguiente:
- Se envia la petición bloqueante inicial usando XmlHttpRequest para iniciar la secuencia de consulta larga.
- Cambia algún estado en la aplicación que genera una respuesta que contiene las actualizaciones para la presentación.
- Se envia la respuesta generada al cliente.
- Un JavaScript en el cliente atiende la respuesta y actualiza la presentación.
- Se vuelve al paso 1, en donde se genera otra petición bloqueante.
Aunque el proceso parece bastante simple, hay algunos detalles a tener en cuenta. Para empezar, el mecanismo de consulta larga puede no ser robusto en todas las condiciones de red, y es posible que se pierda una conexión bloqueante. Para que el mecanismo sea robusto, se necesita mantener alguna estrategia de keep-alive. Un mecanismo estándar de pulsos es suficiente.
Ocurre un problema más complejo en cuanto al límite de conexiones del navegador, en particular con IE que tiene un límite de 2 conexiones al mismo dominio. El mecanismo de consulta larga necesita una de estas conexiones, y se necesita otra para gestionar el procesamiento de peticiones normales asociadas con la integración del usuario, así que debería alcanzar, ¿no? Bueno, tenemos lo justo para el caso más simple de una única ventana del navegador a la aplicación, pero ¿qué pasa cuando se abren muchas solapas o ventanas a la aplicación, o en un entorno de portales en donde cada página tiene múltiples portlets que necesita usar un mecanismo de consulta larga? No es posible que cada una de estas vistas inicie su secuencia de consulta larga, porque el mecanismo va a fallar cuando se alcance el límite de conexiones del navegador. Es necesario gestionar una única conexión bloqueante, y compartirla entre múltples vistas del navegador y portlets.
Entonces, desde la perspectiva del cliente, vemos que es posible implementar una Web Asíncrona, pero vamos a necesitar aplicar técnicas Ajax y solucionar varios problemas relacionados con mantener las conexiones bloqueantes asociadas a la consulta larga.
¿Y qué pasa con compartir conexiones del servidor?
Ya que estamos en el tema de gestionar conexiones de múltiples vistas y portales, volvamos al lado del servidor y revisemos a las conexiones bloqueantes, en particular en ambientes de portales. No tenemos problemas si estamos usando una única aplicación web, ya que tenemos una única conexión bloqueante para gestionar, pero en un entorno de portales nos encontramos con la posibilidad de tener varios portlets que pueden desplegarse en distintas aplicaciones web. En este caso, ¿en dónde gestionamos la única conexión bloqueante que el navegador cliente establece? Ninguno de los motores de portales existente considera esta necesidad para un mecanismo ARP compartido, por lo que otra vez tendremos estamos forzados a una solución por fuera de la especificación Java EE actual. Necesitamos más infraestructura del lado del servidor para brindar una conexión compartida única que gestionar el mecanismo de consulta larga a través de las aplicaciones del portal, y necesitaremos usar algún sistema de IPC via JMS o simliar para lograrlo.
Y por último, ¿hay algún modelo de programación para todo esto?
Hasta ahora estuvimos discutiendo el "detrás de escena" para implementar una Web Asíncrona, pero toda esta información no da como resultado aplicaciones, y en últimoa instancia son las aplicaciones las que van a revolucionar el uso de la Web. Como vimos, ya sabemos que se necesita algo de programación Ajax en el cliente, pero esto está bien por afuera de la especificación Java EE, que en la presentación habla de JSP y JSF. ¿Estamos forzados a movernos hacia un modelo de programación centrado en el cliente para construir una Web Asíncrona, o podemos aprovechar las tecnologías existentes? JSF va a ser el modelo de programación predominante para Java EE, por lo que representa el lugar más lógico para solucionar el problema. Ya sabemos que la especificación JSF 1.2 no tiene capacidades Ajax; y aunque JSF 2.0 introduce algunos mecanismos Ajax, no extiende el modelo de programación más allá del ciclo de vida normal de petición/respuesta. Nuevamente, estamos forzados fuera de la especificación Java EE para adoptar un modelo de programación para aplicaciones Web Asíncronas.
Más preguntas que respuestas
Entonces, es totalmente posible crear aplicaciones Web Asíncronas, pero el estándar Java EE tiene poco para brindar un soporte completo. Sabemos lo que necesitamos hacer, y varios problemas para enfrentar, pero todavía no existe un modelo de programación apropiado para construir aplicaciones reales. La verdad es que, en este momento, estamos con más preguntas que respuestas.
La Web Asíncrona representa una revolución en la forma de pensar y crear aplicaciones web, que llevará a una nueva generación de servicios. Estamos viviendo el inicio de una revolución, que acaba de empezar.