22 febrero, 2013

Cuidado con yotube.com!

Hace unos instantes, trate de ingresar a youtube. Grande fue mi sorpresa cuando me encontré con esta página:



¡Mich! dije yo... Asi que me puedo ganar un iPad... jejejeje...

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.

La pregunta es ¿cómo llegué ahí? . . .  simple... puse yotube.com en lugar de youtube.com

Ya me parecía extraño que Google estuviera regalando "iMac", "iPads" y "iPhones" . . . si ofrecieran un Nexus... caigo.



bytes!

09 noviembre, 2012

Seleccion de área de una imágen con Java

De 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.

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.

El problema en si no es muy complejo. A grandes rasgos se resume en:

  • Determinar el punto de origen.
  • Determinar el área.
  • Seleccionar el área.


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.

Supongamos que el usuario hace clic en un punto de la imagen que llamaremos pi(xi, yi) y arrastra el mouse hasta un punto que llamaremos pf(xf, yf).

El primer paso consiste en determinar al ancho y alto del área abarcada por el arrastre del mouse.

      ancho = Math.abs(xi - xf);
    alto = Math.abs(yi - yf);


Luego obtenemos una imagen con el área seleccionada. Para ello utilizaremos el metodo getSubimage() de BufferedImage.

     BufferedImage seleccion = imagen.getSubimage(x, y, ancho, alto);

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 RescaleOp.

BufferedImageOp op = new RescaleOp(new float[]{0.5f, 0.5f, 0.5f}, new float[]{0f, 0f, 0f}, null);

Finalmente sobrecargamos el metodo paintComponent() del JPane para que se dibuje la imagen y el área seleccionada.

@Override
public void paintComponent(Graphics gr) {
   Graphics2D g = (Graphics2D) gr;
   super.paintComponent(g);
   if (imagen == null) {
       return;
   }
   if (puntoInicial != null && puntoFinal != null) {
       g.drawImage(imagen, op, 0, 0);
       g.drawImage(getImagenSeleccionada(), x, y, this);
       g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,         RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
       g.setColor(Color.WHITE);
       g.drawRect(x, y, ancho, alto);
       g.drawString("Área: " + ancho + "x" + alto, 10, 20);
   } else {
       g.drawImage(imagen, 0, 0, this);
   }
}


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.

El código es largo y la verdad me da flojera escribirlo todo aca, por eso los ejemplos resumidos.

Por lo mismo, en este enlace 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.



24 octubre, 2012

Modulador de Ancho de Pulso (PWM) en Java

javaPWM.png


JavaPWM es una sencilla aplicación que permite convertir cualquier PC con un puerto serial en un modulador de ancho de pulso (PWM).

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:

(originalmente publicada en http://www.windmeadow.com/node/4)

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.

El ciclo de trabajo (duty cycle) puede variar entre 1 y 99%. 

En modo oscilador (continuo) la frecuencia puede variar entre 1 y 50 Hz.

En modo pulso, el pulso puede durar entre 1 y 100 segundos.

El modo "off/on" invierte el ciclo.

Requiere Java 6 o superior y la biblioteca rxtx correctamente instalada o configurada.

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.

Para descargar la aplicación clic aqui. Es totalmente gratuita!
El codigo fuente se puede descargar desde aca.

Si te sirve, te gusta o tienes alguna sugerencia, tu comentario es bienvenido.



24 septiembre, 2012

Algunos 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".

Es muy útil en algunos casos, explorar un objeto en tiempo de ejecucion para conocer sus métodos y atributos.

He aqui algunos tips básicos para iniciarse con reflexión.

Clase: Class

La clase Class 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.

Clase: Constructor

La clase Constructor proporciona informacion de y acceso a un constructor de una clase.

Clase: Method

La clase Method proporciona información de y acceso a un método de una clase.

Clase: Field

La clase Field proporciona información de y acceso a un atributo de una clase.


Hay mucho más, pero estos simples conceptos son suficientes para comenzar.

Tomemos como ejemplo, la siguiente clase, la cual nos servirá para explorar un poco de la API java.lang.reflect:

public class Clase {

private String atributo;

public Clase() {
}

public Clase(String atributo) {
    this.atributo = atributo;
}

public String getAtributo() {
    return atributo;
}

public void setAtributo(String atributo) {
    this.atributo = atributo;
}

public void verAtributo() {
    System.out.println("El valor del atributo es: " + atributo);
}

public void metodo() {
    System.out.println("Este es el metodo.");
}

public void metodo(String parametro) {
    System.out.println("Este es el metodo con parametro. El parametro fue: " +       parametro);
}

public static void estatico() {
    System.out.println("Este es el metodo estatico.");
}

public static void estatico(String parametro) {
    System.out.println("Este es el metodo estatico con parametro. El parametro       fue: " + parametro);
}
}


Examinando esta clase, vemos que posee las siguientes características:


  • Un atributo de tipo String.
  • Un constructor sin parámetros.
  • Un constructor que recibe un parámetro de tipo String.
  • Un métod getter para el atributo.
  • Un método setter para el atributo.
  • Un método sin parámetros que imprime un texto en consola.
  • Un método con un parámetro String que imprime un texto en consola.
  • Un método estático sin parámetros que imprime un texto en consola.
  • Un método estático con parámetros que imprime un texto en consola.
Esto es fácil, porque estamos viendo el código fuente de la clase, pero podemos examinarla completamente usando un programa en java.

Lo primero es obtener una instancia de Class.

    Class c = Class.forName("paquete.Clase")
    Class c = Clase.class

Puede ser por el nombre completo de la clase (incluyendo el paquete), o bien invocando directamente el atributo class que toda clase Java tiene.

El siguiente código instancia una clase por su nombre e imprime el nombre de la clase en pantalla:


    Class c = Class.forName("paquete.Clase");
    System.out.println("Clase instanciada: " + c.getName());


La ejecución de este código dará como resultado lo siguente:

    run:
    Clase instanciada: paquete.Clase


Teniendo una instancia de la clase, podemos comenzar a explorarla:

El siguiente código permite obtener los constructores de la Clase:

System.out.println("\nConstructores de la clase:");
Constructor[] cons = c.getConstructors(); //c.getDeclaredConstructors();
for (Constructor co : cons) {
   System.out.println("Constructor : " + co.getName());
   Class[] param = co.getParameterTypes();
   if (param.length == 0) {
      System.out.println("\tConstructor sin parámetros.");
   } else {
      for (Class p : param) {
         System.out.println("\tParametro: " + p.getName());
      }
   }
}


La ejecución del código anterior dará como resultado:


Constructores de la clase:
Constructor : paquete.Clase
     Constructor sin parámetros.
Constructor : paquete.Clase
     Parametro: java.lang.String

Si se nota, ya esposible obtener información de la clase. En este caso el método c.getConstructors() nos permite obtener todos los constructores de la clase. Su hermano c.getDeclaredConstructors() nos permite obtener los constructores que fueron declarados específicamente en la clase que estamos explorando (útil cuando una clase hereda de otra).

Exploremos ahora los atributos que posee la clase:

System.out.println("\nAtributos de la clase:");
Field[] fields = c.getFields();
for (Field f : fields) {
   System.out.println("Atributo: " + f.getName());
   System.out.println("\tTipo del Atributo: " + f.getType().getName());
}



La ejecución del código anterior dará como resultado:


   Atributos de la clase:


En este caso, no hay nada. ¿Por qué? 

Si miramos el código de la clase, veremos que contiene un único atributo de tipo private por lo que no es visible fuera de la clase. Si agregamos el siguiente atributo:


   public String atributoPublico;


Y ejecutamos el código, veremos lo siguiente.


Atributos de la clase:
Atributo: atributoPublico
   Tipo del Atributo: java.lang.String



Ahora exploremos los métodos. El siguiente código muestra los métodos de la clase:


System.out.println("\nMetodos de la clase: ");
Method[] metodos = c.getMethods();
for (Method m : metodos) {
   System.out.println("Metodo: " + m.getName());
   Class[] param = m.getParameterTypes();
   if (param.length == 0) {
      System.out.println("\tEl método no acepta parametros.");
   } else {
      for (Class p : param) {
         System.out.println("\tParametro: " + p.getName());
      }
   }
}


El cual, al ser ejecutado mostrará:


Metodos de la clase:
Metodo: getAtributo
   El método no acepta parametros.
Metodo: setAtributo
   Parametro: java.lang.String
Metodo: verAtributo
   El método no acepta parametros.
Metodo: metodo
   El método no acepta parametros.
Metodo: metodo
   Parametro: java.lang.String
Metodo: estatico
   El método no acepta parametros.
Metodo: estatico
   Parametro: java.lang.String
Metodo: wait
   Parametro: long
Metodo: wait
   Parametro: long
   Parametro: int
Metodo: wait
   El método no acepta parametros.
Metodo: equals
   Parametro: java.lang.Object
Metodo: toString
   El método no acepta parametros.
Metodo: hashCode
   El método no acepta parametros.
Metodo: getClass
   El método no acepta parametros.
Metodo: notify
   El método no acepta parametros.
Metodo: notifyAll
   El método no acepta parametros.


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 getMethods(), 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). 


