El extraño bug del Calendar

Publicado en Java el 4 de March, 2010 por Lek. (7 comentarios)

Cuando empezaba a programar con C y C++ recuerdo los quebraderos de cabeza para comprobar que los valores “entraban” dentro de las variables y evitar desbordamientos problemáticos. Java solucionó esto haciendo que, si el valor se pasaba del rango de la variable, se reiniciaba el contador. Es decir, que si queremos poner el valor 212 a un fichero byte (-128 a 127), Java nos muestra en realidad -44.

Esto, que en principio puede parecer un gran avance porque evita problemas de seguridad en los programas (uno de los motivos por los que en Java no se pueden manejar punteros), al final se demuestra que es un nido de bugs. Porque 212 no son -44. Y esto puede ser un auténtico problema en algo tan visible como una fecha.

El mes de marzo es un mes muy especial. Su mes anterior es de longitud variable (28 ó 29 días) y el siguiente es de 30, siendo el propio marzo de 31. Ved el siguiente código:

Calendar cal = new GregorianCalendar();
cal.set (Calendar.DAY_OF_MONTH, 30);
cal.set (Calendar.MONTH, 2);
System.out.println (cal.getTime ());
System.out.println (cal.getActualMaximum (Calendar.DAY_OF_MONTH));
cal.set (Calendar.MONTH, cal.get(Calendar.MONTH) -1);
System.out.println (cal.getActualMaximum (Calendar.DAY_OF_MONTH));

Esencialmente, lo que hace es ponernos en 30 de marzo de este año y sacar por pantalla los siguientes datos:

  • Fecha actual
  • Número de días del mes de marzo
  • Número de días del mes de… ¿febrero?

Java, en su excelsa sabiduría, ha decidido que en este caso que 2-1=2. Porque al restar uno al mes nos quedamos en 30 de febrero o, lo que es lo mismo, 2 de marzo. Esta chorrada (obviamente en un código más complejo) nos tuvo en el trabajo una mañana entretenidos porque el número de días de los meses siempre eran 30 ó 31, incluído un inexistente febrero.

En parte fue una suerte que estuviéramos a 30 de marzo y no en 2 de abril, en cuyo caso nos daríamos cuenta del problema casi un año después de sacar el proyecto a producción. A veces Java es realmente odioso con su “deja que la JVM piense por ti“.

Cómo proteger las contraseñas de los usuarios

Publicado en Java, Seguridad el 22 de November, 2009 por Fran. (17 comentarios)

Voy a recuperar otro de mis documentos perdidos en Google Docs (el anterior fue el de las autotools), esta vez se trata de un pequeño manual sobre cómo proteger las contraseñas de lo usuarios de cualquier aplicación que se programe, el manual es una traducción al español del artículo How to encrypt user passwords de Daniel Fernandez.

1. Visión general

Casi todas las aplicaciones web modernas necesitan, de un modo u otro, cifrar las contraseñas de sus usuarios. Se podría decir que, desde el momento en que la aplicación tiene usuarios, y los usuarios se identifican usando una contraseña, esas contraseñas se deben guardar usando algún tipo de cifrado.

Hay muchas razones básicas para esto: las bases de datos pueden estar comprometidas, y por tanto también las comunicaciones. Pero la razón más importante es que se tiene que pensar que las contraseñas de los usuarios son datos personales. Sus contraseñas son sus claves para su privacidad, por tanto son personales, y nadie tiene el derecho de conocerlas. Y se debe cumplir esto si se quiere ganar la confianza de los usuarios.

Leer el resto »

Internacionalización en Java usando UTF-8

Publicado en Java el 23 de October, 2009 por Fran. (1 comentario)

Una de las bondades de Java es que trae un montón de clases que hacen de todo, incluso internacionalización, es decir, poder traducir nuestra aplicación para que se muestre en el idioma adecuado para el usuario.

Si alguna vez habéis necesitado internacionalizar en Java, os habréis encontrado con la clase ResourceBundle, esta clase permite la traducción a partir de un archivo tipo properties (que se basa en líneas campo = valor).

Lo malo es que Java trata estos archivos properties utilizando la codificación ISO-8859-1, de modo que si utilizas un archivo properties guardado en UTF-8 algunos símbolos (por ejemplo: la eñe) se mostrarán de forma incorrecta. Para solucionar este problema, se debe usar el siguiente truco:

import java.io.UnsupportedEncodingException;
import java.util.ResourceBundle;

public class UTFi18n {

    // Messages es el nombre del archivo que contiene los mensajes traducidos
    private ResourceBundle messages =  ResourceBundle.getBundle ("Messages");

    public static String getMessage (String message) {

        String value = messages.getString (message);
        String ret;

        try {
            // Hack to manage properties files using UTF-8
            ret = new String (value.getBytes ("ISO-8859-1"), "UTF-8");

        } catch (UnsupportedEncodingException encEx) {
            ret = value;
        }

        return ret;
    }
}

Basado en Quick and Dirty Hack for UTF-8 Support in ResourceBundle de Thoughts About.

Los problemas de la clase JSObject

Publicado en Java, JavaScript el 19 de October, 2009 por Fran. (Sin comentarios)

Como los applets se ejecutan dentro de una página web, se creó un mecanismo (llamado LiveConnect) para comunicarse con el navegador mediante JavaScript, es decir, poder ejecutar JavaScript desde el applet.

Este mecanismo ofrece una clase llamada JSObject que permite realizar la comunicación del applet a JavaScript, esta clase se localiza en el paquete netscape.javascript.

Lo malo es que esta clase tiene varios problemas y fallos relacionados que no vienen documentados en ningún sitio, sólo en algunas páginas de gente que ha conseguido averiguarlos por su cuenta.

Leer el resto »

Applet-fu insertando fácilmente los applets en (X)HTML

Publicado en (X)HTML, Java, JavaScript, Recursos el 1 de October, 2009 por Fran. (Sin comentarios)

Sigo pesado con los applets, esta vez porque he descubierto un script de JavaScript (applet-fu) que permite insertar los applets en (X)HTML de manera sencilla y evitando tener que preocuparte si será compatible con IE o cumplirá los estándares (X)HTML.

A costa de unos cuantos KB del script de JavaScript que hay que incluir en el (X)HTML, se pueden insertar applets con el siguiente código:

<script type="text/javascript" language="javascript" charset="utf-8">
    applet_fu.run (
        // Atributos del elemento (X)HTML (como object)
        { 'width'  : '0',
          'height' : '0',
          'name'   : 'applet',
          'id'     : 'applet' },
        // Parámetros del applet
        { 'archive' : 'applets/Applet.jar',
          'code' : 'es.4bits.Applet' },
        // Versión de Java necesaria
        '1.6',
        // Mensaje mostrado si no se encuentra la versión de Java
        '<p>No se ha encontrado la versión de Java necesaria.</p>'
    );
</script>

Además, este código ofrece mediante el mecanismo del navegador utilizado la posibilidad de descargar Java si no se ha encontrado o si tiene una versión distinta a la necesaria.

Sun ofrece algo parecido llamado Java Deployment Kit, pero ocupa más, sólo por realizar más tareas como la posibilidad de usar Java Web Start.

Dejo el enlace a su repositorio en github, para quién lo quiera descargar: código de applet-fu.