
Monday April 24, 2006
He vuelto
Tras una larga temporada, vuelvo a retomar el weblog con las ganas e ilusiones de siempre. Han sido meses duros, sin mucho tiempo para aportar a la comunidad, enfrascado en trabajo y trabajo pero... bicho malo nunca muere y aqui estamos de nuevo.
En todo esto tiempo, me he dado cuenta de que la mayoria de mi navegacion transcurre entre paginas y proyectos personales como la de los amigos de El nido del Cuco, que consiguen generar contenido mas interesante y fresco que los productos preofesionales.
¿ Se esta convirtiendo Internet en ese medio democratico e ingobernable con el que todos soñamos ?. Yo desde luego he decidido volver a mi universo particular para asistir a esta revolucion silenciosa desde primera fila.
(2006-04-24 16:41:18.0)
Permalink

Thursday July 07, 2005
MADRID 2012... NO
No ha podido ser... y mira que lo siento. Por encima de centralismos, resquemores y envidias, Madrid es la ciudad de TODOS y TODAS. El unico sitio de España donde a nadie le importa un carajo de donde eres, como eres o lo que piensas.
A Madrid le hacian falta estos juegos, pero, sobre todo, a los madrileños. Nuestra ciudad crece sin sentido, sin planificacion ni infraestructuras. Muchos veiamos a los Juegos como la oportunidad de empezar a cambiar todo esto (alguien se acuerda de la Barcelona preolimpica).
Lo mas facil ahora es echar balones fuera, decir que todo es politica y que nos han "robado". Puede ser, pero no estaria de mas hacer una pequeña reflexion y autocritica. Madrid era, con diferencia, la candidatura con mayor apoyo popular si, pero eso no significa que fuera la que tuviera mayor implicacion. Hace poco inicie una timida campaña para impulsar el logo de MADRID 2012, al menos en nuestro reducto privado de jH... ¿ Que repercusion ha tenido ? ¿ Cuantos de vosotros pusisteis un misero logo en vuestro blog ?. ¿ Cuantos nos hicimos voluntarios ? ¿ Cuantos participamos activamente de las fiestas y actividades ?.
No creo que ni Londres, ni Paris lo hallan hecho mucho mejor pero, sabiendo el poder de los paises a los que pertencen, Madrid tendria que haberlo hecho muuuuuucho mejor.
Para la proxima vez. SEGURO. :)
(2005-07-07 15:57:12.0)
Permalink

Friday June 17, 2005
De Examenes
Tras un periodo de trabajo muy intenso entro en examenes en la UOC. No son muchos (Estadistica y Algebra) pero los suficientes como para robarme alguna (muchas) hora de sueño.
Este weblog, ademas de tecnologia, tambien puede contar algo personal de vez en cuando para los que se interesan por lo que hago.
(2005-06-17 08:35:59.0)
Permalink

Tuesday April 26, 2005
Crystal Reports XI y JAVA
Ya esta disponible Crystal Reports XI en español de los chicos de Business Objects. Esta herramienta no necesita presentacion. Todos sabemos que son los lideres en herramientas de reporting y que llegan donde desfallecen Jasper Reports y demas, los que no son tan conocidos son sus intentos por acercarse al mundo web.
Su primera aproximacion fue Crystal Enterprise X, una especie de "cataplasma" para Crystal Reports X que hacia de repositorio y front-end web de los informes generados en Crystal y tenia un motor que te generaba los mismos en DHTML, PDF, etc. No estaba mal, pero su arquitectura era un desastre, mezclando DLLs con JARs y lindezas por el estilo.
La sorpresa es que Crystal Enterprise desaparece como tal -a un año de su salida, ole tus huevos- y pasa a denominarse Crystal Reports XI Server. Esta informacion que facilito, sera util para los que ya trabajaban con estos sistemas y, como yo, desearan actualizarse y el cambio de nomenclatura les ha dejado un poco "descolocados".
Aun es pronto para evaluar que novedades -relativas al mundo JAVA- pueden aportar estas herramientas, pero, de momento, la instalacion de las aplicaciones WEB en un simple TOMCAT se ha simplificado notariamente. Supongo que las APIs para recuperar, programar, modificar y visualizar reports con JAVA tambien habran sido mejorados (ya desde la version X se permirte establecer como fuente de datos de un informe de Crystal una clase JAVA, por ejemplo).
Tambien es destacable que los licenciatarios de Crystal Enterprise Professional con soporte contratado no son actualizados al ya mencionado Crystal Reports XI Server sino a Business Objects Enterprise que, ademas de las funcionalidades de repositorio y front-end añade funcionalidades de Business Inteligence. Mención aparte merece el TORTUOSO PROCESO necesario para que te actualicen tus claves de licencia del anterior producto a este, pero eso merece ser contado en otro post.
Todos estos productos estan disponibles para descarga en la web de Business Objects asi que, si necesitais herramientas de reporting avanzado del tipo quiero un informe de ventas semanal que se realice automaticamente todos los lunes a las 9 de la mañana en formato PDF y se envie, tambien automaticamente, a n direcciones de correo ya sabeis de donde podeis tirar. Se integra con JAVA -aunque nadie haya dicho que sea facil- y... funciona !!!.
(2005-04-26 08:53:21.0)
Permalink

