
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
URL de la referencia: http://weblogs.javahispano.org/dbonillaf/entry/clases_de_cocina_1_barra
|
|
| Archivos |
|
|
| « July 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: 25
|
|
|
|
|
|
Muy bueno, e instructivo.
Gracias.
Enviado por Tx en October 11, 2004 a las 10:36 AM EDT #
Ummmm.. tu quieres hipnotizarnos. Sube ek tamaño de letra del código, por favor. <br><br>
El post esta interesante, por lo menos a mi me gusta que haya cosas técnicas que leer de en cuando en un blog. <br><br>
PS: Por cierto que pasa con la entrevista "real programmers" de este mes ;)
Enviado por Akuma en October 11, 2004 a las 04:54 PM EDT #
La verdad <strong>Akuma</strong> es que la letra del codigo es la que poner el JRoller con la etiqueta HTML < code >.
<br>
<br>
Pues si, la verdad es que en estos weblogs de jH yo creo que, sobre todo, tiene que haber post tecnicos. Si te das cuenta, en mi weblog los post tecnicos son mayoria.
<br>
Si quisiera un weblog para hablar de mi vida, no creo que lo hubiese colgado en javahispano ;).
<br>
<br>
Respecto a la entrevista de Real Programmers... no te preocupes, dentro de poco habra otra entrega.
Enviado por David Bonilla en October 11, 2004 a las 05:05 PM EDT #
Muy interesante, sí señor. Sólo una observación: ¿no queda muy guarro tanto HTML en un servlet? (pregunta pretenciosa, es obvio que queda guarro, pero es para ver si has pensado en alguna alternativa :P)
Enviado por mariscal en October 13, 2004 a las 05:20 AM EDT #
Pues si... mas que "guarro", en el momento en que escribes HTML un poco "complicado", capas, hojas de estilo y demas te puedes morir poniendolo en un Servlet pero...
<br>
<br>
Teniendo en cuenta que esto es una generalidad y tiene que ser sencillo, reutilizable y, sobre todo, <strong>retocable</strong> he decidido ponerlo en un Servlet.
<br>
¿ Por que ? Pues muy sencillo, porque si alguien quiere pasar el codigo a una JSP seria muuuuuy facil hacerlo pero, ¿ Y si alguien quiere utilizar el output del servlet para ir escribiendo en la JSP <u>sin que haya refresco</u> hasta hacer un flush al final de proceso ?.
<br>
No es que me guste mucho pero, hay gente que lo hace, aunque la verdad, con los pocos bytes que ocupa la pagina el refresco es imperceptible.
<br>
¿ Tu que opinas ?
Enviado por David Bonilla en October 13, 2004 a las 06:07 AM EDT #
Ummmmm...... no podría dar problemas el que SessionProgressBox tenga una referencia a la session ?¿? De esta forma,siempre hay una referencia a la session y esa session nunca caduca ni es cepillada por el GarbageCollector... no sería mejor usar una WeakReference o algo de eso ?¿?¿
Enviado por bumba en October 13, 2004 a las 09:51 AM EDT #
Bueno, ya que estoy ..... también lo que haría sería que la interfaz ProgressBox, ya que te dá el método setProgress para especificiar el nivel de progreso, te oferte el método getProgress, para obtener el progreso de la barra y encapsular así la lógica necesaria para obtener el progreso de sabe Dios donde (session, properties, BBDD como tu dices.... ). Así, el servlet que pones de ejemplo no tendría que hacer nada más que instanciar un objeto SessionProgressBox, hacer un setTask con la task que obtiene de la request y luego hacer un getProgress() sobre ese objeto, sin saber nada de sesiones ni ná de ná; es decir, ya que es su responsabilidad meter en session (en este caso), es su responsabilidad sacar de session.
También prodrías hacer que los objetos SessionProgressBox tuviesen el atributo progress inicializado a Double(0). Así te ahorras comprobaciones para detectar que no sea nulo ese atributo y es menos engorroso.
Qué te parece ?¿ Saludos.
Enviado por bumba en October 13, 2004 a las 10:08 AM EDT #
Jarl ¿?... Creo que lo que dices <strong>bumba</strong> no tiene mucho sentido... la HTTPSession que le estas pasando al objeto <strong>SessionProgressBox</strong> se encapsula como variable de clase <u>no estatica</u>. Eso quiere decir que tu utilizaras tu objeto por donde quieras (aunque lo logico es que los metodos consuman la interfaz ProgressBox y tu les proporciones la implementacion que desees, por ejemplo, <strong>SessionProgressBox</strong>) y una vez que lo hayas utilizado, <u>el Garbage Collector lo destruira</u>.
<br>
<br>
La Session que le pasas en el constructor, ten en cuenta que la pasas <u>ya creada</u>, por tanto al hacer este paso por referencia, no se destruira con el objeto (puesto que el objeto solo tiene un puntero al objeto Session ya creado). La Session se destruira cuando lo diga el Servidor de aplicaciones que es quien la ha creado.
<br>
<br>
No obstante, si no quieres jugar con la Session, puedes picarte otra implementacion de ProgressBox que guarde la variable en otra "caja" pero, tranquilo, que no te vas a dejar sesiones abiertas por ahi. ;)
Enviado por David Bonilla en October 13, 2004 a las 10:10 AM EDT #
Pero <strong>bumba</strong>... en fin... vamos a ver, piensa un poco lo que acabas de decir.
<br>
Si te instancias un objeto <strong>SessionProgressBox</strong> para empezar <u>ya sabes</u> donde estas guardando el progreso: en la Session.
<br>
Se ha donde quieres llegar pero entonces lo que deberiamos hacer es traernos una instancia de la interfaz <strong>ProgressBox</strong> y preguntarle un getProgress sin saber donde lo tiene guardado... el problema intrinseco de lo que dices es el siguiente: <u>¿De donde me traigo esa instancia?</u> ¿De la Session? ¿De Base de Datos?... ¿ DE DONDE ?. La unica solucion valida seria guardar ESE objeto en la Session para poder recuperarlo pero entonces ya estarias guardando en memoria un objeto entero en vez de un Double (bueno... aunque tambien es un objeto, un wrapper). Si lo que deseamos es NO GUARDAR NADA EN SESSION... en fin, que no tiene sentido. ¿Lo entiendes?
Enviado por David Bonilla en October 13, 2004 a las 10:20 AM EDT #
Eiiii,que no para ponerte asi!! A ver, esa instancia no es necesaria traertela de ningún lado, sencillamente la instancias pasando la sesión y task a su constructor y que ella sea la encargada de hacer un getProgress encapsulando detalles de acceso a sesión (por ejemplo, encapsulando como se construye la clave del objeto Double almacenado en la sesión). Lo que me choca es que uses el metodo setProgress para meter en la sesión y que oculte detalles de como meter en la sesión pero a la hora de sacar, el servlet saque directamente de la sesión... no sé.. a mi modo de ver o de una forma o de otra. No es necesario guardar el objeto que implenta ProgressBar en la sesión. Yo lo haría así, que tanto almacenar en XXX o recuperar de XXX pasen a través del objeto SessionProgressBox.
Bueno, espero haber pensado un poquito más la respuesta, o al menos dar sensación de pensar.
Saludos y wuen rollo, hombre, wuen rollo!!
Enviado por bumba en October 13, 2004 a las 01:42 PM EDT #
A veeeer... antes de nada, a lo mejor soy muy apasionado escribiendo (sobre todo porque me has pillado en el trabajo y con las orejas rojas) pero el buen rollo siempre, SIEMPRE, SIEMPRE imperara en este weblog.
<br>
Por eso no te preocupes ;).
<br>
Contestando a tus post... espero que, al menos en el primero estemos de acuerdo, la session no se queda colgada por ningun sitio y el garbage collector funcionara perrrrrrfectamente.
<br>
Respecto al segundo... intentare explicarte OTRA VEZ para que lo entiendas. Tu te centras en el objeto SessionProgressBar, sin embargo, el objeto que reciben los metodos que monitorizan el progreso NO ES ESTE sino ProgressBar, ¿Por que? pues porque a lo mejor alguien se pica un PropertyProgressBar o un DBProgressBar.
<br>
Si que coincido contigo en que se puede implementar tambien un getProgress que encapsule la logica de recuperacion... estoy de acuerdo.
<br>
Espero que con este que te cuento te aclare un poco las cosas. NO es que oculte la manera de guardar en session y luego lo saque directamente de ella.... PARA NADA. Lo que estoy definiendo es un metodo de una interfaz que luego puede implementar un objeto que PUEDE o NO PUEDE tirar de una session ¿entiendes?.
<br>
En el servlet tiro directamente de la session porque no necesito instanciar ninguna objeto para saber donde buscar SE QUE LO HE GUARDADO EN LA SESSION.
<br>
<br>
Tu piensa mas en que el objeto de trabajo es ProgressBox y no SessionProgressBox y veras como entenderas mas todo.
<br>
<br>
Y perdona si algun comentario mio te ha disgustado. En ningun caso era mi intencion.
Enviado por David Bonilla en October 13, 2004 a las 02:27 PM EDT #
...ok, pero si tu interfaz no tiene el metodo getProgress()... cuando implementes un DBProgressBox...o un PropertyProgressBox..... el cliente o contexto que use esa clase.... como obtiene el progreso ?¿?¿?¿?
Entiendo perfectamente que setProgress no encapsula como acceder a una sesión si hablamos de la interfaz; si hablamos en concreto de SessionProgressBox, en esa implementación del interfaz, si entra en juego la sesión.
Jjeje, perdona que sea pesado, pero es que el método getProgress se me antoja necesario en esa interfaz. Igual en el caso de SessionProgressBox no es estrictamente necesario (Servlet conoce Session) pero si quieres hacerlo con una BBDD o un properties por debajo, cambiando la implementación de SessionBox, si es necesario.
Saludos :)))))
Enviado por bumba en October 13, 2004 a las 03:32 PM EDT #
que pasa tronco, la forma elite es crear un hilo, vincularlo a la sesión y redireccionar al jsp mientras siga vivo, en cuanto entienda mi código te lo mando jaja la que no mola es la forma de javaworld porque no es nada generica
Enviado por jano-r en October 13, 2004 a las 03:35 PM EDT #
¿ Pero no habiamos quedado en que estabamos de acuerdo con lo util de implementar un <strong>getProgress</strong> ?. Eso no se discute... entonces ¿ hemos alcanzado el consenso ? ;)
Enviado por David Bonilla en October 13, 2004 a las 03:44 PM EDT #
Jejejeje, ok, fumata blanca, getProgress será a la barra de progreso lo que el monorail a los Simpson. Me despido esperando tu próxima receta de cocina.
Saludos :))
Enviado por bumba en October 13, 2004 a las 06:45 PM EDT #
Jejejeje... creo que hemos llegado a un consenso (eso si, esperando la solucion "elite" de jano-r).
Por cierto bumba... weblog ya.
Enviado por David Bonilla en October 13, 2004 a las 06:48 PM EDT #
En ello estoy, amigo, pero como se avecinan dos semanas de profundos cambios (mudanza de Madrid a Valencia, pintar piso, sacar cera, poner cera, etc, etc) lo estoy dejando un poco apartado hasta tener toda la mudanza hecha. Te felicito por tu log, al menos yo es el que más leo! :)))
Saludos.
Enviado por bumba en October 14, 2004 a las 03:31 AM EDT #
Muchas gracias por las felicitaciones... me abrumas !!!. La verdad es que es muy gratificante que alguien encuentre medio utiles tus comentarios.
<br>
Respecto al weblog... venga... se tarda 2 minutos en ponerlo en pie !!!. En cuanto se acabe esa mudanza lo quiero a la vista.
<br>
Un saludo.
Enviado por David Bonilla en October 14, 2004 a las 03:39 AM EDT #
porq?
Enviado por 200.71.51.217 en April 04, 2007 a las 03:32 PM EDT #