Si en lugar de getMethods() usamos getDeclaredMethods(), obtendremos el siguiente resultado:

Metodos de la clase:
Metodo: getAtributo
   El método no acepta parametros.
Metodo: setAtributo
   Parametro: java.lang.String
Metodo: verAtributo
   El método no acepta parametros.
Metodo: metodo
   El método no acepta parametros.
Metodo: metodo
   Parametro: java.lang.String
Metodo: estatico
   El método no acepta parametros.
Metodo: estatico
   Parametro: java.lang.String



Pero ésto sólo nos proporciona información de una clase. Ahora pasaremos a la acción.


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.

Object o = c.newInstance();
Object o2 = c.getConstructor(String.class).newInstance("Instancia 2");

System.out.println("Instacia o de Clase: " + o);
System.out.println("Instancia o2 de Clase: " + o2);


La ejecución del código anterior dará como resultado:

Instacia o de Clase: paquete.Clase@62f72617
Instancia o2 de Clase: paquete.Clase@4fe5e2c3


En el primer caso, la llamada del método newInstance() llama directamente al contructor sin parámetros. 

Para invocar la llamada al constructor con parámetros, invocamos el método getConstructor() y le entregamos como parámetro String.class. Literalmente le estamos diciendo: "Dame el constructor que recibe como parámetro un String".


Al constructor retornado le invocamos el método newInstance() y le pasamos como parámetro un String.


Ejercicio: Intentar construir la instancia o2, pasándole un Integer (u otro). Tendremos una linda excepción.

Ahora vamos a invocar el método para ver el valor del atributo:

Method verAtributo = c.getDeclaredMethod("verAtributo", null);
verAtributo.invoke(o, null);
verAtributo.invoke(o2, null);



Puede observarse que el código en si es simple. A la clase le pedimos el método llamado verAtributo que no tiene parámetros.


Luego, invocamos el método mediante invoke(), y le pasamos como parámetro la instancia 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:

El valor del atributo es: null
El valor del atributo es: Instancia 2


Lo cual es correcto, ya que al momento de instanciar, sólo declaramos el atributo en la instancia 2.

Invoquemos un método con parametros.

  Method setAtributo = c.getDeclaredMethod("setAtributo", String.class);
  setAtributo.invoke(o, "Un parámetro");


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.

Si volvemos a invocar el método verAtributo en la instancia o, veremos el siguiente resultado:

El valor del atributo es: Un parámetro

Finalmente, invocaremos un método estático con parámetros.

Method estatico = c.getDeclaredMethod("estatico", String.class);
estatico.invoke(null, "¡Es un método estático!");


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:

Este es el metodo estatico con parametro. El parametro fue: ¡Es un método estático!

Como puede verse, la API de reflexión es muy potente y trabajando en conjunto con Interfaces y Generics 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.

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.

Archivos: Clase.java Reflexion.java

Salu2!!!

17 mayo, 2012

Tratamiento de ResultSet con multiples hilos

Aunque el título de la entrada no es el mas adecuado, la implementación de esta técnica permite procesar aparentemente un ResultSet con múltiples hilos.

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 thread-safe, es decir, no puede se accedido desde múltiples hilos a la vez.

Por lo tanto, un escenario como el que se ilustra abajo es técnicamente imposible:




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.

Una solución simple, es almacenar los datos en un objeto que actúe como buffer 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 buffer, y por otro lado a varios hilos que leen los datos de este buffer y los procesan en forma paralela.

Se llega a un escenario más cómodo, que permite el uso de múltiples hilos para el procesamiento de nuestros datos:



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. 