Monday April 04, 2005
¿ Bugcito en log4j ?
Yo, keko y muchos mas extendemos log4j para ampliarlo y adaptarlo a nuestras aplicaciones. En concreto, yo no utilizo el objeto Logger sino un objeto Log que extiende del mismo y facilita la gestion de push y pop del mismo entre otras muchas cosas.
Para poder utilizar tu propia clase extendida de Logger tienes que crear una clase que herede de LogFactory y, en concreto, sobreescribir el metodo makeNewLoggerInstance que devuelve un Logger para que devuelva una nueva instancia de tu objeto extendido. Despues, cuando quieres instanciar un objeto extendido de Logger, en vez de hacer el clasico Logger.getLogger(String) utilizas Logger.getLogger(String, LogFactory) donde LogFactory es tu factoria extendida.
Como veis, sencillo y elegante, sin embargo algo obscuro se esconde bajo la superficie ;).
Normalmente, cuando se instancia un log, se califica el mismo con el nombre de la clase en la que se instancia (Ej. Logger.getLogger("com.foo.Bar")) aunque se puede calificar "solo" con el nombre del paquete, o con lo que queramos ("pepino", "jarroncho", etc.).
Nosotros, ademas de extender log4j tenemos un pequeño "cache" de logs que guarda las distintas instancias de Logger por eso, solemos calificar por paquetes en vez de por clases, se crea una instancia por paquete en vez de por cada una de las clases que contienen. Y AQUI PUEDE APARECER EL PROBLEMA.
Si te instancias un objeto Logger, calificandolo con el mismo nombre de la categoria que has puesto en tu log4.properties, te sale una CascotazoDeLaMuerteException. Es decir, imaginemos que en nuestro log4j.properties tenemos una categoria tal que asi:
- log4j.logger.com.varma.util.database=DEBUG
Bien, cuando yo me instancio mi objeto que hereda de Logger (en mi caso Log) puedo hacer esto:
Log log = Log.getLog("com.varma.util.database.otropaquete");
o esto otro:
Log log = Log.getLog("com.varma.util.database.Miclase");
Pero como haga esto, la aplicacion se me muere;
Log log = Log.getLog("com.varma.util.database");
¿ Curioso ? ¿ Os ha pasado ?. La verdad es que me parece demasiado increible como para que sea cierto, seguiremos investigando.
(2005-04-04 13:22:17.0)
Permalink

Wednesday February 23, 2005
Madrid 2012
Madrid, mi ciudad, esta luchando por conseguir las olimpiadas del 2012 contra duros competidores como Londres, Paris, Moscu o Nueva York. Esta dificil, pero a lo mejor, con suerte y el apoyo de todos, consigamos traernos los juegos.
Quizas los juegos solo sirvan para enriquecer a unos pocos, para fomentar aun mas la burbuja inmoviliaria y colapsar los accesos a la ciudad pero, yo al menos, tengo la esperanza de que sean una oportunidad unica para hacer mas vivible y confortable esta ciudad que es el espacio comun de todos.
Como ciudadanos anonimos, poco podemos hacer, pero, me gustaria que, al menos, pongamos el logo de nuestra candidatura en nuestras webs para hacerla todo lo visible que podamos. Si quieres apoyar la candidatura, partidismos y sectarismos estupidos aparte, pon alguno de estos logos en tu web.
Ah... y muchas gracias por adelantado :) .
(2005-02-23 15:22:28.0)
Permalink
¡¡¡ Nieve !!!!
Hoy Madrid se ha levantado cubierta de nieve. No es que hayamos llegado a niveles polares pero, habia una buena capa de 5 o 6 centimetros cubriendolo todo. ¡ Que bonito ! ¡ Que alboroto ! ¡ Otro perrito piloto !. El caso es que, una vez mas, al primer contratiempo metereologico toda la ciudad se ha colapsado.
Son las 10 menos cuarto y la mayoria de la gente aun no ha llegado a trabajar. Yo me libro porque trabajo fuera de la ciudad y vivo en un borde de la misma. Si no fuera asi, a lo mejor estaba atrapado detras de un camion en la M-40.
Creo que todo esto nos deberia hacer reflexionar. Basta ya de PAUs, de actuaciones urbanas, de torres del Real Madrid, de urbanizaciones gigantescas y recalificaciones de terrenos sin planificar accesos, carreteras, servicios, etc. Si seguimos asi, esto seguira siendo una republica bananera, por mucho Madrid 2012 ...
(2005-02-23 09:42:14.0)
Permalink

