miércoles, diciembre 31, 2008

Otro blog que os recomiendo (si os gusta el heavy)

Resulta que mi vecino de mesa en el trabajo es también un bloguero, y yo sin saberlo, y además, aunque no lo aparente, un adicto del heavy metal (eso sí que lo sabía). Si os gusta este tipo de música pasaros por este blog: f7f.blogspot.com (nota: está en inglés).

martes, diciembre 30, 2008

Otra aplicación para iPhone: iMarcador

Pensé que ya os había hablado de ella pero he comprobado que no es así. Hace tiempo os hablé de la web diseñada para iPhone para consultar cuando vienen los próximos autobuses a una parada; pues bien, también por esa época hice otra web. Consultándola desde el iPhone veremos los marcadores en tiempo real de la Primera y Segunda división del fútbol español (bueno, de la Liga BBVA y de la liga Adelante, ¡vaya chorrada de nombres!).

lunes, diciembre 29, 2008

Peces, peceras y acuarios

The sweet fish es un nuevo blog en internet. Según promete nos explicará situaciones y anécdotas divertidas a la par que didácticas. Además se opina y se denuncian algunas injusticias (como la calidad de la red de cercanías de Renfe...). Os invito desde aquí a todos mis lectores a visitarlo.

domingo, diciembre 28, 2008

25 impresionantes juegos en Javascript

A veces me asombro de lo que son capaces de hacer algunas personas con algo que a priori parece tan limitado como es Javascript. En este enlace podeis ver 25 juegos programados con Javascript (algunos de ellos usando librerías como MooTools... y otros no).

¡Zaragoza gana la Expo 2012 de Gnomos de Jardín!

(Aviso: Está noticia fue una broma por el Día de los Inocentes.)

Hace apenas 20 minutos el alcalde de Zaragoza, Juan Alberto Belloch, ha comunicado a través de Aragón Televisión la importante noticia. Zaragoza albergará en 2012 la feria más importante de Gnomos de Jardín.
En unos días comenzarán a recoger voluntarios para una Exposición que abarcará más de 120 hectáreas, como cinco veces la Expo 2008 que ya se celebró en esta ciudad. Para ello será necesario destruir el actual Parque del Agua, donde hasta ahora se alojaba una noria que no sube el agua a ninguna parte, un campo de golf donde las pelotas son naranjas y unos rápidos donde los monitores se empeñan en volcar las balsas. Todo ellos se convertirá en un jardín gigante lleno de duendecillos de jardín que vendrán a visitar más de 3.000 millones de personas durante enero de 2012.
Las obras de destrucción del Parque del Agua se realizarán rápidamente después de la experiencia en contruir-destruir-construir adquirida trás años de entrenamiento (Plaza de la Ciudadanía...).
Se espera llegar a tiempo para la fecha, en caso contrario se comenzará a trabajar en turnos para aprovechar las 24 horas del día ya que los posibles accidentes laborales (como ocurrió en la anterior Expo) son admisible con tal de llegar a tiempo a tan importante cita.

sábado, diciembre 27, 2008

FireUnit: JavaScript Unit Testing Extension

FireUnit es una extensión de Firefox (mejor dicho, de Firebug) que nos ayuda a hacer test unitaros de javascript. Una vez instalada nos aparece una nueva pestaña en nuestro Firebug donde veremos los resultados de los test que hemos programado en el javascript de la web que estamos visualizando. 
Podemos hacer cosas como estas:


// Si el primer parámetro vale true el test es correcto, si es false es incorrecto
var nombre = null;
if(nombre){
fireunit.ok(true, "Nombre válido");
}else{
fireunit.ok(false, "El nombre tiene un valor nulo o no válido");
}

// Compara dos Strings, si son iguales el test es correcto
var password = "123";
var valPassword = "123";
fireunit.compare(
password,
valPassword,
"Password válido"
);

// Valida un String contra una expresión regular
fireunit.reCompare(
/The .* fox jumped the log./,
"The lazy brown fox jumped the log.",
"Compare a string using a RegExp."
);

