tag:blogger.com,1999:blog-335000332024-03-13T07:56:35.136-03:00Leopard ...Asuntos de java, motos, musica, informática... y cualquier otra cosa que se me venga a la mente.Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-33500033.post-13989238720638398202013-02-22T19:21:00.000-03:002013-02-22T19:21:31.186-03:00Cuidado con yotube.com!Hace unos instantes, trate de ingresar a youtube. Grande fue mi sorpresa cuando me encontré con esta página:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFIG6AqxLlS_OKb5KDYqVY4xURSr_yPNh9o4EmYUvg9g34QTq1riXa5jOtN66Qef9sGuUrLOjCEz8HXgkvvOdkKhsZ7-5D05SR-z8YL3ztOIGIYVG15Nze6yKyQ8uNc5Li5QhfYw/s1600/estafa.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFIG6AqxLlS_OKb5KDYqVY4xURSr_yPNh9o4EmYUvg9g34QTq1riXa5jOtN66Qef9sGuUrLOjCEz8HXgkvvOdkKhsZ7-5D05SR-z8YL3ztOIGIYVG15Nze6yKyQ8uNc5Li5QhfYw/s320/estafa.png" width="320" /></a></div>
<br />
<br />
¡Mich! dije yo... Asi que me puedo ganar un iPad... jejejeje...<br />
<br />
Cuando vi la barra de direcciones me di cuenta de todo. De seguro me pedían el número de la tarjeta de crédito o algo asi.<br />
<br />
La pregunta es ¿cómo llegué ahí? . . . simple... puse <strong>yo</strong>tube.com en lugar de <strong>you</strong>tube.com<br />
<br />
Ya me parecía extraño que Google estuviera regalando "iMac", "iPads" y "iPhones" . . . si ofrecieran un Nexus... caigo.<br />
<br />
<br />
<br />
bytes!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-22078777455183601362012-11-09T18:03:00.000-03:002012-11-21T08:52:28.458-03:00Seleccion de área de una imágen con JavaDe vez en cuando se necesita que el usuario seleccione un área de una imágen para darle tratamiento. Por ejemplo supongamos que tenemos un programa que almacena fichas de empleados y queremos que en cada ficha se almacene la foto del empleado.<br />
<br />
Puede darse el caso de que las imágenes vengan en distinto tamaño, por lo que es útil proporcionar una herramienta que permita la selección de una determinada área de la imágen para su almacenamiento.<br />
<br />
El problema en si no es muy complejo. A grandes rasgos se resume en:<br />
<br />
<div>
</div>
<div>
<ul>
<li>Determinar el punto de origen.</li>
<li>Determinar el área.</li>
<li>Seleccionar el área.</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKEXFXVU9Z6kBTDaC5yxd1mQ5GswPf1FpceXOi-ErXVpptnnPFhjgd3Q7e1dX-Hm2Dan6Wu0R-YIoSbGNmeU7BRyRU5Mt8rSK9IE9TR6oAnn0-Q59kah_a8j5qPJaX1b0iYvX-Lw/s1600/selector.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKEXFXVU9Z6kBTDaC5yxd1mQ5GswPf1FpceXOi-ErXVpptnnPFhjgd3Q7e1dX-Hm2Dan6Wu0R-YIoSbGNmeU7BRyRU5Mt8rSK9IE9TR6oAnn0-Q59kah_a8j5qPJaX1b0iYvX-Lw/s320/selector.png" width="320" /></a></div>
<br />
Para ello utilizaremos un JPanel que contendra la imágen, la cual estaŕa a su vez contenida en un BufferedImage, un MouseListener para detectar cuando el usuario presiona y suelta el boton del mouse y un MouseMotionListener para determinar cuando el usuario mueve el mouse para seleccionar el área.<br />
<br />
Supongamos que el usuario hace clic en un punto de la imagen que llamaremos <i>pi(xi, yi) </i>y arrastra el mouse hasta un punto que llamaremos <i>pf</i><i>(xf, yf)</i>.<br />
<br />
El primer paso consiste en determinar al ancho y alto del área abarcada por el arrastre del mouse.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"> ancho = Math.abs(xi - xf);<br /> alto = Math.abs(yi - yf);</span></span><br />
<br />
Luego obtenemos una imagen con el área seleccionada. Para ello utilizaremos el metodo <i>getSubimage()</i> de BufferedImage.<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> BufferedImage seleccion = imagen.getSubimage(x, y, ancho, alto);</span></span><br />
<br />
Para crear el efecto de opacidad de fondo y seleccion más clara, dibujaremos primero la imagen aplicando un filtro que reduce en un 50% el color. Para ello usaremos <i>RescaleOp.</i><br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">BufferedImageOp op = new RescaleOp(new float[]{0.5f, 0.5f, 0.5f}, new float[]{0f, 0f, 0f}, null);</span></span><br />
<br />
Finalmente sobrecargamos el metodo <i>paintComponent()</i> del JPane para que se dibuje la imagen y el área seleccionada.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">@Override<br /> public void paintComponent(Graphics gr) {<br /> Graphics2D g = (Graphics2D) gr;<br /> super.paintComponent(g);<br /> if (imagen == null) {<br /> return;<br /> }<br /> if (puntoInicial != null && puntoFinal != null) {<br /> g.drawImage(imagen, op, 0, 0);<br /> g.drawImage(getImagenSeleccionada(), x, y, this);<br /> g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);<br /> g.setColor(Color.WHITE);<br /> g.drawRect(x, y, ancho, alto);<br /> g.drawString("Área: " + ancho + "x" + alto, 10, 20);<br /> } else {<br /> g.drawImage(imagen, 0, 0, this);<br /> }<br /> }</span></span><br />
<br />
La verdad, es que el tema quiza sea un poco más complejo, porque debemos cuidarnos de que los puntos esten dentro de la imágen. También podríamos forzar a seleccionar un área siempre cuadrada o bien un rectángulo libre.<br />
<br />
El código es largo y la verdad me da flojera escribirlo todo aca, por eso los ejemplos resumidos.<br />
<br />
Por lo mismo, en <a href="https://sites.google.com/site/leopardbsod/Imagen.tar?attredirects=0&d=1" target="_blank">este enlace</a> se puede descargar el código fuente del Selector de Área de Imágen y un Jframe con el ejemplo de uso para que puedas incluirlo en tu programa. Cualquier comentario, observación y correción del código es bienvenida.<br />
<br />
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-54927462316881925072012-10-24T22:31:00.002-03:002013-08-01T15:38:29.989-04:00Modulador de Ancho de Pulso (PWM) en Java<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
<img alt="javaPWM.png" border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj3-uktmk72WcCshvoSIqBnKbEbdTQ2EH-2xVPi81r7bFjQEbXw137aWnq-a-cmuC3xeHz5WlD12J0fXcC8kWapbyk0QGRLMUA0_Ibv05fXQSJQWARKaSBGiAKJvUoxiRrj3NZMw/s320/javaPWM.png" title="JavaPWM" width="320" /></div>
<br />
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
JavaPWM es una sencilla aplicación que permite convertir cualquier PC con un puerto serial en un modulador de ancho de pulso (PWM).</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Existen en internet varios circuitos simples que permiten controlar un relé con el puerto serial. JavaPWM aprovecha esta característica y envia pulsos al puerto serial que pueden servir para controlar un relé u otro dispositivo similar. He aqui un esquemático simple para controlar un relé por medio del puerto serial:</div>
<div style="text-align: left;">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6d3uDcVDgVIz2OaX2AK-VBNbbOIHE7rse-vb8C1rjeO11vYunhpm3ihGOmwOeeYPZck5olc7fLG9Zn5HmRheb48aXCo1fD-UQwojRfvkYcPSHs1JXEoW_nwjM-9nfWn5Yc-h0zg/s1600/control_rele.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6d3uDcVDgVIz2OaX2AK-VBNbbOIHE7rse-vb8C1rjeO11vYunhpm3ihGOmwOeeYPZck5olc7fLG9Zn5HmRheb48aXCo1fD-UQwojRfvkYcPSHs1JXEoW_nwjM-9nfWn5Yc-h0zg/s320/control_rele.png" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">(originalmente publicada en http://www.windmeadow.com/node/4)</span></div>
<br /></div>
<div style="text-align: left;">
Permite configurar el puerto, modo de operacion, ciclo de trabajo y frecuencia. Se puede trabajar con un pulso simple de duracion determinada o bien como un oscilador a la frecuencia indicada.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
El ciclo de trabajo (duty cycle) puede variar entre 1 y 99%. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
En modo oscilador (continuo) la frecuencia puede variar entre 1 y 50 Hz.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
En modo pulso, el pulso puede durar entre 1 y 100 segundos.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
El modo "off/on" invierte el ciclo.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Requiere Java 6 o superior y la biblioteca <a href="http://rxtx.qbang.org/" target="_blank">rxtx</a> correctamente instalada o configurada.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
En ciertos casos puede dejar el puerto bloqueado. En linux se desbloquea eliminando el archivo Lock del puerto en /var/lock. En Windows no tengo idea como desbloquear un puerto.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Para descargar la aplicación <a href="https://sites.google.com/site/leopardbsod/JavaPWM.jar?attredirects=0&d=1" target="_blank">clic aqui</a>. Es totalmente gratuita!<br />
El codigo fuente se puede descargar <a href="https://sites.google.com/site/leopardbsod/JavaPWM.tar?attredirects=0&d=1" target="_blank">desde aca</a>.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Si te sirve, te gusta o tienes alguna sugerencia, tu comentario es bienvenido.</div>
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com3tag:blogger.com,1999:blog-33500033.post-56073214438304490202012-09-24T10:59:00.000-03:002012-09-24T11:51:56.575-03:00Algunos tips con reflexion en Java.La API de reflexión en Java presenta herramientas que son muy útiles a la hora de hacer que nuestros programas sean "dinámicos" o "expansibles".<br />
<br />
Es muy útil en algunos casos, explorar un objeto en tiempo de ejecucion para conocer sus métodos y atributos.<br />
<br />
He aqui algunos tips básicos para iniciarse con reflexión.<br />
<br />
<b>Clase: Class</b><br />
<br />
La clase <i>Class</i> representa justamente eso: Una clase o una interfaz de Java. Mediante la instancia de Class es posible conocer los métodos que expone la clase, sus atributos, constructores, etc.<br />
<br />
<b>Clase: Constructor</b><br />
<br />
La clase <i>Constructor</i> proporciona informacion de y acceso a un constructor de una clase.<br />
<br />
<b>Clase:</b> <b>Method</b><br />
<br />
La clase <i>Method</i> proporciona información de y acceso a un método de una clase.<br />
<br />
<b>Clase: Field</b><br />
<br />
La clase <i>Field</i> proporciona información de y acceso a un atributo de una clase.<br />
<br />
<br />
Hay mucho más, pero estos simples conceptos son suficientes para comenzar.<br />
<br />
Tomemos como ejemplo, la siguiente clase, la cual nos servirá para explorar un poco de la API <i>java.lang.reflect</i>:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">public class Clase {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> private String atributo;</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public Clase() {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public Clase(String atributo) {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> this.atributo = atributo;</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public String getAtributo() {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> return atributo;</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public void setAtributo(String atributo) {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> this.atributo = atributo;</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public void verAtributo() {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> System.out.println("El valor del atributo es: " + atributo);</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public void metodo() {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> System.out.println("Este es el metodo.");</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public void metodo(String parametro) {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> System.out.println("Este es el metodo con parametro. El parametro fue: " + parametro);</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public static void estatico() {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> System.out.println("Este es el metodo estatico.");</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> public static void estatico(String parametro) {</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> System.out.println("Este es el metodo estatico con parametro. El parametro fue: " + parametro);</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> }</span><span style="font-size: x-small;"><br /></span><span style="font-size: x-small;">}</span></span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">Examinando esta clase, vemos que posee las siguientes características:</span></span><span style="font-size: x-small;"><br /></span><br />
<br />
<ul>
<li><div>
Un atributo de tipo String.</div>
</li>
<li>Un constructor sin parámetros.</li>
<li>Un constructor que recibe un parámetro de tipo String.</li>
<li>Un métod getter para el atributo.</li>
<li>Un método setter para el atributo.</li>
<li>Un método sin parámetros que imprime un texto en consola.</li>
<li>Un método con un parámetro String que imprime un texto en consola.</li>
<li>Un método estático sin parámetros que imprime un texto en consola.</li>
<li>Un método estático con parámetros que imprime un texto en consola.</li>
</ul>
Esto es fácil, porque estamos viendo el código fuente de la clase, pero podemos examinarla completamente usando un programa en java.<br />
<br />
Lo primero es obtener una instancia de <i>Class</i>. <br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Class c = Class.forName("paquete.Clase")</span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Class c = Clase.class</span></span><br />
<br />
Puede ser por el nombre completo de la clase (incluyendo el paquete), o bien invocando directamente el atributo <i>class</i> que toda clase Java tiene.<br />
<br />
El siguiente código instancia una clase por su nombre e imprime el nombre de la clase en pantalla:<br />
<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"> Class c = Class.forName("paquete.Clase");<br /> System.out.println("Clase instanciada: " + c.getName());</span></span><br />
<br />
La ejecución de este código dará como resultado lo siguente:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"> run:<br /> Clase instanciada: paquete.Clase</span></span><br />
<br />
Teniendo una instancia de la clase, podemos comenzar a explorarla:<br />
<br />
El siguiente código permite obtener los constructores de la Clase:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">System.out.println("\nConstructores de la clase:");<br />Constructor[] cons = c.getConstructors(); //c.getDeclaredConstructors();<br /> for (Constructor co : cons) {<br /> System.out.println("Constructor : " + co.getName());<br /> Class[] param = co.getParameterTypes();<br /> if (param.length == 0) {<br /> System.out.println("\tConstructor sin parámetros.");<br /> } else {<br /> for (Class p : param) {<br /> System.out.println("\tParametro: " + p.getName());<br /> }<br /> }<br /> }</span></span><br />
<br />
<span style="font-family: inherit;"><span style="font-size: small;">La ejecución del código anterior dará como resultado:</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">Constructores de la clase:</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">Constructor : paquete.Clase</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Constructor sin parámetros.</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">Constructor : paquete.Clase</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Parametro: java.lang.String</span></span><br />
<br />
<span style="font-family: inherit;">Si se nota, ya esposible obtener información de la clase. En este caso el método </span><span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><i>c.getConstructors() </i></span></span><span style="font-family: inherit;"><span style="font-size: small;">nos permite obtener todos los constructores de la clase. Su hermano </span></span><span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><i>c.getDeclaredConstructors()</i></span></span><span style="font-size: small;"> nos permite obtener los constructores qu</span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">e</span></span><span style="font-size: small;"> fueron declarados específicamente en la clase que estamos explorando (útil cuando una clase hereda de otra).</span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: small;">Exploremos ahora los atributos que posee la clase:</span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">System.out.println("\nAtributos de la clase:");<br /> Field[] fields = c.getFields();<br /> for (Field f : fields) {<br /> System.out.println("Atributo: " + f.getName());<br /> System.out.println("\tTipo del Atributo: " + f.getType().getName());<br /> }</span></span><span style="font-size: small;"><br /></span><br />
<br />
La ejecución del código anterior dará como resultado:<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Atributos de la clase:</span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-size: small;">En este caso, no hay nada. ¿Por qué? </span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<span style="font-size: small;">Si miramos el código de la clase, veremos que contiene un único atributo de tipo <i>private</i></span><span style="font-size: small;"> por lo que no es visible fuera de la clase. Si agregamos el siguiente atributo:</span><span style="font-size: small;"><br /></span><br />
<span style="font-size: small;"><br /></span>
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> public String atributoPublico;</span></span><span style="font-size: small;"><br /></span><br />
<br />
Y ejecutamos el código, veremos lo siguiente.<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Atributos de la clase:<br />Atributo: atributoPublico<br /> Tipo del Atributo: java.lang.String</span></span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: small;"><br /></span>
<span style="font-size: small;">Ahora exploremos los métodos. El siguiente código muestra los métodos de la clase:</span><span style="font-size: small;"><br /></span><br />
<span style="font-size: small;"><br /></span>
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">System.out.println("\nMetodos de la clase: ");</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Method[] metodos = c.getMethods();</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> for (Method m : metodos) {</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> System.out.println("Metodo: " + m.getName());</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> Class[] param = m.getParameterTypes();</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> if (param.length == 0) {</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> System.out.println("\tEl método no acepta parametros.");</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> } else {</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> for (Class p : param) {</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> System.out.println("\tParametro: " + p.getName());</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> }</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> }</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"> }</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<br />
El cual, al ser ejecutado mostrará:<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Metodos de la clase: <br />Metodo: getAtributo<br /> El método no acepta parametros.<br />Metodo: setAtributo<br /> Parametro: java.lang.String<br />Metodo: verAtributo<br /> El método no acepta parametros.<br />Metodo: metodo<br /> El método no acepta parametros.<br />Metodo: metodo<br /> Parametro: java.lang.String<br />Metodo: estatico<br /> El método no acepta parametros.<br />Metodo: estatico<br /> Parametro: java.lang.String<br />Metodo: wait<br /> Parametro: long<br />Metodo: wait<br /> Parametro: long<br /> Parametro: int<br />Metodo: wait<br /> El método no acepta parametros.<br />Metodo: equals<br /> Parametro: java.lang.Object<br />Metodo: toString<br /> El método no acepta parametros.<br />Metodo: hashCode<br /> El método no acepta parametros.<br />Metodo: getClass<br /> El método no acepta parametros.<br />Metodo: notify<br /> El método no acepta parametros.<br />Metodo: notifyAll<br /> El método no acepta parametros.</span></span><br />
<br />
En este caso, vemos métodos que no fueron declarados en la clase. ¿Por que? Porque para obtener los métodos usamos el método <i>getMethods()</i>, el cual retorna todos los métodos en la jerarquía de la clase. Es decir, los métodos de la clase y de su(s) superclase(s). <span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span><br />
<br />
Si en lugar de <i>getMethods()</i> usamos <i>getDeclaredMethods()</i>, obtendremos el siguiente resultado:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Metodos de la clase: <br />Metodo: getAtributo<br /> El método no acepta parametros.<br />Metodo: setAtributo<br /> Parametro: java.lang.String<br />Metodo: verAtributo<br /> El método no acepta parametros.<br />Metodo: metodo<br /> El método no acepta parametros.<br />Metodo: metodo<br /> Parametro: java.lang.String<br />Metodo: estatico<br /> El método no acepta parametros.<br />Metodo: estatico<br /> Parametro: java.lang.String</span></span><br />
<br />
<br />
Pero ésto sólo nos proporciona información de una clase. Ahora pasaremos a la acción.<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span><br />
<br />
Vamos a utilizar 2 instancias de nuestro objeto 'Clase'. En una invocaremos el constructor sin parámetros, y en otra invocaremos el constructor que recibe el parámetro String.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Object o = c.newInstance();<br /> Object o2 = c.getConstructor(String.class).newInstance("Instancia 2");<br /> <br /> System.out.println("Instacia o de Clase: " + o);<br /> System.out.println("Instancia o2 de Clase: " + o2);</span></span><br />
<br />
La ejecución del código anterior dará como resultado:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Instacia o de Clase: paquete.Clase@62f72617<br />Instancia o2 de Clase: paquete.Clase@4fe5e2c3</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span>
<span style="font-size: small;">En el primer caso, la llamada del método <i>newInstance()</i></span><span style="font-size: small;"> llama directamente al contructor sin parámetros. </span><span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span><br />
<span style="font-size: small;">Para invocar la llamada al constructor con parámetros, invocamos el método <i>getConstructor()</i></span><span style="font-size: small;"> y le entregamos como parámetro String.class. Literalmente le estamos diciendo: "Dame el constructor que recibe como parámetro un String".</span><span style="font-size: small;"><br /></span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: small;">Al constructor retornado le invocamos el método <i>newInstance()</i></span><span style="font-size: small;"> y le pasamos como parámetro un String.</span><span style="font-size: small;"><br /></span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: small;">Ejercicio: Intentar construir la instancia o2, pasándole un Integer (u otro). Tendremos una linda excepción.</span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: small;">Ahora vamos a invocar el método para ver el valor del atributo:</span><br />
<span style="font-size: small;"><br /></span>
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Method verAtributo = c.getDeclaredMethod("verAtributo", null);<br /> verAtributo.invoke(o, null);<br /> verAtributo.invoke(o2, null);</span></span><span style="font-size: small;"><br /></span><br />
<br />
Puede observarse que el código en si es simple. A la clase le pedimos el método llamado <i>verAtributo</i> que no tiene parámetros.<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"><br /></span></span><br />
<br />
Luego, invocamos el método mediante <i>invoke()</i>, y le pasamos como parámetro la <b>instancia</b> de la clase en la que invocaremos el método y los parámetros del método (si aplica). La ejecución del código anterior, dará como resultado:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">El valor del atributo es: null<br />El valor del atributo es: Instancia 2</span></span><br />
<br />
Lo cual es correcto, ya que al momento de instanciar, sólo declaramos el atributo en la instancia 2.<br />
<br />
Invoquemos un método con parametros.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;"> Method setAtributo = c.getDeclaredMethod("setAtributo", String.class);<br /> setAtributo.invoke(o, "Un parámetro");</span></span><br />
<br />
Como puede notarse, la metodología es similar a la invocación del constructor. Le decimos a la clase "Dame el método llamado setAtributo que recibe un String como parámetro". Luego invocamos el método en la instancia o y le pasamos como parámetro un String.<br />
<br />
Si volvemos a invocar el método <i>verAtributo</i> en la instancia o, veremos el siguiente resultado:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">El valor del atributo es: Un parámetro</span></span><br />
<br />
Finalmente, invocaremos un método estático con parámetros.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">Method estatico = c.getDeclaredMethod("estatico", String.class);<br /> estatico.invoke(null, "¡Es un método estático!");</span></span><br />
<br />
Como puede notarse, un método estático no necesita una instancia donde invocarse, por lo que el primer parámetro puede ser NULL. La ejecución del código dará como resultado:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-size: x-small;">Este es el metodo estatico con parametro. El parametro fue: ¡Es un método estático!</span></span><br />
<br />
Como puede verse, la API de reflexión es muy potente y trabajando en conjunto con Interfaces y <i>Generics</i> se pueden hacer cosas muy interesantes como por ejemplo una aplicación modular mediante plug-ins o herramientas que analizen y exploren código java... por decir algo.<br />
<br />
Hay mucho, mucho más por explorar. Animo al lector a darse un tiempo de explorar esta API ya que soluciona muchos dolores de cabez y permite que nuestras aplicaciones sean flexibles y extensibles con poco esfuerzo.<br />
<br />
Archivos: <a href="https://sites.google.com/site/leopardbsod/Clase.java?attredirects=0&d=1">Clase.java</a> <a href="https://sites.google.com/site/leopardbsod/Reflexion.java?attredirects=0&d=1">Reflexion.java</a><br />
<br />
Salu2!!!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com1tag:blogger.com,1999:blog-33500033.post-24566061990770278432012-05-17T15:38:00.000-04:002012-05-17T15:48:03.316-04:00Tratamiento de ResultSet con multiples hilosAunque el título de la entrada no es el mas adecuado, la implementación de esta técnica permite procesar <em>aparentemente</em> un ResultSet con múltiples hilos.<br />
<br />
Típicamente, en una aplicación que manipula una gran cantidad de datos con un ResultSet, tenemos el problema de que el tratamiento puede llegar a ser costoso en terminos de tiempo. Esto se debe a que el ResultSet no es <em>thread-safe</em>, es decir, no puede se accedido desde múltiples hilos a la vez.<br />
<br />
Por lo tanto, un escenario como el que se ilustra abajo es técnicamente imposible:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCsUvW7TjsCoKb4WOqZjRHpLcPZVTZ5ALbb5QptAx9MObt8MVgFfxG-7Q98LOJRlWPGhSGqLlNwPTIgv0_GZw-Y_xX3PmhyphenhyphenxbUH25VNoId0ooiMM2DnVFELurZPZ1Osvbkrsgwfw/s1600/BD1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCsUvW7TjsCoKb4WOqZjRHpLcPZVTZ5ALbb5QptAx9MObt8MVgFfxG-7Q98LOJRlWPGhSGqLlNwPTIgv0_GZw-Y_xX3PmhyphenhyphenxbUH25VNoId0ooiMM2DnVFELurZPZ1Osvbkrsgwfw/s1600/BD1.png" /></a></div>
<br />
<br />
Luego, se está obligado a utilizar un único hilo que acceda al ResultSet, lo que se traduce en un desperdicio de recursos y en un altísimo tiempo de espera en caso de contar con grandes volúmenes de información.<br />
<br />
Una solución simple, es almacenar los datos en un objeto que actúe como <i>buffer</i> y que pued ser leído desde múltiples hilos. De este modo, se tiene por un lado a un hilo único accediendo al ResultSet y dejando los datos en nuestro <i>buffer</i>, y por otro lado a varios hilos que leen los datos de este buffer y los procesan en forma paralela.<br />
<br />
Se llega a un escenario más cómodo, que permite el uso de múltiples hilos para el procesamiento de nuestros datos:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi04Wl5-EpOTLiZoSkGMK-mG9n-ayACIGE1c5crLOjbWkxTEeC54vZwSYUQUn5JqWB2B8fg6pSy16aMxFsm9MuVuO2WfZhofhc_X5P1i98n3GpHLsHUYL6sJYBXzv2PDcp09ajpSw/s1600/BD2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi04Wl5-EpOTLiZoSkGMK-mG9n-ayACIGE1c5crLOjbWkxTEeC54vZwSYUQUn5JqWB2B8fg6pSy16aMxFsm9MuVuO2WfZhofhc_X5P1i98n3GpHLsHUYL6sJYBXzv2PDcp09ajpSw/s320/BD2.png" width="304" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Para esto, se necesita un JavaBean que contenga los datos que son leídos desde el ResultSet, una cola para almacenar estos JavaBeans a medida que se van leyendo y una clase que extienda Thread (o implemente Runnable) que será la encargada del proceso. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
La secuencia sería más o menos así:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul>
<li>Obtener el ResultSet</li>
<li>En un hilo, leer el ResultSet, crear los Beans de Datos y llenar el buffer.</li>
<li>Lanzar uno o varios hilos que lean el buffer.</li>
</ul>
<div>
Adicionalmente se necesitan algunos mecanismos de control para:</div>
<div>
<ul>
<li>Ganatizar que el Buffer no crezca descontroladamente.</li>
<li>Asegurar que los hilos de proceso se esten ejecutando hasta que se haya leido completamente el ResultSet.</li>
<li>No continuar hasta que todos los hilos de proceso hayan terminado (este paso puede ser opcional).</li>
</ul>
<div>
<br /></div>
</div>
<div>
Existen muchas formas de implementar esta lógica. Aqui propongo una simple, que puede ser mejorada en gran medida.</div>
<div>
<br /></div>
<div>
Primero: Definimos una clase que actue como "Bean" de datos:</div>
<div>
<br /></div>
<div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">class Bean {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private String dato1;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private String dato2;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private String dato3;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public String getDato1() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> return dato1;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public void setDato1(String dato1) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> this.dato1 = dato1;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public String getDato2() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> return dato2;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public void setDato2(String dato2) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> this.dato2 = dato2;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public String getDato3() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> return dato3;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public void setDato3(String dato3) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> this.dato3 = dato3;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
</div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;">Luego, definimos una clase donde se hará el proceso:</span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;"></span><br />
<span class="Apple-style-span" style="font-family: inherit;"></span><br />
<span class="Apple-style-span" style="font-family: inherit;"><div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">class Proceso {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private static final int MAXIMO_BUFFER = 10;</span></span><br />
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private static final int MAXIMO_HILOS_PROCESO = 5;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private ResultSet rs;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private Thread[] hilosProceso;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private volatile boolean leyendoRs;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> private LinkedBlockingQueue<bean> buffer;</bean></span></span></div>
</div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> /**</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> * Este metodo debe ser lanzado desde un hilo que no sea el </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> * event-dispatch-thread</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> */</span></span></div>
<div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public void procesar() throws SQLException {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> buffer = new LinkedBlockingQueue<bean>();</bean></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> hilosProceso = new Thread[MAXIMO_HILOS_PROCESO];</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> rs = leerBaseDatos();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> leyendoRs = true;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Runnable proceso = new Runnable() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> @Override</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> public void run() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> while (true) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Bean b = buffer.poll();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> if (b == null) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> if (leyendoRs) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> try {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Thread.sleep(250);</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> } catch (InterruptedException ex) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> ex.printStackTrace();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> } else {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> break;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> } else {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> //Hacer algo con Bean b</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> };</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> for (int i = 0; i < MAXIMO_HILOS_PROCESO; i++) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> hilosProceso[i] = new Thread(proceso, "Hilo Proceso " + i);</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> hilosProceso[i].start();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> while (rs.next()) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Bean b = new Bean();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> b.setDato1(rs.getString("dato1"));</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> b.setDato2(rs.getString("dato2"));</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> b.setDato3(rs.getString("dato3"));</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> buffer.offer(b);</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> if (buffer.size() >= MAXIMO_BUFFER) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> try {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Thread.sleep(250);</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> } catch (InterruptedException ex) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> ex.printStackTrace();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> rs.close();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> leyendoRs = false;</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> for (Thread hilo : hilosProceso) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> if (hilo.isAlive()) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> try {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> Thread.sleep(500);</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> } catch (InterruptedException ex) {</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> ex.printStackTrace();</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> /*</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> * En este punto estamos completamente seguros de que </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> * </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">todos los datos </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">han sido procesados.</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> * </span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> */</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> }</span></span></div>
</div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">}</span></span></div>
<div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;">Como puede verse, la clase que procesa los datos es bastante simple. Utilizamos como buffer la clase <b>LinkedBlockingQueue</b> que permite un acceso concurrente a los metodos offer() y poll(). </span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;">Obetenemos los datos con algún método a nuestro gusto, y luego levantamos un flag que indica que estamos leyendo los datos. </span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;">Utilizamos la interfaz <b>Runnable</b> y definimos una pequeña clase anónima que procesa los datos. Esta clase está constantemente leyendo los datos desde el buffer. Si en algún momento no se han leído datos, pero el flag de lectura aún está a <i>true</i>, el hilo esperará 250 milisegundos y continuará su lectura. Esto permite que no se detengan los hilos aunque se produzca algun retraso en el llenado del buffer.</span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-family: inherit;">El bloque while que lee el RsultSet crea las instancias de nuestro bean de datos y las encola. Contiene un pequeño bloque de control, el cual verifica que si el tamaño del buffer supera un máximo establecido, se esperan 250 milisegundos antes de continuar. Esta tecnica me ha dado mejores resultados que definir el tamaño máximo de </span><b>LinkedBlockingQueue </b>(se me estaban perdiendo datos). Cuando termina el ciclo de lectura del ResultSet, el flag de lectura se lleva a <i>false</i>, lo que indica a los hilos de proceso que ya no habrá mas datos para procesar.</div>
<div>
<br /></div>
<div>
Finalmente, existe un pequeño bloque de control, el cual verifica que mientras existan hilos de proceso activos, se esperará. Por lo tanto en este punto la ejecución no continuará hasta que todos los hilos hayan finalizado.</div>
<div>
<br /></div>
<div>
El código es bastante rudimentario, pero es efectivo. Pueden hacerse varias mejoras en las secciones de control (sobre todo la del final), pero prefiero publicar este código ya que es simple de entender. Todas las mejoras y extensiones quedan a gusto del consumidor ;-)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
bytes!</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</span></div>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-25922599372180824542012-03-13T15:23:00.000-03:002012-03-13T16:33:39.829-03:00Actualización de la zona horaria en JavaHasta que pasó... llegó el día del cambio de hora, pero se decidió aplazarlo hasta el 28 de abril.<br />
<br />
Esto pasa con bastante frecuencia y en varios países. Se adelanta o se cambia el horario de verano y nuestros computadores son los primeros en sufrir las consecuencias.<br />
<br />
Pero ¿que es lo que pasa?<br />
<br />
En los sistemas operativos modernos, el reloj hardware del computador almacena la hora oficial universal (GMT/UTC) que en español significa que el reloj de nuestro computador está a la hora con el reloj de Greenwich, Inglaterra.<br />
<br />
El Sistema Operativo deduce entonces la hora de una zona en base a la configuración de zona horaria y la hora UTC. Adicionalmente se utiliza la configuración de horario de verano (DST en ingles) para ajustar la hora a los estándares del momento.<br />
<br />
Por ejemplo, aca en Chile continental, tradicionalmente el horario de verano comienza el segundo sábado de septiembre y termina el segundo sábado de marzo. Nuestra zona horaria es GMT -4, lo que significa que al horario de Greenwich se le restan 4 horas para obtener la hora de Chile continental.<br />
<br />
Es decir: Hora de Chile continental = Hora GMT/UTC - 4.<br />
<br />
Hasta ahí, todo simple, pero además tenemos nuestras reglas de configuracion de horario de verano (DST). Estas reglas introducen un "delta" adicional a la zona horaria.<br />
<br />
O sea: Hora de Chile continental = Hora GMT/UTC - 4 +- DST.<br />
<br />
El problema ocurre justamente con ese delta DST. Por regla general los sistemas operativos tratan de mantenerse actualizados y suelen hacerlo bastante bien, por lo que a menos que usemos un sistema sin soporte o con soporte escaso, esto no debiera presentar mayor inconveniente.<br />
<br />
Java utiliza su propia información de zona horaria. Esto significa que aunque este configurado para uilizar la misma zona horaria del sistema operativo, la información DST que contiene no es la misma del sistema. Como resultado, aunque se actualice la información DST del sistema operativo, la maquina de Java no se verá afectada.<br />
<br />
Y eso fue lo que pasó el sabado pasado. Mi computador se actualizó correctamente y se mantuvo a la hora oficial correcta, pero mis aplicaciones Java muestran la hora con una hora de atraso con respecto al computador:<br />
<br />
Hora UTC: 16:00<br />
Hora Chile Continental: 13:00<br />
Hora PC: 13:00<br />
Hora Java: 12:00<br />
<br />
La máquina virtual Java "cree" que estamos en horario de invierno y por lo tanto muestra la hora que su información de zona horaria le indica que debe mostrar.<br />
<br />
Se puede corregir de varias formas:<br />
<br />
<ul>
<li><div>
Mover la zona horaria del computador o cambiar la hora manualmente.</div>
</li>
<li><div>
Actualizar la versión de Java.</div>
</li>
<li>Corregir la información de zona horaria de Java.</li>
</ul>
La opción 1 no es válida, a menos que solo usemos el computador para la aplicación Java conflictiva. El problema es que cuando sea el cambio de horario real, tendremos que mover a mano nuevamente la configuración horaria.<br />
<br />
La opción 2 es adecuada, pero a veces no es posible. Hay aplicaciones que dependen de una versión particular de java y no es posible actualizar, en otros casos Oracle no ha liberado la actualización para la zona horaria.<br />
<br />
La opción 3 puede ser útil en casos que no se pueda actualizar. La información de zona horaria es compatible entre diferentes versiones de Java.<br />
<br />
La información de zona horaria se encuentra en:<br />
<br />
JAVA_HOME/lib/zi<br />
<br />
Por lo tanto es posible sobreescribir la informacion de zona horaria con la de una versión actualizada.<br />
<br />
Por ejemplo, puedo sobreescribir el directorio 'zi' de una version de Java Sun 1.4 con el directorio 'zi' de una versión de OpenJDK actualizado. Con esto la información de zona horaria se actualizará y la máquina virtual mostrará la información correcta.<br />
<br />
En sistemas UNIX puede usarse un enlace simbólico a una versión que sabemos se mantiene constantemente actualizada y asi incluso nos evitaremos hacer actualizaciones a mano.<br />
<br />
Opciones y soluciones hay... la proxima vez no tendremos problemas con el cambio de horario.<br />
<br />
<br />
bytes!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com2tag:blogger.com,1999:blog-33500033.post-50206905254108057802012-02-06T11:17:00.000-03:002012-02-06T16:31:29.397-03:00Agregar Texto en color a un JTextPane<span style="font-family: "Arial", "Helvetica", sans-serif;">De vez en cuando se me ha hecho necesario utilizar un </span><span style="font-family: "Courier New", "Courier", monospace;">JTextPane</span><span style="font-family: "Arial", "Helvetica", sans-serif;"> para entregar mensajes al usuario conforme se realiza una tarea. Por lo mismo es muy importante que el usuario pueda detectar rápidamente mensajes de error y que mejor para esto que utilizar colores en el texto. Los mensajes normales pueden ir en negro, los mensajes de error en rojo, etc.</span><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Para ello se puede utilizar la clase </span><span style="font-family: "Courier New", "Courier", monospace;">StyledDocument</span><span style="font-family: "Arial", "Helvetica", sans-serif;"> de Java que permite definir algunas caracteristicas del texto que se insertará en el </span><span style="font-family: "Courier New", "Courier", monospace;">JTextPane</span><span style="font-family: "Arial", "Helvetica", sans-serif;">. </span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Sin más, he decidido crear una clase que extienda de </span><span style="font-family: "Courier New", "Courier", monospace;">JTextPane </span><span style="font-family: "Arial", "Helvetica", sans-serif;">y que proporcione los métodos que necesito:</span><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><span style="font-size: x-small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;">public class Consola extends JTextPane {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> </span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;">public void append(Color color, String texto) {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> StyledDocument doc = getStyledDocument();</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> Style syle = doc.addStyle("txt", null);</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> StyleConstants.setForeground(syle, color);</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> try {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> doc.insertString(doc.getLength(), texto, syle);</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> setCaretPosition(doc.getLength());</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> } catch (BadLocationException ex) {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> ex.printStackTrace();</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> }</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> }</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> public void appendRed(String texto) {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> append(Color.RED, texto);</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> }</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> public void append(String texto) {</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> append(Color.BLACK, texto);</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"> }</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;"><br /></span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: small;">}</span></span><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;">Una solución simple que puede ser de gran utilidad. Jugando un poco con las clases </span></span><span style="font-size: small;"><span style="font-family: "Courier New", "Courier", monospace;">StyledDocument</span></span><span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;">,</span></span><span style="font-size: small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span><span style="font-family: "Courier New", "Courier", monospace;">Style </span></span><span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;">y</span></span><span style="font-size: small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span><span style="font-family: "Courier New", "Courier", monospace;">StyleConstants</span></span><span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;"> pueden obtenerse resultados muy interesantes.</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"><br /></span></span><br />
<span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span></span><br />
<span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span></span><br />
<span style="font-size: small;"><span style="font-family: "Arial", "Helvetica", sans-serif;">bytes!</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"><br /></span></span>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-20445298543031585212012-02-02T10:02:00.001-03:002012-02-02T10:05:02.837-03:00JTextArea transparente en Look & Feel Nimbus<span style="font-family: "Arial", "Helvetica", sans-serif;">Un problema que he observado al utilizar el look & feel 'Nimbus' de Java 6 es que las JTextArea mantenien el color de fondo blanco a pesar de que se ha invocado el método </span><span style="font-family: "Courier New", "Courier", monospace;">setOpaque(false)</span><span style="font-family: "Arial", "Helvetica", sans-serif;">.</span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Por lo que he leído, el problema se debe al diseño original de Swing. El metodo setOpaque() tiene el efecto de que el componente pueda no pintar alguno o todos sus pixeles, y en clases que extiendan a JComponent esto depende del look & feel.</span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">En el caso de Nimbus, este look and feel requiere transparencia en los componentes para dibujar los bordes redondeados, por lo que los pixeles del componente deben ser pintados.</span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">La solucion es utilizar un color de fondo transparente (alfa=0) y tambien un borde transparente a fin de que el efecto final sea un componente 100% transparente:</span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;">textArea.setBorder(BorderFactory.createEmptyBorder()); </span><span style="font-family: "Arial", "Helvetica", sans-serif;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;">textArea.setBackground(new Color(0, 0, 0, 0));</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Con esta simple operación, el componente será completamente transparente, no sólo omitiendo el dibujado de pixeles, sino haciendo que los pixeles que se dibujan sean realmente transparentes.</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com1tag:blogger.com,1999:blog-33500033.post-30071746428181704612011-11-30T09:46:00.001-03:002012-12-06T12:36:18.000-03:00Respaldo rápido de un disco duro en UNIX con dddd es un comando muy potente que realiza copias bit-a-bit de un archivo a otro. Gracias a que en UNIX, todos los dispositivos son un archivo, podemos aprovechar esta característica para hacer copias de seguridad.<br />
<br />
El uso básico de dd es:<br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;">$dd if={archivo_de_entrada} of={archivo_de_salida} bs={tamaño_bloque}</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span>
El tamaño de bloque indica más o menos la cantidad de bytes que se copiaran a la vez. Un tamaño de bloques pequeño permite una mayor tolerancia a fallos en el origen, mientras que un tamaño más grande permite una mayor velocidad.<br />
<br />
Por ejemplo, una copia de disco a disco podría ser:<br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;">$dd if=/dev/hda of=/dev/sda bs=4096</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span>
También es posible usar un archivo de imagen:<span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;">$dd if=/dev/hda of=./imagen.img bs=4096 conv=noerror</span><br />
<br />
El parametro <span style="font-family: "Courier New", "Courier", monospace;">conv=noeeror </span><span style="font-family: inherit;">indica que continúe si se presenta un error de lectura.</span><br />
<span style="font-family: inherit;">Especificamos un tamaño de bloque de 4k para hacerlo más tolerante a errores de lectura.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Otra forma es utilizarlo en conjunto con gzip para hacer copias de respaldo comprimidas:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: "Courier New", "Courier", monospace;">$dd if=/dev/hda conv=noerror bs=4k | gzip -c > ./imagen.img.gz</span><span style="font-family: inherit;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span>
<span style="font-family: inherit;">O con gunzip para restaurar las imágenes de respaldo</span><span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;">$gunzip -z ./imagen.img.gz | dd of=/dev/hda bs=4k conv=noerror</span><span style="font-family: inherit;"><br /></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br /></span>
<span style="font-family: inherit;">Si se quiere monitorear el estado de copia, se le puede enviar la señal USR1 al PID del comando. </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">$kill -USR1 {PID_DE_dd}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Obviamente hay muchas más opciones, que pueden ser investigadas en el manual de dd</span><span style="font-family: "Courier New", "Courier", monospace;"><br /></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: "Courier New", "Courier", monospace;">$man dd</span><span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-68850314470997542142011-08-30T10:42:00.000-03:002011-11-30T10:32:08.748-03:00Recorriendo Vectores gigantes con multiples hilos<span style="font-size: small;">Hay momentos en la vida en que inebitablemente nos enfrentamos a la busqueda de un valor dentro de una coleccion gigante. Hay veces en que el uso de un </span><i><span style="font-size: small;">contains(Object o)</span></i><span style="font-size: small;"> aplicado a una </span><i><span style="font-size: small;">Collection</span></i><span style="font-size: small;"> puede ser suficiente, pero hay ocasiones en las que incluso esto no es bastante.</span><br />
<span style="font-size: small;">Hace poco me vi enfrentado a un problema en que dado un dato y un gran vector, debía aplicar un algoritmo de comparación especial que me impedía recurrir al </span><i><span style="font-size: small;">contains().</span></i><br />
<span style="font-size: small;">El problema fundamental en este caso era que la comparación no se hacía directamente con un metodo </span><i><span style="font-size: small;">equals()</span></i><i><span style="font-size: small;"> </span></i><span style="font-size: small;">o un == sino que ambos datos debían ser entregados a un tercer objeto que se encargaba de la verificación, por lo que me vi enfrentado a un punto en el que mi unica vía era iterar uno a uno los elementos del vector.</span><br />
<span style="font-size: small;">En las pruebas de desarrollo el modelo funcionaba perfectamente, pero al ponerlo en producción comenzó a mostrar falencias en el rendimiento. Pese a que el algoritmo de verificación es eficiente, el ciclo </span><i><span style="font-size: small;">for</span></i><span style="font-size: small;"> utilizado podía ser realmente demoroso.</span><br />
<span style="font-size: small;">Lugo de pensarlo un poco, llegué a una solución bastante aceptable, aprovechando las características multi hilo de Java.</span><br />
<span style="font-size: small;">La solución en si es simple: </span><b><span style="font-size: small;">divide y vencerás</span></b><span style="font-size: small;">. Corté el vector en N trozos de pequeño tamaño e inmediatamente lanzo N hilos de verificación simultánea que realizán la búsqueda. El primero que encuentre el dato grita "gané" y detiene a los demas hilos.</span><br />
<span style="font-size: small;"></span><span style="font-size: small;"><br />
</span><br />
<span style="font-size: small;">Visto paso a paso:</span><br />
<span style="font-size: small;"></span><span style="font-size: small;"><br />
</span><br />
<ol>
<li><span style="font-size: small;">Establezco un tamaño de bloque. Por ejemplo 100 unidades. Cada hilo hará la búsqueda sobre este número de datos.</span></li>
<li><span style="font-size: small;">Divido el tamaño de mi vector en el tamaño del bloque. Si el resultado es menor a uno, significa que mi vector es menor al bloque, por lo que el resultado debe ser 1.</span></li>
<li><span style="font-size: small;">Preparo un espacio para que cada hilo notifique que ha terminado sin encontrar resultados.</span></li>
<li><span style="font-size: small;">Preparo un boolean para indicar que el dato fue encontrado.</span></li>
<li><span style="font-size: small;">Lanzo hilos de busqueda.</span></li>
<li><span style="font-size: small;">Espero...</span></li>
</ol>
<br />
<span style="font-size: small;">La implementacion mas simple de esta algoritmo, podria hacerse asi:</span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;">public class Buscador {</span></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private static final int TAM_BLOQUE = 100; //Tamaño del bloque</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private static Logger logger = Logger.getLogger(</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;">Buscador.class.getName()</span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;">); </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private boolean encontrado; //Indica que el dato fue encontrado</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private List datos; //Donde se hara la busqueda</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private Map<integer, boolean=""> flags;</integer,></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> //Donde cada hilo indica que termino</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private Resultado resultado; //El dato que fue encontrado </span></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> public Buscador(List datos) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> this.datos = datos;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> }</span></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> /**</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * Este metodo debe ser lanzado desde un hilo, no desde el event-dispatch </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * thread ya que si no bloqueara la GUI</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> *</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> */ </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> public Resultado buscar(Muestra muestra) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> if (datos == null || datos.isEmpty()) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> return null;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> }</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> //Sincronizo los datos para buscar desde muchos hilos </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> List vector = Collections.synchronizedList(datos);</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> int bloques = datos.size() / TAM_BLOQUES;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> if (bloques < 1) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> bloques = 1;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> }</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> flags = Collections.synchronizedMap(new HashMap<integer, boolean="">(bloques));</integer,></span></span><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> final int largoSegmento = t / bloques;<br />
encontrado = false;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> resultado = null;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> /*</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * Este es el punto donde se lanzan los hilos de busquedas. Aprovechamos </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * las caractristicas de las clases anonimas y el metodo sleep() de la </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * clase Thread. Por eso este metodo debe lanzarse desde un hilo en </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * segundo plano. </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> */ </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> for (int hilo = 1; hilo <= bloques; hilo++) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> final int nHilo = hilo; //Lo hacemos final para usarlo en la clase anonima</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> flags.put(nHilo, false); //El hilo aun no termina</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> Runnable busqueda = new Runnable() {</span></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> public void run() {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> //Desde donde y hasta donde debe buscar este hilo </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> int desde = desde = (nHilo - 1) * largoSegmento;<br />
int hasta = largoSegmento * nHilo;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> /*</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * Instancia del verificador. Es propia de cada clase, </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * para asi evitar colisiones entre los hilos</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> */</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> Verificador v = Verificador.newInstance();</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> for (int k = desde; k < hasta; k++) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> if (encontrado) {<br />
logger.debug("Hilo " + nHilo + ": Otro hilo encontro el registro :(");<br />
marcarfin();<br />
return;<br />
}</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> Object dato = vector.get(k);</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> //Realiza la verificacion. . .. bla bla bla </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> v.verificar(dato, muestra); </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> if (v.esValido()) {</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> logger.debug("Hilo " + nHilo + ": Encontre el registro! :D");<br />
encontrado = true;</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> resultado = v.getResultado();</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> marcarfin();<br />
return; </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> } </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> } </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> logger.debug("Hilo " + nHilo + ": Finalizo sin encontrar registro :(");<br />
marcarfin(); </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> }</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> /**</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * Coloca en el mapa la marca de que este hilo ya temino.</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> */ </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private void marcarfin() {<br />
flags.put(nHilo, true);<br />
} </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> };</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> new Thread(busqueda, "Hilo de busqueda " + hilo).start();</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> } </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> while (!encontrado && !finalizado()) {<br />
try {<br />
Thread.sleep(500L);<br />
} catch (InterruptedException ex) {<br />
//algo con la excepcion<br />
}<br />
}<br />
return resultado; </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> } </span></span><br />
<br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> /**</span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> * Verifica que todos los hilos hayan finalizado. </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> */ </span></span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;"> private boolean finalizado() {<br />
for (boolean hiloFinalizado : flags.values()) {<br />
if (!hiloFinalizado) {<br />
return false;<br />
}<br />
}<br />
return true;<br />
} </span></span><br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;">} </span></span><br />
<br />
<br />
<span style="font-size: small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span><span style="font-family: inherit;">A simple vista puede verse algo confuso, pero si examina con detencion, puede verse que el truco se encuentra dentro del ciclo <i>for.</i></span></span><span style="font-size: small;"><span style="font-family: inherit;"> Aqui se lanzan tantos hilos como deban ser lanzados. Cada hilo comparte algunos atributos con los demas hilos: Un mapa para grabar su estado, la variable donde se graba el resultado, un boolean para indicar que el dato fue encontrado y un vector sincronizado que es copia del original.</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">Cada hilo realiza la búsqueda en su espacio asignado dentro del <i>gran vector</i></span></span><span style="font-size: small;"><span style="font-family: inherit;">. Asi, por ejemplo si nuestro vector tiene 1000 unidades y cada bloque es de 100, el primer hilo hará la busqueda desde el 0 al 99, el segundo desde el 100 al 199, el tercero desde el 200 al 299 y asi sucesivamente.</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">Obviamente los valores aqui expresados son para ejemplo, quiza puedan modificarse los valores para ajustarse a un escenario más real. La clase <i>Verificador </i></span></span><span style="font-size: small;"><span style="font-family: inherit;">y sus metodos son ficiticias y la idea es que sea reemplazado por lo que se necesite. Del mismo modo puede optimizarse el uso de <i>Generics</i></span></span><span style="font-size: small;"><span style="font-family: inherit;"> en el buscador y hacer otras mejoras como eliminar el boolean "encontrado".</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">También puede limitarse el número de hilos lanzados <a href="http://leopard-bsod.blogspot.com/2009/08/control-y-pausa-de-ciclos-for-do-while.html">aplicando un mecanismo de pausa y espera</a> </span></span><span style="font-size: small;"><span style="font-family: inherit;"> para el control de los hilos y varias mejoras más que se me van ocurriendo.</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">Actualmente esta implementación está funcionando perfectamente y mis usuarios no han vuelto a quejarse por lentitud.</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">=) </span></span>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-18800736716605796252011-07-26T16:57:00.002-04:002011-07-26T16:57:43.471-04:00ReflexiónUn buen programador no hace la pega.... hace un programa que haga la pega por él . . . .Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-71897081929336709892011-07-26T12:50:00.001-04:002011-07-26T13:00:47.739-04:00Controlar JSpinner con la rueda del mouseUna caracteristica de una buena aplicacion con interfaz gráfica es la capacidad de responder a eventos que el usuario supone debe realizar para una determinada acción.<br />
<br />
Me explico: Si un usuario ve un botón, la acción natural es hacer clic en el, pero también sería válido hacer que el botón responda a la tecla 'enter'.<br />
<br />
Del mismo modo, en los JSpinner la acción natural es utilizar las flechitas y hacer clic en ellas para modificar el valor, pero si el mouse tiene rueda probablemente el usuario girará la rueda esperando modificar el valor del JSpinner.<br />
<br />
Para que esto ocurra, se debe agregar al JSpinner un <i>listener</i> que implemente la interfaz <b>MouseWheelListener</b>. Java tiene por defecto una implementación vacía llamada <i>MouseAdapter</i> que simplifica la creación de <i>listener</i> ya que debe sobrecargarse sólo el método que necesitamos.<br />
<br />
Manos a la obra: Una vez instanciado nuestro JSpinner agregamos un <i>MouseAdapter</i> con un código similar a éste:<br />
<br />
<span style="font-family: "Courier New", "Courier", monospace;">JSpinner spinner = new JSpinner();</span><br />
<span style="font-family: "Courier New", "Courier", monospace;">SpinnerModel modelo = new SpinnerNumberModel(0, 0, 100, 1);</span><br />
<span style="font-family: "Courier New", "Courier", monospace;">spinner.setModel(modelo);</span><br />
<span style="font-family: "Courier New", "Courier", monospace;">spinner.addMouseWheelListener(new MouseAdapter() {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br />
</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> @Override</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> public void mouseWheelMoved(MouseWheelEvent e) {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> try {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> Object mov = null;</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> if (e.getWheelRotation() == 1) {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> //la rueda baja</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> mov = modelo.getPreviousValue();</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> } else if (e.getWheelRotation() == -1) {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> //la rueda sube</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> mov = modelo.getNextValue();</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> }</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> if (mov == null) {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> return;</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> }</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> modelo.setValue(mov);</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> } catch (Exception ex) {</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> ex.printStackTrace();</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> }</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"> }</span><br />
<span style="font-family: "Courier New", "Courier", monospace;">});</span><br />
<span style="font-family: "Courier New", "Courier", monospace;"><br />
</span><br />
Como puede observarse, se agrega una clase anónima que extiende a <i>MouseAdapter</i> y sobrecargamos el método <i>mouseWheelMoved()</i>. En este método leemos el evento y determinamos la dirección en que se giró la rueda. Para ello invocamos el método getWheelRotation() que retornará un entero: -1 si la rueda "sube" y 1 si la rueda "baja". <br />
<br />
Luego, sabiendo la direccion en que el usuario giró la rueda, le solicitamos al modelo del JSpinner el valor siguiente o anterior según el caso. Cuando se ha llegado al tope de valores del modelo (0 o 100 en el ejemplo) el modelo retorna null.<br />
<br />
Teniendo el valor que debemos aplicar, se lo entregamos al modelo. Fin del problema.<br />
<br />
Se pueden hacer varias mejoras al ejemplo (por ejemplo usar un <i>switch</i> en lugar de un <i>if</i>, pero eso queda a gusto del programador)Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-72154964811843118102009-10-23T16:51:00.001-03:002009-10-23T16:51:52.593-03:00Primeras Impresiones de Kubuntu Karmic KoalaEn cuanto me entere de que se habia liberado la primera RC de Kubuntu 9.10 Karmic Koala me hice el animo y decidi dar el salto.<br />
<br />
La actualizacion desde los repositorios de Chile tomo solo un par de horas y pude continuar trabajando normalmente mientras se hacia la actualizacion.<br />
<br />
La primera impresion fue notar la ausencia de parpadeos en la pantalla al conmutar entre el splash de inicio y el entorno X. Este beneficio se obtiene por el uso del Kernel Linux 2.6.31-14. <br />
<br />
Luego de un par de problemas con mi cliente SVN que pude solucionar purgando y reinstalando el paquete, pude comenzar a operar en serio.<br />
<br />
Uno de los cambios que me dejo gratamente sorprendido es la optimizacion en el uso de memoria que tambien viene gracias al uso del Kernel 2.6.31. El plasmoide de uso de memoria y la luz de actividad del disco duro acusan un menor uso de memoria virtual para la misma cantidad de aplicaciones abiertas. <br />
<br />
El rendimiento general tambien se vio incrementado. El comportamiento de Kwin por fin ha alcanzado un punto en el que no tiene nada que envidiar a otros sistemas de composicion. En mi caso particular me he visto beneficiado por las mejoras en el driver de la tarjeta Intel.<br />
<br />
El aspecto grafico esta muy bien cuidado. Por ejemplo al instalar un programa con KPackageKit no utiliza una ventana GTK para pedir la contraseña de usuario sino que la aplicacion es "100% KDE". La integracion grafica de OpenOffice tambien agrega uniformidad al escritorio lo mismo que K3b (que por fin se integra visualmente con el tema de escritorio de KDE), auque no puedo decir lo mismo de otras aplicaciones que utilizan bindings GTK como Eclipse.<br />
<br />
En resumen general, Karmic Koala cumple lo que promete: Un incremento en el rendimiento que el usuario notará y mejoras visuales que se agradecen.Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com1tag:blogger.com,1999:blog-33500033.post-64939619102449106022009-10-21T15:46:00.002-03:002009-10-21T15:46:41.482-03:00La necesidad de inversion en TI en ChileLes contare una experiencia personal<br />
<br />
Años atras participe en un proyecto de empresa con unos amigos en el que desarrollamos tecnologia para garantizar la trazabilidad de productos agricolas. El software era muy bueno, combinabamos lo mejor de la tecnologia móvil, software libre y un desarrollo innovador, creando un producto nacional que tenía un gran potencial para dotar a la industria agricola Chilena con una excelente herramienta de apoyo.<br />
<br />
Intetamos infructuosamente de obtener algun apoyo estatal ya que los ciclos de venta de este tipo de proyectos son largos, lo que no genera ingresos a corto plazo y por otro lado la mano de obra altamente calificada requiere pagar buenos salarios y contar con una oficina medianamente decente para reunirse con los clientes. Pese a que contamos con el apoyo de algunos empresarios y logramos cerrar algunos proyectos, se necesitaba una inyeccion de recursos importante en los primeros años de funcionamiento.<br />
<br />
Golpeamos las puertas de todos los bancos, recurrimos a varios ministerios, postulamos a varios proyectos y al final tuvimos que bajar la cortina. Me quedo una muy mala sensacion de la importancia que se le da a la industria nacional, sobre todo en el sector TI. Hasta el momento no existe una politica clara del gobierno para entregar apoyo al emprededor (en todas las areas) y mas aun en el área de TI.<br />
<br />
Con mucha tristeza he visto grandes acuerdos que cierra el gobierno con empresas extranjeras, entregando recursos preciosos que podrian ser invertidos en la industria nacional obtieniendo los mismos resultados a corto plazo, pero generando a largo plazo una plataforma de conocimento y experiencia que potencialmente se puede transformar en un producto de exportacion que generaria mucha riqueza.<br />
<br />
Solo basta imaginar que hubiera pasado si hubieramos conseguido el apoyo necesario en el moento necesario. Probablemente hoy en dia seriamos lider en sistemas de trazabilidad agrícola y quiza ya estariamos exportando nuestro conocimiento generando riqueza y puestos de trabajo que tan necesarios son hoy en dia.<br />
<br />
Tambien imagino una distribucion Linux desarrollada en conjunto por muchas universidades, institutos y liceos con patrocinio del estado. Imagino empresas recibiendo regalias tributarias en la medida que implementan esta distribucion. Imagino computadores ensamblados aqui en Chile con software nacional a bajo costo para todo ciudadano. Imagino muchas empresas utilizando estas herramientas y contratando a los profesionales surgidos de estas universidades e institutos prestando servicios aca y exportando su know-how a otros paises.<br />
<br />
He visto nacer y morir muchas empresas TI aca en Chile por falta de apoyo estatal. Por lo mismo creo que se hace necesario un rol mas activo del estado que vaya en apoyo del pequeño y mediano empresario que quiera innovar en tecnologia. Tal como dicen muchos, tecnologia no es lo mismo que internet. No estamos en condiciones de desarrollar una industria pesada o una industria de alta tecnologia (hardware) que sea competitiva con los estandares internacionales, pero si estamos en condiciones de desarroollar una industria basada en el software que puede potenciar y revolucionar el modelo economico nacional. Las herramientas estan al alcance de la mano, hay mucha innovacion aca, hay mucha gente inteligente, trabajadora y emprendedora. Solo hace falta darles una mano.Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-46677330410507078002009-10-14T12:20:00.000-03:002009-10-14T12:20:28.012-03:00Horas extras2 horas extras diarias.. de 18:00 a 20:00 hrs, justo cuando comienza el horario de verano. Que lindo!!!<br />
<br />
Hay que ganarse el pan, asi que es mejor dedicarse de cabeza a eso, debemos establilizar una version del programa que cariñosamente llamamos 'incompilable' mientras que debemos hacer mejoras de ultimo minuto a la version estable.Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-33028870821241983612009-09-08T08:45:00.000-04:002009-09-08T08:45:31.901-04:00Makepkg version PIEn Slackware 13:<br />
<br/><br />
<b><br />
Slackware package maker, version 3.14159<br />
</b><br />
<br />
<br />
:-PAnonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-28667525832512824252009-09-03T08:54:00.003-04:002009-09-03T09:55:30.425-04:00Slackware 13 a la cartaAcabo de enterarme del <a href="http://www.slackware.com/announce/13.0.php">lanzamiento de la version 13</a> de la veterana distribucion Slackware Linux.<br/><br />Ha pasado mucha agua bajo el puente desde que probe linux por primera vez en 1998. Y dado que Slackware (version 3.3) fue lo primero que conoci, paso a ser mi distribucion favorita durante muchos años, llegando incluso a escribir <a href="http://www.slackware.cl/index.php?q=node/345">un libro</a> con algunos consejos para la utilizacion y aprendizaje.<br/><br />Cambios en mi enfoque de usuario, insatisfaccion con el ritmo de desarrollo y software disponible y otras cosas que no viene al cabo mencionar me hicieron abandonar el uso de esta distribucion cuando se encontraba en la version 11 (creo). Aun asi siempre tuve el DVD a mano ya que hasta el momento no he conocido otra distribucion que funcione en modo Live sin tratar de iniciar X, lo que se agradece cuando la tarjeta de video no esta soportada (lease ATI).<br/><br />Hace un par de meses atras tuve que descargar el DVD de la version 12.2 para probar un servidor con tarjeta RAID que era imposoble de hacer funcionar con otras distros (Centos, Ubuntu y Suse no se la pudieron). Al comprobar que Slackware arrancaba sin problemas y felizmente reconociendo de inmediato la controladora e ignorando cualquier otro error, retumbaron en mi mente las palabras 'Keep it simple, stupid'.<br/><br />Y bien, hoy me disponia a instalar Slackware 12 en una maquina virtual cuando solo por curiosidad visito la pagina oficial. Asi es como me encuentro con la agradable noticia de una nueva version de la que fue mi primer amor. Una lectura del anuncio oficial hizo que me pusiera a descargarla de inmediato y ahora solo espero que termine pronto la descarga para probarla en una maquina REAL y no virtual:<br /><ul><br /><li>Por primera vez Slackware tiene un port <b>oficial</b> a 64 bits. Era algo de realmente necesario y que de hecho me tenia desencantado.</li><br /><li>Entornos de escritorio XFCE 4.6.1 y KDE 4.2.4. Personalmente creo que habria sido mejor incoporar KDE 4.3.0 pero considerando que fue lanzado hace poco... quiza en la version current....</li><br /><li>Kernel 2.6.29. Debo agregar que Slackware es la unica distribucion de todas las que he probado que <b>nunca me ha dado problemas con los drivers propietarios de ATI y Nvidia</b></li><br /><li>GNU Lib C 2.9</li><br /><li>GCC 4.3.3</li><br /><li>Una coleccion de paquetes de X 'remasterizada' que en muchos casos presciende del archivo de configuracion</li><br /><li>Un nuevo formato de paquetes 'txz' con mayor compresion y otras mejoras</li><br /></ul><br />Ahora solo espero que termine de bajar para probarlo... espero reencantarme.<br/><br />bytes!!!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com2tag:blogger.com,1999:blog-33500033.post-14750783995278875242009-08-28T11:29:00.002-04:002009-08-28T11:33:53.504-04:00Eclipse v/s Netbeans . . . Introduccion<p>Una disputa de nunca acabar. Una guerra santa mas <br />en el universo del software.<br/><br />Cuando no es Windows v/s Linux, Kde v/s Gnome, GTK v/s QT. Siempre hay un buen motivo para pelear. Y como no se puede ser menos, tambien hay bandos que luchan a muerte por imponer al bando contrario la idea de que su IDE favorito es el mejor.<br/><br />No pretendo aqui decantarme por un bando en particular. He usado ambos IDE en los ultimos 6 <br />meses, lo suficiente como para dar una opinion objetiva y sin cegueras causadas por el fanatismo. Cada IDE tiene sus pro y sus contra, y la decision final dependera de las necesidades y el gusto personal de cada uno.<br/><br /><b>Preparando el terreno:</b><br/><br />Antes de comenzar, quiero poner mis piezas sobre el tablero <br />para que asi se entienda en cierta manera mi perspectiva:<br/><br /><ul><br /><li>Llevo casi 3 años programando en Java, 11 años usando Linux, y trabaje 5 años como administrador de redes antes de programar.</li><br /><li>Cuando aprendi Java (hice un curso), fue con Eclipse. Mis primeros pasos en Java fueron con Eclipse.</li><br /><li>Durante 1 año y medio aprox trabaje exclusivamente con NetBeans, desarrollando en J2EE, Struts y Swing.</li><br /><li>Los ultimos 6 meses han sido simultaneamente en Eclipse y Netbeans dependiendo del problema a enfrentar. Ha sido trabajando en una aplicacion Swing con base de datos Postgres</li><br /></ul><br />Durate los proximos meses ire escribiendo acerca de mis impresiones, las cuales emanan desde una prespectiva de usuario de la aplicacion, el cual debe lidiar con factores como la configuracion, ayuda, herramientas disponibles, extensiones, bugs, etc. Factores que finalmente influyen en algo tan trascendental como es la <b>productividad</b> de quien utiliza estas herramientas.<br/><br />No pretendo hacer una comparación demasiado acuciosa, sino más bien que estas líneas y sus futuras extensiones sirvan de orientación al usuario neófito que debe decidir por cual herramienta decantarse.<br /><br/><br />Let's dance!<p>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-36765617311586276642009-08-21T08:44:00.005-04:002009-08-21T09:27:53.669-04:00AudioCopy 0.1<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE61MxnZYg_HXx1utbtwkQXzj9W4u_0zQ3vpDIU6eS40sCcvvlrH4G81G8tcrbQrWshCsXjy2RtDjjgO7cyE6YtqRcImhamq2zGdZPO7bZjonmk5gH2BZDsYM8fOlovFA3uw157A/s1600-h/audiocopy_0.1.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 272px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE61MxnZYg_HXx1utbtwkQXzj9W4u_0zQ3vpDIU6eS40sCcvvlrH4G81G8tcrbQrWshCsXjy2RtDjjgO7cyE6YtqRcImhamq2zGdZPO7bZjonmk5gH2BZDsYM8fOlovFA3uw157A/s320/audiocopy_0.1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5372400145176185874" /></a><br />AudioCopy es una sencilla herramienta para copiar y transferir archivos de audio<br />desde una carpeta a otra.<br /><br />A diferencia de los complementos y plugins de algunos reproductores de musica,<br />AudioCopy tiene algunas ventajas:<br /><br /><ul><br /><li>Copia hasta 4 archivos simultaneamente (por defecto 2)</li><br /><li>Permite pausar las copias</li><br /><li>Es ligero y consume pocos recursos del computador.</li><br /><li>100% Java. Puede ser ejecutado en cualquier computador con Java 6 o superior</li><br /><li>Codigo Libre. Puedes modificar, contribuir o simplemente curiosear respetando<br />la licencia. Tambies puedes compartirlo con quien quieras.</li><br /><li>Facil de usar. Su interfaz es simple y no tiene menus extravagantes o atajos<br />dificiles de aprender.</li><br /></ul><br />Caracteristicas de la version actual 0.1<br /><ul><br /><li>Hasta 4 copias simultaneas</li><br /><li>Pausado de copia.</li><br /><li>Agregar nuevas pistas a la cola mientras copia.</li><br /><li>Crea carpetas destino segun tags de archivos de audio</li><br /><li>Licencia GPL V2</li><br /></ul><br /><br /> artista/año - album/pista - titulo.extension<br /> Depeche Mode/1997 - Ultra/01 - Barrel of a Gun.mp3<br /><br />Requisitos:<br /><ul><br /><li>Java 1.6 o superior</li><br /></ul><br /><br />Errores conocidos en la version actual.<br /><ul><br /><li>Falla con carpetas de musica demasiado grande</li><br /><li>Se puede cambiar la carpeta origen durante la exploracion, lo que da problemas</li><br /><li>No manipula bien los errores durante la copia (disco lleno, etc.)</li><br /></ul><br />Mejoras proximas:<br /><ul><br /><li>Corregir errores conocidos</li><br /><li>Acelerar la exploracion.</li><br /><li>Recordar carpetas origen (con contenido) y destino.</li><br /><li>Cancelar la copia</li><br /><li>Seleccionr codificacion (ISO/UTF) segun filesystem de carpeta destino</li><br /></ul><br /><br />Posiblemente en un futuro distante:<br /><ul><br /><li>Tooltips y ayudas contextuales</li><br /><li>Informar progreso de copias individuales.</li><br /><li>Editor de tags</li><br /><li>Detectar automaticamente unidades USB</li><br /><li>¿Reproductor? ... por ahora me quedo con <a href="http://jajuk.info/index.php/Main_Page">Jajuk</a></li><br /></ul><br /><br />La version actual puede obtenerse <a href="http://kenai.com/projects/audiocopy">aqui</a>Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com2tag:blogger.com,1999:blog-33500033.post-53203061396106677542009-08-19T09:16:00.005-04:002012-02-06T11:01:31.541-03:00Control y pausa de ciclos for, do, while en JavaUn problema que sucede a menudo cuando se necesita procesar gran cantidad de informacion en un ciclo for o do/while es el de pausar el ciclo, esperar alguna señal y continuar. <br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">for (condicion) {</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> ....hacer algo...</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> ....esperar....</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> ....continuar.....</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">}</span></span><br />
<br />
Por ejemplo, un problema al que me vi enfrentado fue el de ingresar el precio para una gran cantidad de productos, teniendo los productos en un Collection, parecia facil iterar sobre este listado, mostrar una ventana para que el usuario ingresara el precio y continuar:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">Collection<producto> productos;<br />for (Producto p : productos) {<br /> ingresarPrecio(p);<br />}</producto></span></span><producto><br /><br />A primera vista se ve simple, pero si este codigo es ejecutado, su resultado sera abrir tantas ventanas de ingreso como productos tenga el Collection.<br /><br />La forma de ir mostrando las ventanas de forma ordenada, es pausar el ciclo for hasta que la ventana genere algun evento. Para ello lo primero sera hacer correr el ciclo dentro de un <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html">Thread</a> diferente del actual de forma que pueda ser controlado sin interrumpir la ejecucion del programa:<br /></producto><span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><producto>Runnable hiloFor = new Runnable() {<br /><br /> public void run() {<br /> for (Producto p : productos) {<br /> ingresarPrecio(p);<br /> }<br /> }<br />}<br /><br />new Thread(hiloFor).start;</producto></span></span><producto><br /><br />Esto lanzara nuestro ciclo for en un hilo distinto del actual, abriendonos la posibilidad de control. Para ello utilizaremos los metodos proporcionados por la clase <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html">Thread</a>.<br /><br />Lo que haremos a continuacion sera sincronizar el Thread donde vive nuestro ciclo for con el Thread principal donde se enta ejecutando nuestra aplicacion (en el caso de una aplicacion Swing sera el <a href="http://en.wikipedia.org/wiki/Event_dispatching_thread">Event dispatching thread</a><br /></producto><span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><producto>Collection<producto> productos;<br />Thread hilo;<br /><br />Runnable hiloFor = new Runnable() {<br /> <br /> public void run() {<br /> Thread actual = Thread.currentThread();<br /> synchronized(actual) {<br /> for (Producto p: Productos) {<br /> ingresarPrecio(p);<br /> actual.wait();<br /> }<br /> }<br /> }<br />}<br /><br />hilo = new Thread(hiloFor);<br />hilo.start();</producto></producto></span></span><producto><producto><br /><br />Puede notarse de inmediato los cambios introducidos: Primero obtenemos el objeto Thread donde se ejecuta nuestro for y luego ejecutamos el ciclo dentro de un bloque sincronizado con este hilo, invocamos el metodo que abre la ventana y pausamos la ejecucion del hilo.<br /><br />En este punto el hilo donde se ejecuta el ciclo for estara pausado de forma indefinida esperando la señal notify(). Luego el metodo ingresarPrecio(Producto p) debera:<br /></producto></producto><br />
<ul><br />
<li>Abrir la ventana para ingresar el precio en el event dispatching thread</li>
<br />
<li>Notificar al hilo que puede continuar una vez se haya hecho el ingreso</li>
</ul>
<br /><br />Para ello, bastara que el metodo ingresarPrecio(Producto p) incluya en su interior algo similar a:<br /><br /><br /><span style="font-family: "Courier New", "Courier", monospace;"><span style="font-size: x-small;">ingresarPrecio(final Producto p) {<br /> Runnable abrir = new Runnable() {<br /><br /> public void run() {<br /> VentanaIngreso v = new VentanaIngreso(p);<br /> v.addActionListener(new ActionListener() {<br /> public void actionPerformed(ActionEvent e) {<br /> continuar();<br /> }<br /> });<br /> <br /> }<br /><br /> private void continuar() {<br /> synchronized (hilo) {<br /> hilo.notify();<br /> }<br /> }<br /> }<br /><br /> SwingUtilities.invokeLater(abrir);<br />}</span></span><br /><br />La parte importante aca es el metodo continuar(). Aqui se le dice al hilo que continue ejecutandose. Como puede verse en este sencillo ejemplo, este metodo se llama desde un ActionListener que sera gatillado dentro de la ventana de ingreso ante ciertas acciones (cancelar, grabar el precio, etc).<br /><br />El ejemplo puede mejorarse y extenderse a otras situaciones.<br /><br /><br />Bytes!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com2tag:blogger.com,1999:blog-33500033.post-7453679624624996762009-08-13T09:19:00.003-04:002012-02-08T17:43:09.252-03:00Control de Look and Feel en SwingUn problema recurrente de los usuarios de aplicaciones <br />
creadas en Java es el del look an feel. "No se ve como <br />
si fuera windows" es el tipico comentario de quien usa <br />
una aplicacion Swing en este sistema operativo. Los <br />
usuarios de *nix estan mas acostumbrados a las diferencias <br />
de l&f segun el toolkit de la aplicacion (gtk+, qt, motif.. etc) <br />
y no suelen quejarse tanto.<br />
<br />
Personalmente encuentro horrible el l&f por defecto (metal) <br />
asi que tengo a mano un codigo que selecciona automaticamente <br />
el l&f dependiendo del sistema:<br />
<br />
<br />
----------<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">String jVersion = System.getProperty("java.version");<br />String os = System.getProperty("os.name");<br />String[] ver = jVersion.split("_");</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">if (ver.length > 0) {<br /> String vMajor = ver[0];<br /> Double update = Double.parseDouble(ver[1]);<br /> try {<br /> if ((vMajor.compareTo("1.6.0") > -1 && update >= 10) || (vMajor.compareTo("1.7.0") > -1)) {<br /> UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");<br /> } else {<br /> if (os.toLowerCase().contains("windows")) {<br /> UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");<br /> } else if (os.toLowerCase().contains("linux")) {<br /> UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");<br /> }<br /> } catch (ClassNotFoundException ex) {<br /> Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);<br /> } catch (InstantiationException ex) {<br /> Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);<br /> } catch (IllegalAccessException ex) {<br /> Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);<br /> } catch (UnsupportedLookAndFeelException ex) {<br /> Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);<br /> }<br /> }</span></span><br />
<br />
----------<br />
<br />
El codigo en si es bastante simple:<br />
<br />
- Obtengo la version de la VM de java.<br />
- Obtengo el nombre del sistema operativo.<br />
- Obtengo el numero de actualizacion de la VM.<br />
<br />
Desde el update 10 de la JVM 1.6 se encuentra disponible <br />
el l&f "Nimbus", asi que si nuestra version de JVM es <br />
1.6_10 o superior se selecciona este L&F para la <br />
aplicacion. En caso contrario si el sistema es Windows <br />
se selecciona el L&F de Windows, si el OS es Linux <br />
se selecciona el L&F GTK (como quisiera un l&f QT!!!).<br />
<br />
Si no es posible seleccionar alguno de estos L&F se <br />
mantendra el por defecto (metal).<br />
<br />
Bastara con que este codigo se inserte en el main() de <br />
nuestra aplicacion Swing, antes que se dibuje el primer <br />
JFrame y lo demas sera coser y cantar.<br />
<br />
Esta solucion es muy simple y utiliza las bibliotecas <br />
estandar de la JVM. No obstante podemos extender <br />
las capacidades de L&F de nuestra aplicacion utilizando <br />
la completisima biblioteca <a href="https://substance.dev.java.net/">substance</a>.<br />
<br />
<br />
<br />
<br />
bytes!!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com2tag:blogger.com,1999:blog-33500033.post-54156795979146864062009-08-12T17:46:00.002-04:002012-02-02T10:17:33.137-03:00Moviendo un JScrollPane de forma automatica<span style="font-family: "Arial", "Helvetica", sans-serif;">Uno de los problemas clasicos al tener un JPanel dentro <br />de un JScrollPane es como mover automaticamente la <br />barra de Scroll del JScrollPane. Para ello existe el metodo <br />scrollRectToVisible(Rectangle r) que hara que el o los<br />ScrollBar se desplazen para hacer que el rectangulo indicado <br />sea visible.<br /><br />Hasta aqui la cosa no es muy complicada, pero ¿que ocurre <br />si dentro de nuestro JPanel tenemos uno o mas JPanel <br />anidados? La cosa tiende a complicarse un poco ya <br />que la posicion final de nuestro componente es desconocida <br />para el JScrollPane.<br /><br />Consideremos el siguiente ejemplo:</span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">--------------------<br />JScrollPane scrPane = new JScrollPane();<br />JPanel panelPrincipal = new JPanel();<br />JPanel panelAnidado1 = new JPanel();<br />JPanel panelAnidado2 = new JPanel();<br /><br />JLabel label = new JLabel("....");<br />JTextField txt = new JTextField("......")M<br /><br />panelAnidado2.add(txt);<br />panelAnidado2.add(label)<br /><br />panelAnidado1.add(panelAnidado2);<br />panelPrincipal.add(panelAnidado1)<br /><br />scrPane.setViewportView(panelPrincipal);<br />----------------------</span></span><br />
<br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Si queremos desplazar el JScrollPane hasta la posicion del <br />label o el txt, la primera idea que se nos viene a la cabeza <br />seria:</span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">-------<br />scrPane.scrollRectToVisible(label.getBounds());<br />-------</span></span><br />
<br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Lamentablemente esto no funcionara ya que scrPane solo <br />"sabe de la existencia" de panelPrincipal e ignora su contenido. <br />Por lo tanto lo que debemos hacer es calcular la posicion <br />relativa de label con respecto a panelPrincipal.<br /><br />Para ello, el siguiente codigo de ejemplo puede ser util;</span><br />
<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">-------------<br /><br />//obtengo el padre del label (panelAnidado2)<br />JPanel padre = (JPanel) label.getParent();<br />//Obtengo la posicion del padre<br />Point posPadre = padre.getLocation();<br />//Obtengo el 'padre del padre' (panelAnidado1) y su posicion<br />JPanel padre2 = (JPanel)<br />Point posPadre2 = padre2.getLocation();<br /><br />//Conociendo las posiciones, puedo hacer el calculo<br />Double y = posPadre2.getY() + posPadre1.getY() + label.getLocation.getY();<br /><br /> /*<br /> * la variable y contiene la distancia desde el borde del<br /> * panelAnidado1 hasta el borde del label<br /> */<br />//Creo un punto en la posicon relativa del Label<br /><br />Point relativo = new Point(new Double(posPadre2.getX()).intValue(), y.intValue());<br /><br />//Con este punto relativo puedo crear un rectangulo y desplazar el JScrollPane<br /><br />Rectangle moverA = new Rectangle(relativo, label.getPreferredSize());<br />scrPane.scrollRectToVisible(moverA);<br /><br />---------------</span></span><br />
<br />
<span style="font-family: "Arial", "Helvetica", sans-serif;">Resumen:<br /><br />Como 'panelPrincipal' desconoce la presencia y posicon <br />de label, calculamos la posicion relativa de label con <br />respecto a 'panelPrincipal' en base a la posicion de su padre <br />y cualquier panel previo. Una vez conocida esta posicion <br />relativa, basta desplazar el scrPane hasta un rectangulo <br />ubicado en esta posicion relativa con el tamaño del <br />componente que queremos enfocar.<br /><br /><br />Agregando este codigo a un FocusListener, es facil <br />hacer que el JScrollPane se desplace hasta la posicion <br />del componente que obtiene el foco:</span><span style="font-family: "Arial", "Helvetica", sans-serif;"><br />Ejemplo:</span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">--------------</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">private JScrollPane scroll;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">private Jpanel panel;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">private FocusListener focoDesplazamiento = new FocusAdapter() {<br /><br /> @Override<br /> public void focusGained(FocusEvent e) {<br /> Point posicionScroll = scroll.getLocation();</span></span><span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> Container parent = e.getComponent().getParent();<br /> int y = posicionOpcional.y + parent.getLocation().y;<br /> Point moverA = new Point(posicionScroll.x, y + parent.getHeight());</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> panel.scrollRectToVisible(new Rectangle(moverA, parent.getPreferredSize()));<br /> }<br /> };</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">....</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">{ </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> /*</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> * En alguna parte del codigo, hacemos que el JPanel panel este contenido</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> * dentro del </span></span><span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">JScrollPane scroll</span></span><span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> *</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> */</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> panel = new JPanel();</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> scroll = new JScrollPane(panel);</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> /*</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> * Luego, a todos los componentes que se agregan a panel se les agrega</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> * nuestro FocusListener</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> */</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> JTextField txt1 = new JTextField();</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> txt1.addFocusListener(focoDesplazamiento);</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> panel.add(txt1);</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> ...</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br /></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"> //y asi sucesivamente.</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;">}</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New", "Courier", monospace;"><br />--------------</span></span><br />
<br />
bytes!Anonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-75575204881645563092009-01-22T15:06:00.002-03:002009-01-22T15:09:03.730-03:00BLOG??Veo que por fin la interfaz de Blogspot ha mejorado un poco.<br /><br />Lo suficiente para animarme a escribir de vez en cuando.<br /><br />La vida ya tiene demasiadas interfaces: los mandos de un vehículo, las ventanas de windows, la consola de Linux, la interfaz del celular, el idioma de las mujeres... si a eso sumamos que para escribir idioteces que nadie lee debes entenderte con una interfaz maldita que apenas se entiend, poco ánimo queda de publicar entradas...<br /><br />en fin.. a ver si me hago el animoAnonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0tag:blogger.com,1999:blog-33500033.post-80910730960000250612007-06-05T16:07:00.000-04:002007-06-05T16:08:29.134-04:00returnvolviendo a esto del blog....<br /><br />espero escribir mas seguido, aunque nadie lo leaAnonymoushttp://www.blogger.com/profile/03364206591567109276noreply@blogger.com0