Monday February 07, 2005
Pasando de Struts 1.0.X a 1.1 y no morir en el intento.
Hace poco quise hacer unos retoques en una utilityde mi proyecto relacionada con la gestion de errores. Basicamente, queria utilizar los mensajes de error con parametros que proporciona el framework Struts y su clase ActionError, para que admitiera mensajes con un numero ilimitado de parametros.
El caso es que la version de Struts con la que trabajamos era la version 1.0.2 y, en esta version, la API de Struts te da la posibilidad de trabajar con 1,2,3 y 4 parametros pero no mas asi que... ¡Que mejor que esta ocasion para actualizarse!. Craso Error.
A los actualizadores compulsivos, a los que nunca leen las Release Notes (como yo) y a los echaos p'alante... ¡¡¡ QUIETORRRL !!!. La actualizacion no es tan sencilla como actualizar un jar por otro y puede ser bastante traumatica.
Espero que esta enumeracion de "chinitas" pueda servirle a alguien que tenga que pasar por tan traumatica experiencia:
¿ Donde esta mi jar y quien es esa gente ?
¿ Te esperas un struts.jar sencillo y facilito ? Ayyyy alma candida... a partir de la version 1.1, los de JAKARTA decidieron que habia mucho (pero mucho) utilizable dentro de Struts y ademas utilizado por muchos de sus otros proyectos. Para limitar la dependencia de estos de Struts se sacaron un conjunto de librerias de utilidades del "antiguo" Struts. Habian nacido las librerias Jakarta Commons.
Asi que, ademas de el jar de Struts ya os estais descargando e importando todas estas porque, sino, Struts no os va ni a compilar. Es como las lentejas. Si quieres lo tomas y, si no, lo dejas.
Struts es mio y depreco lo que me sale de los c******
Pues si. Y eso ha debido pensar algun guru de JAKARTA... "y lo que no quiero deprecar pero me molesta lo elimino" ... y living la vida loca. Asi que, si habeis hecho un uso mas o menos exhaustivo de Struts ya os podeis preparar para sustituir y rebuscar por la API hasta que deis con algo parecido.
Tu DataSource te lo picas tu.
Antes Struts daba soporte a un conjunto de utilidades para el acceso a Base de Datos. Ahora ya no. Y, como dicen las feministas, NO MEANS NO. No esta deprecado, ni desactualizado, ni desfasado... simplemente NO esta. Lo han quitado por si te entran tentaciones de seguir utilizandolo. En concreto, nosotros hutilizabamos el GenericDataSource y la clasecita, una vez extendida y retocada nos ha dado mucho juego. Afortunadamente, la implementacion de la misma es monolitica y hereda de javax.sql.Datasource y poco mas asi que, si lo deseais, podeis meter la clase directamente en vuestro CLASSPATH y se soluciono el problema.
LOG4J utilizaste... la cagaste
Y esto es lo mejor... Struts deja de funcionar porque no se loga bien con... ¡ tu log4j !. Si amigos, es lo bueno de utilizar la libreria Commons Logging que como encuentre log4j en tu CLASSPATH va y lo utiliza, y claro... tu que tenias tu log4j bien configurado mediante tu properties en un directorio fuera de tu CLASSPATH (porque claro, tus properties los quieres dejar fuera de un supuesto y futuro .war para que puedan ser modificados en caliente) y te curras tu Factoria de Logs que trinca el properties con un configureAndWatch y te has montado el invento del siglo y... ahora resulta que viene Struts, que se carga antes que tu aplicacion y UTILIZA PORQUE SI el log4j y... este todavia no se ha configurado y CASCOTAZO. Asi que, o te pones a hacer reingenieria inversa y averiguas como arreglas el embolao o te das cuenta de que tienes que meter el log4j en el CLASSPATH para que Struts sencillamente cargue. En dos palabras: IN-CREIBLE.
Como conclusion, que cambiar de Struts 1.0.X a 1.1 puede ser bueno pero, desde luego, ni bonito ni barato. Aun con todo, es una decision muy a tomar en cuenta porque la version 1.1 ha sido la gran revolucion a nivel de Struts y, una vez migrado a esta, no hay coste para cambiar a versiones posteriores como la 1.2. No, no me arrepiento de todo el embolao al que me han arrastrado pero, la verdad, siendo Struts un framework tan extensamente utilizado, el cambio de version me ha parecido chapuceril, agresivo y complicado. Quizas todo sea culpa mia, quizas era mi obligacion estar al tanto de todo lo que suponia cambiar de version pero, la verdad, los diseñadores de JAKARTA me tenian muy bien acostumbrado. De momento yo, con la version 1.1 voy a aguantar tooooodo lo que pueda.
(2005-02-07 21:00:45.0)
Permalink
MENUDO PLANCHAZO
Sin comentarios. Adivinar quien es el Jefe de Nacho ;)
(2005-02-07 18:44:54.0)
Permalink