// Muestra un resumen con los test correctos y fallados
fireunit.testDone();

Además también permite simular eventos javascript:

var input = document.getElementsByTagName("input")[0];
fireunit.mouseDown(input);
fireunit.click(input);
fireunit.focus(input);
fireunit.key(input, "a");

Dejándolo niquelado

El pasado martes fui a la C/Unceta 70 (Zaragoza) para enseñar a mi novia lo que en breves será la tienda de videojuegos (y más) del barrio de las Delicias: Nexus. Allí estaban los emprendedores que se han lanzado a esta aventura manos a la obra dejandolo todo "niquelado" (dos de ellos me recordaron a Manolo y Benito).
Y nada, que parece que esto está a punto... en unos días espero poder anunciaros la inaguración.

miércoles, diciembre 24, 2008

Windows Enabler

Una aplicación muy simple y a la vez muy útil que usaba hace tiempo y me gustaría compartir con vosotros es Windows Enabler. Permite poner "enabled" los botones de una aplicación de Windows que están "disabled". ¿Y para que puede ser interesante? pues por ejemplo para poder desactivar ese antivirus que ralentiza tu PC y que por culpa del de sistemas no tenemos privilegios para quitar.
Podeis descargar la aplicación aquí.

Úsalo bajo tu responsabilidad.

Campeonato de España de Mus 2009


Si os gusta el mus y quereis participar en el torneo más importante a nivel nacional todavía podeis hacerlo con un descuento del 50%; esta promoción dura hasta el 11 de Enero así que si estais interesados daros prisa. En la web teneis toda la infomación, incluidos los 80.000€ en premios.

By the way (que dirian los ingleses), la pareja que me eliminó en el campeonato de Kukuxumuxu ha ganado en Aragón con lo que se van a jugar la final a Pamplona. Ya comenté que eran buenos, muy buenos, de esos que no te dejan jugar y ellos no paran de sacar piedras. Espero que ganen ellos y así poder decir que me eliminaron los campeones de España.

martes, diciembre 23, 2008

Próximo cambio a FeedBurner

Bueno, acabo de hacer una cuenta en feedburner y pronto el RSS de este blog pasará por allí. Así podré saber si alguno de vosotros me lee desde un lector de rss en lugar de vía web. Supongo que esto puede afectar a la URL de la sindicación, la nueva va a ser:

http://feeds.feedburner.com/vsbabylon

He visto que Blogger tiene una opción para añadir esto, así que puede ser que el cambio sea transparente... mañana con tiempo lo sabré.

Editado 29/12/2008:
Como he podido comprobar estos de Google hacen bien las cosas; el paso a Feedburner es transparente y el RSS (Atom) de Blogger se redirecciona el solito a través de Feedburner por lo que no hace falta cambiar la URL de las sindicaciones.

Una de botellas

Cuando vais a un restaurante y pedís una botella de vino lo más normal es que os saquen una botella de 0,75 litros, pero estas no son las únicas que existen y los franceses les han puesto nombre. Aquí teneis una tabla explicando la capacidad, el número de botellas "normales" a las que equivale y el nombre o nombres que tiene:
  • 1.5 litros = 2 botellas -> Magnum
  • 3 litros = 4 botellas -> Doble magnum o Jéroboam en Borgoña
  • 4.5 litros = 6 botellas -> Jéroboam en Burdeos o Rehoboam en Borgoña
  • 6 litros = 8 botellas -> Imperial en Burdeos, o Mathusalem en Borgoña
  • 9 litros = 12 botellas -> Salmanazar
  • 12 litros = 16 botellas -> Baltasar
  • 15 litros = 20 botellas -> Nabucodonosor
  • 20 litros = 28 botellas -> Solomon
  • 27 litros = 36 botellas -> Primat

lunes, diciembre 22, 2008

Invocar desde Hibernate procedimientos almacenados en Oracle

