Mi primera aplicacion Comet en Glassfish
Grizzly es un framework de desarrollo de servidores Java. No vamos a desarrollar un servidor, ni mucho menos, pero vamos a intentar ver las posibilidades que nos ofrece Grizzly dentro de Glassfish.
Gracias a Grizzly nuevos proyectos nacidos recientemente como JRuby o Phobos cuentan con un rendimiento envidiable y una base solida y estable por su extenso uso en Glassfish como conector HTTP. Esta fue la idea inicial con la que nació, dar soporte HTTP al servidor de aplicaciones de Sun, por entonces el Sun Aplication Server 8.1, para que este pudiera funcionar de forma independiente sin servidor Web.
Grizzly, según sus autores, consigue excelentes rendimientos gracias a que usa la "nueva" librería de entrada/salida introducida en la JDK1.4: NIO. Esta librería además aportar facilidades para desarrollar servidores no bloqueantes (asincronos) lo cual puede resultar muy interesante como veremos a continuación.
Además de su rendimiento Grizzly es tremendamente "programable". En el Weblog de Jean-Francois Arcand podéis encontrar muchísima información pero de lo que yo he leído, destaco cosas tan sorprendentes como la capacidad de desarrollar un control de cuotas de ancho de banda o acceder a la capa de conexiones HTTP del servidor para poder realizar cosas tan novedosas como las aplicaciones Comet.
Estas aplicaciones consisten en enviar datos desde el servidor al navegador sin necesidad de que se realicen peticiones por parte del cliente. Para que este envió push sea posible, el servidor debe registrar y mantener una conexión abierta con los usuarios que se subscriben a la información que será enviada. El ejemplo más claro es el de un chat web como el de GMail, donde el envío de un usuario se ve reflejado en la pantalla de todos los usuarios conectados al chat.
El primer paso para realizar una aplicación comet es configurar el listener-http. En la instalación por defecto de Glassfish V2 existen dos listener el http y el https, para el ejemplo hay que añadir la propiedad cometSupport al http-listener-1 con valor true y eliminar la propiedad proxiedProtocols, que parece que no se lleva muy bien con el soporte de Comet. (Lo estoy consultando)
Una vez nuestro servidor esta preparado vamos a utilizar un ejemplo de chat desarrollado por Jean-Francoise y comentado en su blog. El servlet de una aplicación comet como el del ejemplo, debe instanciarse y ejecutar su método init al arrancar la aplicación, por lo que debemos añadir a su configuración en el web.xml la etiqueta <load-on-startup>0</load-on-startup>. De esta forma obtenemos el contexto o ruta (CometContext) donde se van a esperar las conexiones antes de que la aplicación este funcionando. Podemos decir que el CometContext es el enlace del API de Comet con Grizzly.
super.init(config);
contextPath = config.getServletContext().getContextPath()+"/chat";
CometEngine cometEngine = CometEngine.getEngine();
CometContext context = cometEngine.register(contextPath);
context.setExpirationDelay(20 * 1000);
Una vez el servlet se ha iniciado y por tanto tenemos el contexto comet, los usuarios pueden acceder al chat. Cuando esto ocurre el ejemplo registra el nombre del usuario en la sessión y redirecciona a la página chat.jsp, compuesta por dos iframes.
El primero de ellos es la pantalla donde se muestran los mensajes de los usuarios del chat. Se puede decir que este iframe es el que muestra el uso de la tecnología comet. Para ello llama al servlet del ejemplo enviando el parametro openchat. En el servlet al llegar esta petición se crea un CometHandler. Este interfaz que debemos implementar es el enlace entre nuestra aplicación y Grizzly. Se encarga de registrar el ciclo de vida y los eventos/notificaciones generados en el contexto. Además tiene la posibilidad de adjuntar recursos de la aplicación para hacer uso de ellos al producirse estos eventos. El caso más habitual es adjuntar los streams de salida (HTTPServletResponse ó PrintWriter) para enviar los datos al cliente.
Una vez hemos creado el handler, debemos añadirlo al contexto vinculando así al usuario. mas concretamente a su conexión HTTP.
CometRequestHandler handler = new CometRequestHandler();
handler.clientIP = request.getRemoteAddr();
handler.attach(response.getWriter());
cometContext.addCometHandler(handler);
Todos los eventos que se produzcan en el contexto comet a partir de ahora mediante las llamadas a la operación CometContext.notify() serán enviados como eventos al handler del usuario (Típica implementación del patrón Observer). Estos eventos se generan desde el segundo iframe, que se encarga de enviar los mensajes del chat. El servlet en este caso, traduce el mensajes de los usuarios en un evento lanzado a todos los usuarios vinculados al contexto mediante la ya nombrada operación notify y por tanto generando una llamada a la operación onEvent del interfaz CometHandler.
cometContext.notify("[ " + username + " ] " + message + " ");
La operación onEvent del Handler recibe como parámetro el último interfaz de esta pequeña API, el CometEvent. Bajo este interfaz se almacena toda la información del CometContext y el objeto adjunto a la notificación, en el ejemplo, el mensaje enviado por algún usuario. Como el handler ya tiene los recursos necesarios para enviar los datos al usuarios, tan solo debe redireccionar la información adjunta al evento hasta el cliente.
printWriter.println(event.attachment());
printWriter.flush();
Y esto es todo, creo que merece la pena descargar el ejemplo y probarlo. Hace algunas cosas más de las que comento en el post, pero la basé es asi de simple: tres interfaces implementando un patron Observer. La verdad es que se me ocurren un par de ejemplos de donde usar esta técnologia... veremos si los pongo en práctica.







Estuve echando un vistazo a grizzly me parecio bastante interesante sobre todo como trabaja con NIO, merece la pena bajarse los fuentes y aprender un poco algunos truquillos utiles.
Enviado por batch4j en junio 07, 2007 a las 07:06 PM CEST #