viernes, 28 de diciembre de 2007

Trabajar con Horas en Java

En esta ocasión, voy a escribir sobre el mecanismo que encontré en java, para poder especificar mediante programación, la zona horaria de la JVM.

Todo comienza cuando el mismo software al ser ejecutado en diferentes maquinas, al mismo tiempo, cada una retorna una hora diferente.

La solución a este problema (sin necesidad de alterar la configuración de los servidores) es muy simple: solo basta con tener un pequeño código estático en una clase de nuestro software, donde se indique al objeto TimeZone de java, cual es el TimeZone por defecto que se va a utilizar.... lo más simple es tomar el TimeZone preestablecido y alterarlo para cambiarle el offset respecto a GMT.

A continuación les incluyo un código donde se setea al objeto TimeZone un nuevo objeto SimpleTimeZone que se crea en el momento, al cual se le setea el ID del TimeZone actual, pero se indica en milisegundos el offset con respecto a GMT.

TimeZone actual = TimeZone.getDefault();
int milliseconds = ((Configuration.GMT_OFFSET * 60) * 60) * 1000;
String id = actual.getID();
SimpleTimeZone simpleTimeZone = new SimpleTimeZone(milliseconds,id);
TimeZone.setDefault(simpleTimeZone);

Es una solución muy simple que puede evitar muchos problemas.

Espero les sea útil.
Hasta la proxima!

miércoles, 26 de diciembre de 2007

Internacionalización

Todos nos enfrentamos en algún momento de nuestras carreras con algúna dificultad al momento de trabajar con idiomas que presentan caracteres especiales, y las aplicaciones web son las más propensas a estos inconvenientes.
En cada página con caracteres especiales, no es raro que nos aparezca algún signo de pregunta en lugar de la letra acentuada.

En esta ocasión, veremos como trabajar con una aplicación web publicada en un servidor Tomcat.

Lo más importante es entender que cuando se trabaja con aplicaciones que pueden contener estos caracteres, es importante definir la codificación que se desea utilizar (el encoding), el cual siempre es conveniente que esté en una constante, de modo de poder alterarlo rápidamente sin efectos sobre el código.

Para tener una idea, el idioma español y el portugués, ambos usan un encoding ISO-8859-1, pero ésto no quiere decir que no se pueda utilizar UTF-8. Por experiencia, mi recomendación es que siempre se use UTF-8, dado que soporta a muchos idiomas.

Entonces, que debemos tener en cuenta en una aplicación:

- las páginas enviadas al cliente (ya sea html estatico, o html generado por un jsp) deben indicarle al browser en el cliente, con qué codificación van a trabajar. Y para ésto nunca debe faltar dentro del tag <head> la sigiuente línea:


<meta equiv="Content-Type" content="" charset="<%="Parameters.APP_ENCODING%">">

En el ejemplo anterior, se utiliza una constante de tipo String llamada APP_ENCODING que contiene el encoding a utilizar.

- para los archivos .jsp, también es necesario indicar el encoding con el que se vá a trabajar, y para ésto, es indispensable incluir la siguiente línea:

<%response.setCharacterEncoding(Parameters.APP_ENCODING);%>

Con motivos de simplificar el código, recomiendo que esta linea sea contenida en un jsp que se incluya en todos los demás... nuevamente con el objetivo de no tener que alterar cientos de archivos frente algún cambio de planes.

No debe ser olvidado, el tratado de los archivos XML... éstos también llevan un encoding en su primer línea:

<?xml version="1.0" encoding="UTF-8"?>

Con estos puntos se cubre solo una parte del problema.... es decir, lo que se envía al cliente. Pero una parte no menos importante, consiste en interpretar correctamente del lado del servidor, los datos enviados por el cliente.

Y es en este momento donde hay que hacer una pequeña clase, un filtro, que el servidor web ejecutará cada vez que se envíen datos hacia el servidor. ¿Cómo hacemos esto? incluyendo en el archivo web.xml un filtro:


<filter>
<filter-name>UTF8Filter</filter-name>
<filter-class>com.filters.UTF8Filter</filter-class>
<init-param>
<param-name>requestEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UTF8Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Aquí se indica que se invocará a la clase com.filters.UTF8Filter para procesar los datos. A comtinuación, incluyo el codigo de la clase UTF8Filter:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Filtro para que la aplicación acepte codificación en formato UTF-8
*/
public class UTF8Filter implements Filter {

private String encoding;

/**
* Recogemos el tipo de codificación definido en el web.xml
* Si no se hubiera especificado ninguno se toma "UTF-8" por defecto
*/
public void init( FilterConfig filterConfig ) throws ServletException {
encoding = filterConfig.getInitParameter( "requestEncoding" );
if( encoding == null ) {
encoding = "UTF-8";
}

}

/**
* Metemos en la request el formato de codificacion UTF-8
*/
public void doFilter( ServletRequest request, ServletResponse response, FilterChain fc ) throws IOException, ServletException {
request.setCharacterEncoding( encoding );
fc.doFilter( request, response );
}

public void destroy() {}

}

Y como el ejemplo es en Tomcat, se debe incluir en el archivo server.xml (ubicado en la carpeta conf de tomcat) dentro de la configuración del conector HTTP, el siguiente atributo:

URIEncoding="UTF-8"

Hasta ahora vimos lo básico para poder mostrár caracteres especiales y recibir en el server los datos en la codificación correcta.

Pero aún faltan otros aspectos importantes a tener en cuenta, por ejemplo cómo generar archivos para hacer download o upload de archivos.

Una solución simple a este problema es incluir en el objeto response el seteo del content type indicando el encoding, como se vé en el ejemplo anterior.

response.setContentType("application/x-msdownload;charset="+ Parameters.APP_ENCODING);

Hasta ahora creo que esto es todo. Espero les sea útil.