En la aplicación que estoy desarrollando la persistencia se realiza con Hibernate. En general nosotros nos lo guisamos todo pero para algunas funcionalidades complejas y que requieren "comunicarse" con otra aplicación ya desarrollada me dicen el nombre del procedimiento almacenado (stored procedure) que ya existe y los parámetros que le debo pasar (en la mayoría de los casos Arrays) de forma que yo no tengo que implementar esa lógica. Cada vez que tengo alguna duda con Hibernate suelo consultar el libro Java Persistence by Hibernate, que me ha resuelto más de una y dos dudas pero en este caso no me sirvió de nada. No me decía como llamar a un PL/SQL mediante la "current session" de Hibernate, para los que tengais el mismo caso os muestro como lo he resuelto yo (quizá haya mejores formas... pero esta garantizo que funciona).

Algunos de las clases que se van a usar:

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.OracleCallableStatement;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
Y a continuación un ejemplo de como invocariamos el procedimiento "p_calcular" que está dentro del package "pack". Este Stored Procedure tiene cuatro parámetros de entrada y devuelve un Number:

OracleCallableStatement callable = null;
try {
// conseguimos la conexion con la que llamaremos al procedimiento
OracleConnection conn = (OracleConnection) getSession().connection().getMetaData().getConnection();
// establecemos el paquete al que vamos a llamar
callable = (OracleCallableStatement) conn.prepareCall("{call pack.p_calcular (?, ?, ?, ?)}");

// declaramos el parámetro que nos devolverá el procedimiento
callable.registerOutParameter(1, OracleTypes.ARRAY, "T_REF"); // NUMERIC

// en esta variable enviaremos los parámetros de entrada
ARRAY newArray;

// declaramos los tipos de los parámetros de entrada, estos tipos tendrán que estar declarados en el Oracle
ArrayDescriptor tRef = ArrayDescriptor.createDescriptor("T_REF", conn);
ArrayDescriptor tMatricul = ArrayDescriptor.createDescriptor("T_MATRICUL", conn);

// rellenamos los parámetros de entrada con los valores que queremos pasar
Long[] param1 = new Long[] { unitId };
newArray = new ARRAY(tRef, conn, param1);
callable.setArray(1, newArray);

String[] param2 = new String[] { memberId };
newArray = new ARRAY(tMatricul, conn, param2);
callable.setArray(2, newArray);

Long[] param3 = new Long[] { Long.valueOf(userId) };
newArray = new ARRAY(tRef, conn, param3);
callable.setArray(3, newArray);

Integer[] param4 = new Integer[] { planning.getPriority() };
newArray = new ARRAY(tRef, conn, param4);
callable.setArray(4, newArray);

// invocamos al procedimiento
callable.execute();

// obtenemos el array con los resultados devueltos
ARRAY array = callable.getARRAY(1);
Integer newPlanningId = 0;
int[] result = array.getIntArray();

if (result.length > 0) {
// en este ejemplo el procedimiento sólo devuelve un valor entero
newPlanningId = result[0];
}
return newPlanningId;
} catch (SQLException sqle) {
logger.error(sqle.toString());
throw new Exception(sqle);
} finally {
try {
callable.close();
} catch (Exception e) {
logger.error(e.getMessage());
}
}
Si conoceis otra forma más sencilla de hacer esto, por favor, ponérmelo en los comentarios.

Actualizado 18/03/2009: Aquí encontrareis otro forma de hacerlo. Es más automatizada pero con algunas limitaciones. Echadle un ojo antes de decidiros por una u otra forma.

jueves, diciembre 18, 2008

Pruebas de rendimiento con JMeter

JMeter es un programa java que se puede utilizar para testear aplicaciones web. Simula mediante hilos a usuarios que se conectan contra un servidor, de modo que una vez configurado puedes comprobar que tal funciona tu servidor y aplicación cuando haya, por ejemplo, 3000 usuarios conectados.
He utilizado este programa para simular a 2000 usuarios concurrentes conectados contra el servlet que os comente en un post hace unas semanas desplegado sobre un Tomcat 6 (usando NIO). No se si esta información es útil, la prueba no la he hecho sobre un server sino sobre un PC de sobremesa con 2Gb de RAM, pero han sido más o menos 150 mb lo que ha subido la memoria del PC como se puede ver en las siguientes capturas. La CPU se ha ido más allá del 50% pero claro... estaba lanzando los hilos desde el mismo PC donde está el Tomcat... cuando tenga tiempo haré pruebas más serias, esto sólo es un vistazo rápido y pruebas para aprender a manejar el JMeter.