La secuencia sería más o menos así:
  • Obtener el ResultSet
  • En un hilo, leer el ResultSet, crear los Beans de Datos y llenar el buffer.
  • Lanzar uno o varios hilos que lean el buffer.
Adicionalmente se necesitan algunos mecanismos de control para:
  • Ganatizar que el Buffer no crezca descontroladamente.
  • Asegurar que los hilos de proceso se esten ejecutando hasta que se haya leido completamente el ResultSet.
  • No continuar hasta que todos los hilos de proceso hayan terminado (este paso puede ser opcional).

Existen muchas formas de implementar esta lógica. Aqui propongo una simple, que puede ser mejorada en gran medida.

Primero: Definimos una clase que actue como "Bean" de datos:

class Bean {
        
        private String dato1;
        private String dato2;
        private String dato3;

        public String getDato1() {
            return dato1;
        }

        public void setDato1(String dato1) {
            this.dato1 = dato1;
        }

        public String getDato2() {
            return dato2;
        }

        public void setDato2(String dato2) {
            this.dato2 = dato2;
        }

        public String getDato3() {
            return dato3;
        }

        public void setDato3(String dato3) {
            this.dato3 = dato3;
        }
        
    }

Luego, definimos una clase donde se hará el proceso:



class Proceso {
    
    private static final int MAXIMO_BUFFER = 10;
    private static final int MAXIMO_HILOS_PROCESO = 5;
    private ResultSet rs;
    private Thread[] hilosProceso;
    private volatile boolean leyendoRs;
    private LinkedBlockingQueue buffer;