Tuesday January 11, 2005
Recursividad en Schemas XML
Los schemas XML se han convertido en una herramienta de desarrollo
imprescindible. No solo se utilizan para validar XML sino que, bien
estructuradas y documentadas, sirven para comprender en un solo vistazo
funcionalidades y/o modulos enteros.
Al definir nuestros schemas, podemos encontrarnos con la necesidad de definir una recursividad que se puede producir en nuestros XML. Por ejemplo, imaginemos un Departamento de una empresa que, a su vez, esta compuesto de n Departamentos y estos de otros a su vez hasta el infinito. ¿Como podemos definir esto en un schema?.
A continuacion se muestra un sencillo ejemplo.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="empresa">
<xs:annotation>
<xs:documentation>Comment
describing your root element</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="nombre" type="xs:string"/>
<xs:element
name="departamentos" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element
name="departamento" type="departamento" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="departamento">
<xs:sequence>
<xs:element name="nombre" type="xs:string"/>
<xs:element name="numeroTrabajadores" type="xs:int"/>
<xs:element name="subdepartamentos" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element
name="departamento" type="departamento" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
Si os fijais en el anterior schema, podreis observar que ademas del nodo raiz del schema, llamado empresa, esta definido otro elemento a parte denominado departamento.
<xs:complexType name="departamento">
<xs:sequence>
<xs:element name="nombre" type="xs:string"/>
<xs:element name="numeroTrabajadores" type="xs:int"/>
<xs:element name="subdepartamentos" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element
name="departamento" type="departamento" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
Una vez definido este elemento complejo podemos utilizarlo tantas veces como queramos dentro de la definicion del elemento/nodo principal asi como dentro de si mismo lo unico que hay que hacer es, al definir un elemento dentro de otro, especificar que es de tipo departamento.
Ej.
<xs:sequence>
<xs:element
name="departamento" type="departamento" maxOccurs="unbounded"/>
</xs:sequence>
Quizas entendais mejor el concepto teniendo una representacion visual de este schema.
Con esta representacion visual, es facil entender como este esquema representa recursividad a nivel de departamento. Si validarais un XML contra schema, observarias como el nivel de la recursividad es ilimitado.
(2005-01-11 09:02:29.0)
Permalink

Thursday December 23, 2004
Feliz Navidad
A todos los amigos y a los enemigos. A lo que os conozco y a los que no. Os deseo, de verdad....
¡¡¡¡ FELIZ NAVIDAD !!!!
(2004-12-23 18:47:45.0)
Permalink

Thursday December 16, 2004
FIREFOX, el triunfo de todos
El navegador OpenSource Firefox se ha anunciado a doble pagina en el periodico mas influyente del mundo, el New York Times. Lo sorprendente es que, este anuncio, no forma parte de una costosa camapaña de Marketing que grabe el precio de un producto sino que ha sido financiado por donaciones voluntarias de los usuarios del navegador.
Firefox es un producto de calidad, sencillo y elegante y esta consiguiendo lo que no pudieron hacer ni Opera ni Netscape: quitarle cuota de mercado a Microsoft Explorer. Una muestra de que, hacer las cosas bien es posible.
La competencia es sana y mas, si como en este caso, lo que se oferta es gratis y de mas calidad que productos de pago. Hoy es un buen dia para todos.
(2004-12-16 13:08:13.0)
Permalink