miércoles, diciembre 17, 2008

Nexus Comité

Aviso, este comentario es completamente subjetivo y publicitario:

No se cuantos de los que me leeis teneis la PS3, la Xbox o la Wii... y tampoco se cuantos de mis lectores vivís en Zaragoza, pero si cumplís las dos condiciones teneis que conocer esta web: www.nexuscomite.com. La web no está terminada pero pronto lo estará. Y digo que la teneis que conocer porque esta web corresponde a una nueva tienda que pronto se va a inagurar en medio del barrio de las Delicias en Zaragoza. En plena calle Unceta una nueva tienda se inagurará este fin de semana. No es una simple tienda de videojuegos, es mucho más. En cuanto abran os comentaré aquí todo el valor añadido que van a ofrecer a nuestra ciudad.

Por descontado que desde aquí os la recomiendo encarecidamente:
  • por sus precios
  • por el buen servicio y conocimientos de los dependientes
  • por el valor añadido
Pasaros por la C/Unceta 70 para comprar ese videojuego que quereis regalar estas navidades a vuestr@ novi@ / hij@ / prim@ / herman@ / familiar...

Nexus Comite, algo más que una tienda de videojuegos en Zaragoza.

martes, diciembre 16, 2008

Best Practices for Speeding Up Your Web Site

Lo que libremente viene a significar "Los mejores consejos para aumentar la velocidad de tu web". Vía un ex-compañero de trabajo (gracias Alvaro) me ha llegado el siguiente link de Yahoo! donde en una larga parrafada dan muchos consejos. Algunos todos los conocemos pero otros no son tan obvios o yo no los conocía.

lunes, diciembre 15, 2008

DVD, de Ciro Altabás

Hoy os traigo otro corto más del mismo director que el anterior, Ciro Altabás, en este caso es "DVD" un cortometraje que fue muy premiado. También he encontrado una entrevista al autor por si después de verlo quereís saber más sobre el corto o sobre el mismo.
Por último y antes de dejaros con el corto, una pregunta: la carátula tiene un aire a un comic que yo leía de pequeño y que iba en el suplemento de El Pais (porque entonces no llevaba la tilde) de los domingos. Era de un bicho grandote y marrón con cuernos amiguete de un chaval; no se si se llamaba Muz o como pero siempre he querido saber el título ¿alguien lo sabe? (¡Ya lo he descubierto!)
Y ahora... para todos los frikis, el corto:

viernes, diciembre 12, 2008

Manual Práctico del Amigo Imaginario

Hoy os traigo, vía un compañero de trabajo, un corto realmente bueno. No es una grabación de un par de amigos por pasar el rato sino algo profesional. Ya me contareis si os ha gustado, a mi mucho.

lunes, diciembre 08, 2008

Multicore: Profesionales e Industria