    /**
     * Este metodo debe ser lanzado desde un hilo que no sea el 
     * event-dispatch-thread
     */
    public void procesar() throws SQLException {
        buffer = new LinkedBlockingQueue();
        hilosProceso = new Thread[MAXIMO_HILOS_PROCESO];
        rs = leerBaseDatos();
        leyendoRs = true;
        Runnable proceso = new Runnable() {

            @Override
            public void run() {
                while (true) {
                    Bean b = buffer.poll();
                    if (b == null) {
                        if (leyendoRs) {
                            try {
                                Thread.sleep(250);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        } else {
                            break;
                        }
                    } else {
                        //Hacer algo con Bean b
                    }
                }
            }
        };
        for (int i = 0; i < MAXIMO_HILOS_PROCESO; i++) {
            hilosProceso[i] = new Thread(proceso, "Hilo Proceso " + i);
            hilosProceso[i].start();
        }
        
        while (rs.next()) {
            Bean b = new Bean();
            b.setDato1(rs.getString("dato1"));
            b.setDato2(rs.getString("dato2"));
            b.setDato3(rs.getString("dato3"));
            buffer.offer(b);
            if (buffer.size() >= MAXIMO_BUFFER) {
                try {
                    Thread.sleep(250);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
        rs.close();
        leyendoRs = false;
        
        for (Thread hilo : hilosProceso) {
            if (hilo.isAlive()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
        
        
        /*
         * En este punto estamos completamente seguros de que 
         * todos los datos han sido procesados.
         * 
         */
    }

}

Como puede verse, la clase que procesa los datos es bastante simple. Utilizamos como buffer la clase LinkedBlockingQueue que permite un acceso concurrente a los metodos offer() y poll(). 

Obetenemos los datos con algún método a nuestro gusto, y luego levantamos un flag que indica que estamos leyendo los datos. 

Utilizamos la interfaz Runnable 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 true, 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.

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 LinkedBlockingQueue (se me estaban perdiendo datos). Cuando termina el ciclo de lectura del ResultSet, el flag de lectura se lleva a false, lo que indica a los hilos de proceso que ya no habrá mas datos para procesar.

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.

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 ;-)


bytes!




13 marzo, 2012

Actualización de la zona horaria en Java

Hasta que pasó... llegó el día del cambio de hora, pero se decidió aplazarlo hasta el 28 de abril.

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.

Pero ¿que es lo que pasa?

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.

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.

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.

Es decir: Hora de Chile continental  = Hora GMT/UTC - 4.

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.

O sea: Hora de Chile continental  = Hora GMT/UTC - 4 +- DST.

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.

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.

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:

Hora UTC: 16:00
Hora Chile Continental: 13:00
Hora PC: 13:00
Hora Java: 12:00

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.

Se puede corregir de varias formas:

  • Mover la zona horaria del computador o cambiar la hora manualmente.
  • Actualizar la versión de Java.
  • Corregir la información de zona horaria de Java.
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.

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.

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.

La información de zona horaria se encuentra en:

JAVA_HOME/lib/zi

Por lo tanto es posible sobreescribir la informacion de zona horaria con la de una versión actualizada.

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.

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.

Opciones y soluciones hay... la proxima vez no tendremos problemas con el cambio de horario.


bytes!

06 febrero, 2012

Agregar Texto en color a un JTextPane

De vez en cuando se me ha hecho necesario utilizar un JTextPane 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.



Para ello se puede utilizar la clase StyledDocument de Java que permite definir algunas caracteristicas del texto que se insertará en el JTextPane


Sin más, he decidido crear una clase que extienda de JTextPane y que proporcione los métodos que necesito:



public class Consola extends JTextPane {



    public void append(Color color, String texto) {
        StyledDocument doc = getStyledDocument();
        Style syle = doc.addStyle("txt", null);
        StyleConstants.setForeground(syle, color);
        try {
             doc.insertString(doc.getLength(), texto, syle);
             setCaretPosition(doc.getLength());
         } catch (BadLocationException ex) {
             ex.printStackTrace();
         }
    }



    public void appendRed(String texto) {
        append(Color.RED, texto);
    }


    public void append(String texto) {
        append(Color.BLACK, texto);
    }


}



Una solución simple que puede ser de gran utilidad. Jugando un poco con las clases StyledDocument, Style y StyleConstants pueden obtenerse resultados muy interesantes.





bytes!

02 febrero, 2012

JTextArea transparente en Look & Feel Nimbus

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 setOpaque(false).


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.


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.


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:




textArea.setBorder(BorderFactory.createEmptyBorder()); 

textArea.setBackground(new Color(0, 0, 0, 0));




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.







30 noviembre, 2011

Respaldo rápido de un disco duro en UNIX con dd

dd 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.

El uso básico de dd es:

$dd if={archivo_de_entrada} of={archivo_de_salida} bs={tamaño_bloque}

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.

Por ejemplo, una copia de disco a disco podría ser:

$dd if=/dev/hda of=/dev/sda bs=4096

También es posible usar un archivo de imagen:


$dd if=/dev/hda of=./imagen.img bs=4096 conv=noerror

El parametro conv=noeeror indica que continúe si se presenta un error de lectura.
Especificamos un tamaño de bloque de 4k para hacerlo más tolerante a errores de lectura.

Otra forma es utilizarlo en conjunto con gzip para hacer copias de respaldo comprimidas:

$dd if=/dev/hda conv=noerror bs=4k | gzip -c > ./imagen.img.gz


O con gunzip para restaurar las imágenes de respaldo

$gunzip -z ./imagen.img.gz | dd of=/dev/hda bs=4k conv=noerror


Si se quiere monitorear el estado de copia, se le puede enviar la señal USR1 al PID del comando. 

$kill -USR1 {PID_DE_dd}

Obviamente hay muchas más opciones, que pueden ser investigadas en el manual de dd


$man dd


30 agosto, 2011

Recorriendo Vectores gigantes con multiples hilos

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 contains(Object o) aplicado a una Collection puede ser suficiente, pero hay ocasiones en las que incluso esto no es bastante.
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 contains().
El problema fundamental en este caso era que la comparación no se hacía directamente con un metodo equals() 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.
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 for utilizado podía ser realmente demoroso.
Lugo de pensarlo un poco, llegué a una solución bastante aceptable, aprovechando las características multi hilo de Java.
La solución en si es simple: divide y vencerás. 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.


Visto paso a paso:


  1. Establezco un tamaño de bloque. Por ejemplo 100 unidades. Cada hilo hará la búsqueda sobre este número de datos.
  2. 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.
  3. Preparo un espacio para que cada hilo notifique que ha terminado sin encontrar resultados.
  4. Preparo un boolean para indicar que el dato fue encontrado.
  5. Lanzo hilos de busqueda.
  6. Espero...

La implementacion mas simple de esta algoritmo, podria hacerse asi:

public class Buscador  {

    private static final int TAM_BLOQUE = 100; //Tamaño del bloque
    private static Logger logger = Logger.getLogger(Buscador.class.getName()); 
    private boolean encontrado;                //Indica que el dato fue encontrado
    private List datos;                  //Donde se hara la busqueda
    private Map flags;       //Donde cada hilo indica que termino
    private Resultado resultado;               //El dato que fue encontrado 

    public  Buscador(List datos) {
         this.datos = datos;
     }

    /**
     * Este metodo debe ser lanzado desde un hilo, no desde el event-dispatch 
     * thread ya que si no bloqueara la GUI
     *
     */ 
    public Resultado buscar(Muestra muestra) {
        if (datos == null || datos.isEmpty()) {
            return null;
        }
        //Sincronizo los datos para buscar desde muchos hilos 
        List vector = Collections.synchronizedList(datos);
        int bloques = datos.size() / TAM_BLOQUES;
        if (bloques < 1) {
            bloques = 1;
        }
        flags = Collections.synchronizedMap(new HashMap(bloques)); 
        final int largoSegmento = t / bloques;
        encontrado = false;

        resultado = null;
        /*
         * Este es el punto donde se lanzan los hilos de busquedas. Aprovechamos 
         * las caractristicas de las clases anonimas y el metodo sleep() de la 
         * clase Thread. Por eso este metodo debe lanzarse desde un hilo en 
         * segundo plano. 
         */ 
         for (int hilo = 1; hilo <= bloques; hilo++) {
             final int nHilo = hilo;  //Lo hacemos final para usarlo en la clase anonima
             flags.put(nHilo, false); //El hilo aun no termina
             Runnable busqueda = new Runnable() {

                 public void run() {
                     //Desde donde y hasta donde debe buscar este hilo 
                     int desde = desde = (nHilo - 1) * largoSegmento;
                     int hasta = largoSegmento * nHilo;

                     /*
                      * Instancia del verificador. Es propia de cada clase,  
                      * para asi evitar colisiones entre los hilos
                      */
                      Verificador v = Verificador.newInstance();
                      for (int k = desde; k < hasta; k++) {
                          if (encontrado) {
                              logger.debug("Hilo " + nHilo + ": Otro hilo encontro el registro :(");
                              marcarfin();
                              return;
                          }

                          Object dato = vector.get(k);
                          //Realiza la verificacion. . .. bla bla bla 
                          v.verificar(dato, muestra); 
                          if (v.esValido()) {
                              logger.debug("Hilo " + nHilo + ": Encontre el registro! :D");
                              encontrado = true;

                              resultado = v.getResultado();
                              marcarfin();
                              return; 

                          } 
                      } 
                      logger.debug("Hilo " + nHilo + ": Finalizo sin encontrar registro :(");
                      marcarfin(); 

                 }
                 
                 /**
                  * Coloca en el mapa la marca de que este hilo ya temino.
                  */ 
                 private void marcarfin() {
                     flags.put(nHilo, true);
                 } 

             };
             new Thread(busqueda, "Hilo de busqueda " + hilo).start();
         } 
         while (!encontrado && !finalizado()) {
             try {
                 Thread.sleep(500L);
             } catch (InterruptedException ex) {
                 //algo con la excepcion
             }
          }
         return resultado; 

    } 


    /**
     * Verifica que todos los hilos hayan finalizado. 
     */ 
    private boolean finalizado() {
        for (boolean hiloFinalizado : flags.values()) {
            if (!hiloFinalizado) {
                return false;
            }
        }
        return true;
    } 





 A simple vista puede verse algo confuso, pero si examina con detencion, puede verse que el truco se encuentra dentro del ciclo for. 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.

Cada hilo realiza la búsqueda en su espacio asignado dentro del gran vector. 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.

Obviamente los valores aqui expresados son para ejemplo, quiza puedan modificarse los valores para ajustarse a un escenario más real. La clase Verificador 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 Generics en el buscador y hacer otras mejoras como eliminar el boolean "encontrado".

También puede limitarse el número de hilos lanzados aplicando un mecanismo de pausa y espera  para el control de los hilos y varias mejoras más que se me van ocurriendo.

Actualmente esta implementación está funcionando perfectamente y mis usuarios no han vuelto a quejarse por lentitud.

=)