Monday November 15, 2004
Orejas Rojas
Hace siglos que no posteo. Tengo 3 noticias sin publicar pero, no encuentro el tiempo para poder darles el minimo de calidad que merece quien visita esta pagina perdida en la Red.
Entre todo esto, el cambio a la nueva version del Roller, una practica de Ensamblador, montar un par de muebles de IKEA, hacer test para el carnet de conducir y, sobre todo, convencer a mi novia de que no me abandone por el poco tiempo que le dedico.
Tampoco he visto mucho movimiento en los weblogs supongo que, al igual que yo, algunos estais pasando por un "Red Ears Period".
¿ Y que es eso de "Red Ears Period", "Periodo de Orejas Rojas" o simplemente "REP" ?. Bueno, para aquellos que no lo conozcais (aun estareis estudiando, o acabareis de empezar en la industria o, simplemente, sereis Consultores) intentare explicaroslo.
Un Periodo de Orejas Rojas se produce cuando tienes una carga brutal de trabajo, aderezado con algun compromiso externo (vease estudios y/o familia) y completado con un monton de marrones que no puedes controlar. El REP es facilmente identificable. Puedes asegurar que lo estas pasando si tienes los siguientes sintomas:
- El icono de "Mensajes Nuevos sin leer" del Outlook esta ahi, durante todo el dia y NO desaparece.
- Tienes 4 o 5 pantallas de Messenger con avisos intermitentes de mensajes de tu Madre, tu colega de Burgos y el hermano de tu novia.
- Cuando te dignas a mirar la Bandeja de Entrada del Outlook (vease punto 1) para que no te moleste el iconito, borras sin abrir los correos que te mandan tus amigotes con ficheros adjuntos y titulos como "La Concejala del PP de Caceres en bolas".
- Cuando te dignas a ver lo que te pone tu novia en el Messenger (vease punto 2) y ella te escribe algo en plan "Churriiiii... estoy superenamorada de ti. Eres el hombre de mi vida y quiero estar contigo siempre. Te echo de menos.", tu contestas con un concreto "y yo" acompañado de algun absurdo emoticono.
- Tus compañeros de proyecto te piden que sueltes algo del CVS con post-it en la mesa, mensajes del Messenger o correos.
- No lees jH, ni posteas en tu weblog, ni visitas tu pagina de fisica cuantica favorita.
- No sabes -ni te importa- lo que ha hecho el Atleti el fin de semana pasado.
- No te apuntas al cafe de las 8 y media, ni al de las 12, de hecho, olvidas el sabor del cafe.
- No te apetece afeitarte NUNCA.
- Programas y programas, pero, siempre parece poco.
- Las orejas se te ponen rojas, muy muy rojas.
Hay muchos mas sintomas conocidos pero con estos podras identificar si has entrado en modo REP. Es mas, cuando estas con las Orejas Rojas tus relaciones interpersonales se ven afectadas. Por ejemplo, estos son ejemplos de diferencias entre conversaciones en "Modo Normal" y "Modo REP":
Modo Normal
----------------
- No entiendo porque el flujo del programa dirige la salida a un frame oculto en vez de lanzarlo sobre un frame principal.
- Porque en el caso de que se produzca un error, el frame oculto levantara un popup identificativo, si lo lanzaramos en el frame principal el usuario no podria repetir la accion o volver atras.
Modo REP
------------
- No entiendo porque el flujo del programa dirige la salida a un frame oculto en vez de lanzarlo sobre un frame principal.
- Aha.
En mi caso, ya que no trabajo en EA, las orejas no se me ponen rojas por trabajar 12 horas al dia 7 dias a la semana sino por realizar pruebas y pruebas sobre algo supuestamente probado y absurdamente inconcluso.
El caso es que no es una tarea "orejarojeadora": parchear y solucionar fallos, como si encajaras piezas de un puzle mientras optimizas codigo pero, cuando tu proyecto lleva 1 año de retraso (¿solo 1 año? :) ) se te empiezan a poner las orejas a 50 grados centigrados, y dejas de contestar el Messenger, y no lees los correos, y no visitas jH y no posteas en tu weblog... .
(2004-11-15 21:11:07.0)
Permalink

Wednesday October 13, 2004
ADSL Wars
Parece que esto se mueve !!!. Jazztel con 1MB, ya.com reventando el mercado y servidores.com ofreciendo una linea de 1.2MB para gamers. Y a todo esto, las operadoras ofreciendo fast-path en los ADSL en un "futuro cercano".
Ante esta avalancha... ¿ Que hacer ?. Despues de las malas experiencias que nos han proporcionado a casi todos los distintos ISPs, la actitud de la mayoria es quedarse a la espectativa "a ver que pasa".
Con un punto de inconsciencia (o tambien podeis llamarlo locura) me he decidido por darme de alta en OpenForYou que es una marca comercial de IBERCOM. Despues de leer y leer por los foros, parece que, el mayor problema de este ISP es que se esta retrasando mucho en dar de alta las lineas pero, la verdad, yo creo que esto es mas cuestion de Telefonica que de ellos mismos.
El hecho de que mi linea pertenezca a esta ultima empresa y la grima que esto me da tambien me espolea y me anima para realizar el cambio.
OpenForYou ofrece ADSL 1024/300 por 38 eurazos + IVA siempre que estes en una "Zona Caliente" (Donde su red propia da cobertura). No te exige un minimo de permanencia con ellos y no te cobran hasta que consigan darte de alta. Lo malo (que siempre hay algo malo) es que te piden que pagues 39.95 euros en concepto de alta.
A lo mejor me pego una ostia pero creo que voy a intentarlo. Yo os animo al cambio, a Jazztel, a Wanadoo o a donde sea... pero empezar a animar el mercado para que las telcos empiecen a moverse mas y mas.
(2004-10-13 20:46:06.0)
Permalink