"Multicore: Profesionales e Industria" es el título de un artículo de dos páginas en la revista Sólo Programadores (Nº 164) escrito por José Antonio Álvarez Bermejo. Este hombre es profesor en la Universidad de Almería, pertenece al departamento de Arquitectura de Computadores.
Yo nunca había comprado esta revista, me parece cara (6€, cuando mucho de su contenido, o parecido, se puede adquirir gratis por internet), pero como estaba en la estación de autobuses de Granada a las 6:00 de la mañana y tenía que esperar a que mi novia viniera a buscarme (ella estaba en un congreso de enfermería donde ganó el premio a la mejor comunicación oral!) pués fuí al quiosco de la estación y me compré la revista y me puse a leer.
En aquel entonces, hace dos meses, sólo leí unas cuantas páginas que me resultaban, a priori, interesantes. Una sobre XPath y otra sobre XSLT. Hace un par de días volví a coger la revista que tenía tirada por encima de la cama y, comenzando a ojearla desde el final hasta el principio, me topé con un articulo que se titulaba igual que este post. Y me lo leí.
Al contrario de lo que parece no es un texto sobre la arquitectura de los nuevos microprocesadores; es un texto sobre como esta nueva arquitectura de varios nucleos puede afectar a la industria del desarrollo de software.
La mitad del artículo habla de como en los últimos años la arquitectura de los micros no han cambiado, únicamente subían de Mhz y listo. Esto hizo que los conocimientos sobre arquitectura fueran cada vez menos importantes hasta el punto de no ser considerados por algunos como necesarios ¿para que estudiar arquitectura de computadores si es algo que siempre es igual?. Pues no, ahora resulta que va y cambia, aunque algunos programadores no se han dado cuenta aún.
Una vez nos presenta el pasado y el presente del hardware nos habla del presente del desarrolo de software: el Ingeniero y el Experto Express. El primero es aquel que tiene una base sólida, adquirida principalmente en la universidad, y quizá no muy preparado en lo que la industria demanda. El segundo es todo lo contrario, alguien especializado y preparado en para solventar lo que actualmente la industria demanda. Un ejemplo sería un Ingeniero Infomático titulado y el segundo alguien sin carrera pero con un curso de 1 año en JEE (por ejemplo). Está claro quien de los dos empezará a sacar trabajo en un puesto estandar de los demandados en Infojobs: "se busca programador junior J2ee, se valora experiencia en Struts, no se necesitan estudios mínimos. 12.000 - 16.000 € brutos/año".
Y ahora viene lo que me ha resultado interesante del artículo, porque según augura este profesor: "Las arquitecturas multicore habrán supuesto una formalización en la separación entre ingenieros y otros profesionales. Es decir, habrá desarrolladores que implementan programas en paralelo sin saber realmente qué es lo que están haciendo porque otros desarrolladores más avanzados han creado marcos de portación o librerías que les pemitan abstraer los detalles de la computadora en igual forma que SQL abstrae los detalles del almacenamiento físico de los datos. Incluso entre ingenieros habrá una clara división entre aquellos con un fuerte perfil orientado a la arquitectura del procesador y el resto".
Y esto me ha hecho pensar cuantos programadores, ya sean Ingenieros o no, son conscientes de los efectos que tienen sus líneas de código sobre el hardware sobre el que se ejecutan. Cuantos de ellos saben realmente lo que supone hacer un "new". Estoy seguro de que los Ingenieros Informáticos entienden más que otros profesionales lo que están haciendo. De todo hay, por supuesto, pero creo que asignaturas como Arquitectura de computadores o Concurrencia y tiempo real sólo se imparten en las Ingenierías Informáticas.
Por último decir que este hombre como Ing. en Informática y trabajando para la Universidad puede estar "barriendo para su casa"... pero vamos, la idea base sobre la que reflexionar es completamente objetiva.

jueves, diciembre 04, 2008

El Firebug del iExplorer: Companion.JS

Debo empezar diciendo que no lo he probado; que no se lo estable que será ni lo potente. Dicho esto os presento a: Companion.JS. Según lo venden es un Firebug para iExplorer. No se hasta que punto será cierto porque dudo mucho que tenga la potencia del plug-in the Firefox pero está claro que una vez te acostumbras a Firebug cuando te toca probar la aplicación en iExplorer y te dan fallos javascript que en el navegador de Mozilla no dan te vuelves loco para solucionarlos, sólo entonces te das cuenta de lo fácil que es todo con Firefox+Firebug y de lo mucho que los echas de menos. Si esta herramienta es capaz de ayudarnos, pues bienvenida sea.

A continuación un screenshot en el que se aprecia un cierto aire al firebug:


Más allá del AJAX: Comet

Introducción:

Como todos los que esteis leyendo esto sabreis (porque los que no lo sepan el títulos les habrá disuadido de leer) HTTP es un protocolo sin estado donde un cliente (un navegador o browser) realiza peticiones contra un servidor y este le "contesta".
Gracias al objeto javascript XMLHttpRequest que implementan los navegadores más comunes (Firefox, iExplorer, Safari, Opera...) el navegador puede realizar peticiones de forma asincrona al servidor sin necesidad de hacer el clásico submit. Como en un inicio este tipo de peticiones eran contestada por el servidor mediante XML a esta técnica se le conoce como AJAX (hoy en día cada vez es más común usar JSON en lugar de XML).
Quizá para muchos es muy engorroso programar webs haciendo un uso exagerado de javascript pero el resultado es una web mucho más agradable al usuario. Para facilitarnos la vida existen cada vez más toolkits con los que hacer esto:
Bien, ahora ya podemos hacer webs como Gmail; nos ponemos manos a la obra y vemos que Gmail incorpora un pequeño chat mediante el cual podemos hablar con nuestros contactos que tengan abierto Gmail en ese momento o Gtalk ¿como hacemos eso nosotros con nuestro AJAX? ¿como podemos saber que alguien nos ha hablado? Pues como ya hemos dicho antes el HTTP (que no debemos olvidar que marca unas reglas básicas que no van a cambiar) consiste en que un cliente pide algo a un servidor y este le contesta. Pero en este caso lo que queremos es que sea el sevidor el que nos envie lo que otro usuario ha escrito en el chat... Tenemos un problema. Para solucionarlo con las herramientas que tenemos hasta este punto sólo hay una solución: la función javascript setTimeout(). Cada cierto tiempo periódico "preguntaremos" al servidor si tiene algo que decirnos. Creo que no tengo que decir que esto es un desperdicio de recursos y que da la sensación de ser una "ñapa". Pues puede ser, pero es la única forma... hasta la llegada de Comet.
En este punto debo hacer un inciso; el nombre de Comet fué acuñado por el creador de Dojo, Alex Russell, pero simultaneamente otros desarrolladores bautizaron la misma técnica con otros nombre: Server Push y Reverse AJAX. Estos tres nombres se refieren a la misma técnica, es decir, son sinónimos. Espero que el día de mañana una denominación triunfe sobre las otras ya que sino es un lio hablar con otro programador teniendo que dar los tres nombres por si este sólo se refiere con uno de ellos. Sigamos...
Comet al igual que AJAX no es un invento nuevo, como el bicarbonato :), sino una técnica de "engañar" al HTTP. Básicamente consiste en que el cliente se encargue de que siempre haya una conexión con el servidor y el servidor se encarga de "coger" la conexión y no soltarla hasta que tiene algo que decir al cliente ¿sencillo no?. Aquí el problema es más de rendimiento que de implementar. En el modelo actual de servidores (Tomcat, Jetty...) por cada petición que hace el browser se ejecuta un Thread en el servidor para responderla. Esto para una aplicación web al que se van a conectar 10 usuarios no supone un problema pero para una aplicación de 10.000 usuarios concurrentes pues nos tiraría el servidor.
Por suerte o por desgracia no somos los primeros en "inventarnos" esta técnica y tanto Tomcat como Jetty han implementado formas de solventar este problema mientras esperamos a la nueva especificación de los Servlets: la 3.0 (JSR-315).

Manos a la obra:

A continuación os muestro código de como implementar la técnica Comet en un servidor Tomcat. No es una aplicación completa, sólo pequeños pedazos con lo imprescindible.

Lo primero de todo es hacer que Tomcat use un Thread para cada Servlet en lugar de un Thead para cada petición. Tendremos que sustituir en el server.xml esta linea:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8084" protocol="HTTP/1.1" redirectPort="8443"/>

por esta otra:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8084" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>

Con este cambio hacemos que cuando al Tomcat le llegue una petición AJAX invoque el método:


public void event(CometEvent event) throws IOException, ServletException{}

en lugar del clásico doGet o doPost.

Como estareis pensando el siguiente cambio es en el Servlet. Ya no necesitamos los doGet y doPost y debemos hacer que el Servlet implemente la interfaz CometProcessor:


public class Cometa extends HttpServlet implements CometProcessor {}

Esto va cogiendo forma, tenemos la estructura sólo nos falta rellenar la parte javascript y el método Java. Empecemos por el javascript:


<script>
function peticionAjax(){
$.ajax({
url: 'http://localhost:8084/CometAbel/Cometa',
type: 'post',
data: { message: "enviando cosas al servidor..." },
beforeSend: function(oXhr){ oXhr.setRequestHeader('Connection', 'Keep-Alive'); },
success: function(data){
alert(data);
setTimeout('peticionAjax()', 1000);
}
});
}
</script>

Ese simple código javascript, que hace uso de jQuery, hace una llamada al servidor y cuando este le conteste mostrará un alert() con la respuesta. Acto seguido vuelve a abrir una conexión con el servidor para esperar la siguiente respuesta. Para enrevesar la cosa el cliente envia datos en el campo "data", en una aplicación normal podría mandar un código, identificardor...

Vale pues, ya tenemos casi todo pero eso era la fácil, vamos a la miga del asunto: el Servlet.

Para nuestro ejemplo usaremos dos variables dentro del Servlet. Una primera que almacenará todas las peticiones que le van llegando y otra que será un simple hilo que simulara estar haciendo el trabajo (las consultas en función de las cuales contestaremos a los navegadores):


// Array con las peticiones
protected ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>();
// Hilo que simula la tarea
protected MessageSender messageSender = null;

Vamos a implementar dos métodos del Servlet:

public void init() throws ServletException {
messageSender = new MessageSender();
Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}

public void destroy() {
connections.clear();
messageSender.stop();
messageSender = null;
}

Y ahora lo importante, el método event:

public void event(CometEvent event) throws IOException, ServletException {
// conseguimos la request y la response
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();

if (event.getEventType() == CometEvent.EventType.BEGIN) {
// si nos llega una nueva petición la "pillamos"
synchronized(connections) {
connections.add(response);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
// si ocurre un error desde el cliente "soltamos" la petición
synchronized(connections) {
connections.remove(response);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
// si la "conversación" ha terminado "soltamos" la petición
synchronized(connections) {
connections.remove(response);
}
PrintWriter writer = response.getWriter();
writer.println("['error']");
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
// si el cliente nos "envía" datos, los procesamos
InputStream is = request.getInputStream();
byte[] buf = new byte[512];
do {
int n = is.read(buf); //can throw an IOException
if (n > 0) {
System.out.println(new String(buf, 0, n));
} else if (n < 0) {
System.out.println("Este error no debería ocurrir.");
return;
}
} while (is.available() > > 0);
}
}

Bueno, pues ya está casi todo hecho. En estos momentos tenemos en el servidor un Array que almacena sin desbordarnos la memoria las conexiones. Cuando ocurra "algo": un evento, una consulta que realizamos a la Base de Datos cada cierto tiempo, etc... por lo que tengamos que avisar a los navegadores sólo tenemos que recorrer ese Array y enviarles la información. Un ejemplo un tanto inútil sería una clase que implemente Runnable con el siguiente código en el método run:


public void run() {
while (true) {
try {
Thread.sleep(9000);
} catch (InterruptedException ex) {
System.out.println("InterruptedException");
}
int algoImportanteHaOcurrido = 0;
// en lugar de ese 1 iría la llamada a la lógica de negocio
// que devolverá un código
algoImportanteHaOcurrido = 1;

if(algoImportanteHaOcurrido > 0){
synchronized (connections) {
for (HttpServletResponse connection : connections) {
try {
PrintWriter writer = connection.getWriter();
writer.println("Informo a los navegadores con este texto" + algoImportanteHaOcurrido;
writer.flush();
writer.close();
} catch (IOException e) {
System.out.println("IOException");
}
}
}
}
}
}

Y eso es todo. Con esto podreis ver más o menos en que consiste esa palabra rara que oireis cada vez más: Comet.

Apuntes finales:
  • No os olvideis los synchronized al acceder a los objetos compartidos, en este caso el Array de conexiones..
  • Si quereis saber más sobre NIO aquí teneis un tutorial en inglés.
  • Aquí encontrareis un ejemplo comet de IBM.
  • Y aquí la especificación de Tomcat para NIO.