Monday October 11, 2004
Clases de Cocina: Barra de Progreso JAVA
Muchas veces, todos hemos deseado utilizar una Barra de Progreso para monitorizar el progreso de determinadas tareas en nuestras aplicaciones WEB. Poco a poco, vamos creando procesos mas y mas complejos (y mas y mas pesados) en nuestras aplicaciones y, la verdad, cuando el Front-End de las mismas esta basado en un navegador, tener a un usuario esperando 2,5 o 10 minutos sin indicarle QUE esta pasando no da muy buena sensacion.
A continuacion, voy a plantear una implementacion, sencilla y elegante, de una barra de progreso basada en navegador WEB y un simple mecanismo para ir marcando el progreso de una tarea que reflejara dicha barra. Como el post va para largo, lo he escrito a lo Arguiñano, asi espero que os sea mas amena su lectura. Yo, desde luego, me he divertido escribiendolo.
Hoy vamos a explicar como un implementar, en una aplicacion web JAVA, una barra de progreso rica, rica y con fundamento.
Hay muchas maneras de realizar este plato y, por supuesto, cada uno de vosotros le podeis dar vuestro propio toque personal.
Yo os voy a explicar como la cocino yo, tal y como me la enseño mi madre.
Para cocinar la Barra necesitaremos los siguientes ingredientes:
- 1 Servlet bien fresco
- 150gr de JavaScript
- 1 par de clases de Java ligeras y esponjosas
- Salsa tipo "Patron Commando" para aderezar
Empezaremos por picar muy fino las classes Java. A estas clases JAVA yo les echo "Patron Commando" para que queden mas agradables al gusto.
El patron Commando, bien utilizado -como diria el Chef Albert du Vilch-, puede ser muy util combinado con el patron factoria para cambiar el funcionamiento de toda una aplicacion a golpe de Property, sin embargo, no es este hilo el lugar mas apropiado para que hablemos de el. Podeis conseguir mas informacion, por ejemplo, aqui.
Nos creamos una interfaz que implementara el Patron Commando. Esta interfaz servira para definir los metodos que necesitemos para marcar el progreso de una tarea a traves de nuestro codigo:
public interface ProgressBox {
String task = null;
/**
* Devuelve la tarea que se esta monitorizando.
* @return String el ID de la tarea
*/
public String getTask();
/**
* Establece el porcentaje de finalizacion de una tarea.
* @param percentage double el porcentaje de finalizacion de la tarea
*/
public void setProgress(double percentage);
}
|
Por supuesto, si se desea, se le puede añadir a esta clase un monton de "especias" que realcen el sabor y, asi, podemos definir metodos que calculen el progreso de una tarea en base a un numero de iteracion dentro de un bucle u otro que lance un mensaje (para trasmitir un mensaje de error, por ejemplo, en vez de un porcentaje). Esto se deja a vuestro buen criterio.
Una vez que tenemos la interfaz bien picadita, vamos a empezar a amasar una clase JAVA que la implemente.
Lo bueno del patron Commando es que te permite hacer llamadas a procedimientos sin saber que es lo que realmente estas haciendo. Asi, podemos crear una clase que implemente la Interfaz y que guarde el progreso de una tarea como cada uno desee (HTTPSession, Base de Datos, Property, etc.).
Yo voy a "amasar" una clase que guardara el progreso de una tarea en una Session HTTP. Gracias a la interfaz que he definido previamente, podre distribuir este objeto por toda mi aplicacion, evitando tener que pasar como parametro el objeto Session, lo que supondria cepillarme cualquier logica de diseño en capas que puediera tener. A ver que os parece:
public class SessionProgressBox implements ProgressBox {
public static final String SESSION_PROGRESS_KEY = "task.progress.";
private HttpSession session = null;
private String task = null;
/**
* El constructor necesita una HTTPSession
* @param session HttpSession
* @param task String el ID de la tarea a controlar
*/
public SessionProgressBox(HttpSession session, String task) {
this.session = session;
this.task = task;
}
public void setProgress(double percentage) {
this.session.setAttribute(SESSION_PROGRESS_KEY + this.task, new Double(percentage));
}
public String getTask() {
return task;
}
}
|
Una vez tenemos nuestra interfaz y nuestra clase, las salpimentamos y las reservamos, para utilizarlas posteriormente.
Vamos a pasar a la parte mas dificil del plato: cocinar el Servlet. El Servlet de control de progreso es la parte mas importante a realizar puesto que el generara el codigo HTML y JavaScript que pintara la barra de progreso y seguira monitorizando el progreso.
Os presento un Servlet sencillito pero, eso si hecho de muy buena materia prima. No produce codigo compatible con Explorer y Netscape, solo con el primero pero, he preferido cocinarlo asi en aras de la claridad, para mejorar el entendimiento. Seguro que si alguien necesita compatibilidad doble sabra como dar su toque personal al plato.
public class ProgressServlet extends HttpServlet {
// Declaracion de variables
private static final String CONTENT_TYPE = "text/html";
private String millis2refresh = null;
private String millis2close = null;
/**
* Inicializacion de variables globales
* @throws ServletException
*/
public void init() throws ServletException {
millis2refresh = getServletConfig().getInitParameter("millis2refresh");
if (mil lis2refresh == null) {
millis2refresh = "1500";
}
millis2close = getServletConfig().getInitParameter("millis2close");
if (millis2close == null) {
millis2close = "2000";
}
}
/**
* Proceso de una peticion HTTP de tipo GET
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
try {
// Se recuperan las variables del REQUEST
String idProceso = request.getParameter("idProceso");
String keyProgress = SessionProgressBox.SESSION_PROGRESS_KEY +
idProceso;
// Se recuperan variables de SESSION
Double progreso = (Double) request.getSession().getAttribute(
keyProgress);
if (progreso == null) {
progreso = new Double(0);
}
// Se compone la pagina web dinamicamente
out.println("< html >");
out.println("< head >");
out.println("< title >ProgressServlet< /title >");
out.println("< style >");
out.println(
"#fondobarra{position:absolute;left:100px;top:20px;background-color:#B7C3D0;}");
out.println(
"#barra{position:absolute;left:100px;top:20px;background-color:#3D59AB;}");
out.println("< /style >");
out.println("< /head >");
out.println("< body bgcolor=\"#ffffff\" >");
out.println(
"< div id=\"fondobarra\" style=\"width:100px;height:10px;z-index:9;\" >< /div >");
out.println(
"< div id=\"barra\" style=\"width:" + progreso +
"px;height:10px;z-index:10\" >< /div >");
out.println("< form action=\""+request.getContextPath()+"/progressservlet\" method=\"post\" >");
out.println("< input type=\"hidden\" name=\"progreso\" value=\"" +
progreso + "\"/ >");
out.println("< input type=\"hidden\" name=\"idProceso\" value=\"" +
idProceso + "\"/ >");
out.println("< br >");
out.println("< br >");
out.println(
"< p align=\"center\" >Completado un " +
progreso +
"% del proceso ...< /p >");
out.println("< /form >");
out.println("< /body >");
out.println("< script >");
out.println("if(document.forms[0].progreso.value < 100){");
out.println("setTimeout(\"document.forms[0].submit()\", " +
millis2refresh + ")");
out.println("}");
out.println("else{");
out.println("setTimeout(\"window.close()\", " + millis2close +
")");
out.println("}");
out.println("< /script >");
out.println("< /html >");
} catch (Exception ex) {
out.println("< html >");
out.println("< head >");
out.println("< title >ProgressServlet< /title >");
out.println("< /head >");
out.println("< body bgcolor=\"#ffffff\" >");
out.println("< br >");
out.println(
"< p align=\"center\" >Error al intentar monitorizar el progreso de una tarea: " +
ex+"< /p >");
out.println("< /body >");
out.println("< /html >");
}
}
|
Como podeis apreciar, es un Servlet bien sencillo, con no mucha complejidad. Pinta una barra de progreso utilizando capas (es decir, no viajan imagenes, la "pagina" generada apenas ocupa unos bytes con lo cual la percepcion de refresco, cada vez que va a consultar a servidor el progreso de una tarea, es imperceptible). Tambien escribe el codigo JavaScript necesario para que vuelva a lanzar una peticion al servidor en n milisegundos -los que le hayamos indicado en el Servlet- si el progreso es menor del 100% o que cerrara la ventana en caso contario.
El Servlet escribe el codigo HTML y JavaScript que deseis asi que, ya sabeis, si deseais darle un toque personal... a la sarten y vuelta y vuelta. Es mas, la unica concesion a las delicatessen son las dos variables de inicializacion del Servlet que indican en la configuracion del Servlet en descriptorescada cuantos milisegundos se refrescara el progreso de una tarea y cuantos segundos tardara en cerrarse la ventana una vez que se ha cumplido el 100% (variables millis2refresh y millis2close respectivamente).
He tenido que toquetar el codigo del Servlet para que el post quedara escrito para copiar y pegar (en concreto he tenido que poner un espacio al principio y al final de cada etiqueta HTML para que el weblog no se volviera loco) asi que, si encontrais algun problema en el mismo o algo que no entendais, ya sabeis donde encontrarme.
Una vez que tenemos el Servlet en el plato, procederemos a adornarlo con unas lineas de descriptor. En concreto las siguientes, que debeis colocar en el descriptor web.xml:
< servlet >
< servlet-name >progressservlet< /servlet-name>
< servlet-class >
 [escribir aqui el paquetizado de vuestro servlet Ej. com.test.].ProgressServlet
< /servlet-class >
< init-param>
< param-name >millis2refresh< /param-name >
< param-value >2000< /param-value >
< /init-param >
< init-param>
< param-name >millis2close< /param-name >
< param-value >3000< /param-value >
< /init-param >
< /servlet >
< servlet-mapping >
< servlet-name >progressservlet< /servlet-name >
< url-pattern >/progressservlet< /url-pattern >
< /servlet-mapping >
|
Mmmmm... ¡Que bien huele esto! ¡Ya lo tenemos casi listo!. Un poquito mas y el plato estara cocinado.
Ya hemos montado la estructura que monitorizara el progreso de una tarea ahora vamos a integrarlo con nuestra aplicacion web.
Nos vamos a la pagina web desde donde se lanzara nuestra aplicacion. Alli, dentro de un formulario tendremos seguro un campo del formulario de tipo submit, un campo de tipo button con un evento onclick controlado o algo similar. Bien, lo que tenemos que hacer es, antes de invocar el submit del formulario, llamar a la siguiente funcion:
function barraProgreso(idProceso)
{
window.open('<%=request.getContextPath()%>/progressservlet?idProceso='+idProceso, 'BarraProgreso', 'width=300, height=100, left=500, top=200, resizable=no, scrollbars=no');
}
|
Si os dais cuenta, esta funcion solo recibe un parametro que es un IDENTIFICATIVO UNICO de la tarea que quereis monitorizar. Lo ideal es que copieis esta funcion (y todas las funciones de JavaScript que utiliceis de manera general en toda vuestra aplicacion) en un fichero .js para poder importarlo en todas las paginas en donde haga falta en vez de copiar una y otra vez la misma funcion en todas las paginas.
Bien, el caso es que, lo hayais metido en un fichero .js o lo hayais copiado directamente en la pagina, ya podeis invocar a la funcion. Asi, por ejemplo:
< input type="button" value="Aceptar" onclick="barraProgreso(5);document.forms[0].submit()" />
|
E VOILA !!!. Una nueva ventana se abrira mostrando la barra de progreso en este caso, de la tarea "5".
Ahora solo falta marcar el porcentaje de ese progreso segun se van cumpliendo hitos de la tarea a monitorizar. Si no lo hicieramos, la barra no se moveria del 0% y la ventana que la contiene nunca se cerraria.
Vamos a mostrar, como podriamos ir indicando en nuestro codigo el progreso de nuestra tarea (como ejemplo pongo el metodo doGet de un Servlet aunque se podria hacer lo mismo en un doPost, el perform de Struts, etc...):
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
SessionProgressBox box = new SessionProgressBox(request.getSession(), "5");
System.out.println("¡ Hola Don Pepito !");
box.setProgress(10);
System.out.println("¡ Hola Don Jose !");
box.setProgress(20.5);
System.out.println("Pasaba por su casa.");
box.setProgress(40);
System.out.println("Por mi casa pasa usted.");
box.setProgress(60);
System.out.println("¡ Adios Don Pepito !");
box.setProgress(80.5);
System.out.println("¡ Adios Don Jose !");
box.setProgress(100);
}
|
Asi podeis ver como he marcado progresos del 10, 20.5, 40, 60, 80.5 y 100% en mi tarea "5".
Bueno, bueno, bueno... pues ya esta el plato listo y nos ha salido... ¡ riquisimo !. Para chuparnos los dedos.
Por supuesto, que esto son solo unas directrices, cada uno podeis y debeis cocinar como mas os guste. De hecho, este plato es una version muy simplificada de la que he cocinado en mi "Resturante". Ya sabeis que el objeto SessionProgressBox, o cualquier otra implementacion de la interfaz ProgressBox, podeis propagarla por toda vuestra aplicacion.
A veces podeis monitorizar un metodo que sea llamado por dos tareas y que en cada uno de ellas, la consecucion de un determinado hito suponga un porcentaje de progreso diferente... no problemo !!!. Para eso ProgressBox tiene el utilisimo metodo getTask() que te indica la tarea que se esta monitorizando. Asi podeis, por ejemplo asignar en un hito porcentajes de consecucion distintos para la tarea "pepino" y la tarea "melon":
if(box != null && "pepino".equals(box.getTask()) {
box.setProgress(15);
}
else if(box != null && "melon".equals(box.getTask()) {
box.setProgress(87.5);
}
|
Asi, habeis visto, pasando por el mismo hito le hemos asignado un 15% de progreso a la tarea "pepino" y un 87.5% a la tarea "melon". Tambien es importante que os deis cuenta que, ademas de averiguar en que tarea esta, se ha preguntado primero si el objeto ProgressBox es nulo esto es importante por lo mismo que hemos hablado antes, a lo mejor ese hito que esta dentro de un metodo, se llama desde un primer metodo que no monitoriza el progreso de ninguna tarea y pasa el objeto ProgressBox a nulo.
Bueno... pues ya esta, espero que, por la longitud de este post, no haya cometido muchos errores (mucho del codigo lo escribo de cabeza) y que NO TODOS OS HAYAIS DORMIDO. Si el post tiene aceptacion, poco a poco ire escribiendo mas clases de cocina. Ya sabeis...
RICO, RICO... Y CON FUNDAMENTO
(2004-10-11 14:13:31.0)
Permalink
|
|
| Archivos |
|
|
| « October 2008 | | Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|
| | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | | | | | | | | | Hoy |
|
|
|
| Busca en el weblog |
|
|
|
|
|
|
| Navegacion |
|
|
|
|
|
|
|
| De donde venis |
|
|
|
Las visitas de hoy a la página: 190
|
|
|
|
|
|