lunes, 14 de septiembre de 2009

Validar y formatear fechas

Esta publicación está hecha en base a un error muy común al momento de validar una fecha.

Generalmente se utiliza la clase SimpleDateFormat para validar o formatear una fecha, como se muestra a continuación:

Para formatear:


import java.text.SimpleDateFormat;
import java.util.Date;

public class EjemploFecha {
public static void main(String[] args) {
Date fechaActual = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String fecha = dateFormat.format(fechaActual);
System.out.println("Fecha actual: "+fecha);
}
}


El resultado que entrega la ejecución de la clase anterior sería algo asi:

Fecha actual: 17/09/2009


Para validar:


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class EjemploFecha {
public static void main(String[] args) {
try {
String fechaStr = "13/02/2009";
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date fecha = dateFormat.parse(fechaStr);
System.out.println("Fecha válida: "+fecha.toString());
} catch (ParseException e) {
System.out.println("Fecha no válida");
}
}
}


El resultado que entrega la ejecución de la clase anterior sería algo asi:

Fecha válida: Fri Feb 13 00:00:00 GMT-04:00 2009

Lo anterior se ve perfecto, excepto si cambiamos la fecha de entrada, ahora pondremos una fecha no válida (32/02/2009) y el resultado es el siguiente:

Fecha válida: Wed Mar 04 00:00:00 GMT-04:00 2009

Esto sucede porque la implementacón del método parse no es estricta al formato, esto significa que infiere una posible fecha. En el ejemplo anterior verifica que febrero tiene 28 días y que se le informan 32, por tanto deduce que son 4 días del mes de marzo, entregando como resultado 4 de Marzo. Para evitar este error y restringir la validación al formato especificado sin cambiar la fecha ingresada, se debe indicar explícitamente con el método setLenient como se muestra a continuación:


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class EjemploFecha {
public static void main(String[] args) {
try {
String fechaStr = "32/02/2009";
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
dateFormat.setLenient(false);
Date fecha = dateFormat.parse(fechaStr);
System.out.println("Fecha válida: "+fecha.toString());
} catch (ParseException e) {
System.out.println("Fecha no válida");
}
}
}

El resultado de lo anterior sería:

Fecha no válida

Ha tener cuidado con la api :P

jueves, 3 de abril de 2008

Transferencia de archivos con SCP y JAVA

Este es un tutorial que permite a programadores en Java la transmisión de archivos mediante Conexión SCP (Protocolo de copia segura). A continuación vamos a describir los pasos para lograrlo.

Primero: Obtener la librería j2ssh

j2ssh-core.jar

URL de descarga: http://sourceforge.net/project/showfiles.php?group_id=60894

Segundo: Crear una clase para la conexión

Es conveniente crear una clase que se encargue de la conexión y transmisión de archivos mediante j2ssh.


package cl.miapp.scp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;

import com.sshtools.j2ssh.ScpClient;
import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient;
import com.sshtools.j2ssh.transport.IgnoreHostKeyVerification;
import com.sshtools.j2ssh.transport.publickey.SshPrivateKey;
import com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile;

public class SecureScpBanco {
private SshClient ssh;
private PublicKeyAuthenticationClient pass;
private String hostname;
private String user;
public SecureScpBanco(String hostname, String login){
ssh = new SshClient();
this.hostname = hostname;
user = login;
pass = new PublicKeyAuthenticationClient();
}
public void sendFile(InputStream f, long size, String nombreLocal,
String nombreRemoto) throws ConnectException{
try {
ssh.connect(hostname, new IgnoreHostKeyVerification());
pass.setUsername(user);
String keyfile = "/ruta/archivo/claveprivada/id_rsa";
String passphrase = "";
SshPrivateKeyFile file = SshPrivateKeyFile.parse(new File(keyfile));
SshPrivateKey key = file.toPrivateKey(passphrase);
pass.setKey(key);
int ret = ssh.authenticate(pass);
if(ret == 4) {
ScpClient scpClient = ssh.openScpClient();
scpClient.put(f, size, nombreLocal, nombreRemoto);
ssh.disconnect();
} else throw new ConnectException("Error en la autenticacion de usuario");
} catch(IOException e) {
e.printStackTrace();
throw new ConnectException("No se pudo conectar al Servidor = " + hostname);
}
}

public boolean getFile(OutputStream destino, String ruta_origen)
throws ConnectException{
try{
ssh.connect(hostname, new IgnoreHostKeyVerification());
pass.setUsername(user);
String keyfile = "/ruta/archivo/claveprivada/id_rsa";
String passphrase = "";
SshPrivateKeyFile file = SshPrivateKeyFile.parse(new File(keyfile));
SshPrivateKey key = file.toPrivateKey(passphrase);
pass.setKey(key);
int ret = ssh.authenticate(pass);
if(ret == 4){
ScpClient scpClient = ssh.openScpClient();
InputStream stream = scpClient.get(ruta_origen);
BufferedInputStream bis = new BufferedInputStream(stream);
BufferedOutputStream bos = new BufferedOutputStream(destino);
byte data[] = new byte[8024];
int contador;
while((contador = bis.read(data, 0, 8024)) != -1)
bos.write(data, 0, contador);
ssh.disconnect();
return true;
} else{
throw new ConnectException("Error en la autenticacion de usuario");
}
}catch(IOException e){
e.printStackTrace();
}catch(Throwable ex){
ex.printStackTrace();
}
throw new ConnectException("Error de Entrada/Salida");
}
}


Tercero: Crear el Main

Con la clase creada anteriormente se simplifican mucho las cosas, ahora sólo hay que utilizarla de la siguiente forma:


import java.io.FileOutputStream;
import java.io.File;
import java.io.FileInputStream;
import cl.miapp.scp.SecureScpBanco;

public class TestMain{
public static void main(String []args) throws Exception {
FileOutputStream out = new FileOutputStream("nuevoArchivoLocal.txt");
SecureScpBanco scpBco = new SecureScpBanco("miHostRemoto", "miUsuarioRemoto");
if(scpBco.getFile(out, "/path/miArchivoRemoto.txt")){//ok
System.out.println("Archivo rescatado");
}else{
System.out.println("Error");
}
File fileIn = new File("ArchivoAEnviar.txt");
FileInputStream in = new FileInputStream(fileIn);
scpBco.sendFile(in,fileIn.length(),"archivoOrigen.txt", "archivoDestino.txt");
}
}


Cuarto: Generar las claves pública y privada

Finalmente hay que obtener el archivo de la clave privada que se utiliza, para esto hay que acceder a la máquina remota y tipear el siguiente comando (en linux):

# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/usrcnv/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/usrcnv/.ssh/id_rsa.
Your public key has been saved in /home/usrcnv/.ssh/id_rsa.pub.

No ingresar “passphrase”.
Este comando crea los archivos de clave pública “id_rsa” y de clave privada “id_rsa.pub”.

El archivo “id_rsa.pub” se agrega al archivo que contiene las claves autorizadas “authorized_keys” ubicado en $HOME/.ssh/authorized_keys.

Para agregar la clave se tipea el siguente comando:

# cat id_rsa.pub >> authorized_keys

Finalmente copiar el archivo $HOME/.ssh/id_rsa en un directorio local.

Ahora sólo falta ejecutarlo.

lunes, 31 de diciembre de 2007

Cambio de idioma con struts

Este es una pequeña ayuda para los que quieran desarrollar una página web con diferentes idiomas. Es para un proyecto con tecnología J2EE y con soporte de struts.

Se requiere conocimientos básicos de struts, vamos a hacer un resumen:

El framework struts es un estándar para el desarrollo de aplicaciones web. Tiene las siguientes características:


  • Es open source

  • Está basado en el Modelo Vista Controlador

  • Implementa la arquitectura JSP

  • Se guarda la información de los ruteos y mapeos en un único archivo de configuración llamado struts-config.xml


Componentes de Struts

El controlador:
Es el encargado de recibir las peticiones e interpretar la URL para llamar a una clase Action y seleccionar el módulo adecuado. Lo provee el framework.

El archivo struts-config.xml
Este archivo contiene la configuración y todo el ruteo para una aplicación con soporte de Struts. Este archivo xml debe estar en el directorio WEB-INF de la aplicación.

Clases Action
Actúa como puente entre el link invocado por el usuario y los servicios de negocio. Los actions procesan una solicitud y devuelven un objeto ActionForward que identifica el siguiente componente a invocar.

Recursos de vista
Consisten en JSP (Java Server Pages), páginas HTML, archivos JavaScript y de estilo, Resource bundles, JavaBeans, and tags de Struts JSP.

ActionForms
Facilita la forma de validar la data capturada desde una peticion HTTP. Actúa como un "firewall" entre los formularios (páginas web) y la aplicación (actions). Estos componentes permiten la validación de la entrada antes de llegar al action o ejecutar la acción. Si la entrada no es válida se puede mostrar un error.

Pasos para cambiar el idioma.
Vamos a asumir que ya está creado el proyecto Web con soporte de Struts. El ejemplo que se utilizará será una validación de campos en diferentes idiomas.

Configuración del archivo struts-config.xml:
De este archivo nos interesa configurar el ActionForm, el Action y el archivo de recursos de mensajes

Para el ActionForm se agrega lo siguiente en la etiqueta form-beans:

<form-beans>
<form-bean name="myForm" type="pruebaweb.forms.myForm">
</form-bean>
</form-beans>

El Action se configura de la siguiente forma:

<action-mappings>
<action name="myForm" path="/myAct"
type="pruebaweb.actions.myAction" input="index.jsp">
<forward name="inicio"
path="index.jsp"></forward>
</action>
</action-mappings>

Finalmente los recursos de mensaje:

<message-resources parameter="pruebaweb.resources.ApplicationResources"/>


Esto último debemos tenerlo en cuenta a la hora de querer cambiar el idioma, ya que es el nombre del archivo que contiene los mensajes a mostrar en pantalla. El archivo de mensajes en este caso se llamaría ApplicationResources.properties y se encuentra en el paquete pruebaweb.resources

Creando el ActionForm (myForm)
El ActionForm contendrá los campos necesarios para capturar los datos de entrada desde la página html. Para el ejemplo tendremos un Rut y un nombre como campos:

package pruebaweb.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

public class myForm extends ActionForm {
private String rut = null;
private String nombre = null;
private String ok = null;
public void reset(ActionMapping mapping, HttpServletRequest request) {
rut = null;
nombre = null;
ok = null;
}
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if ((rut != null) && (rut.length() == 0)) {
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.rut"));
}
if ((nombre != null) && (nombre.length() == 0)) {
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.nombre"));
}
return errors;

}
public String getRut() { return rut;}
public void setRut(String r) { this.rut = r;}
public String getNombre() { return nombre;}
public void setNombre(String n) { this.nombre = n;}
public String getOk() { return ok;}
public void setOk(String string) { ok = string;}
}

Creando el action (myAction)
Vamos a crear tres funciones, una para iniciar, una para validar un rut y nombre, y una para cambiar el idioma.

package pruebaweb.actions;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.Globals;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

public class myAction extends DispatchAction {
public ActionForward inicio(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return mapping.findForward("inicio");
}
public ActionForward cambiaIdioma(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
pruebaweb.forms.myForm myForm = (pruebaweb.forms.myForm) form;
request.getSession().setAttribute(Globals.LOCALE_KEY,
new Locale(myForm.getIdioma(), ""));
return mapping.getInputForward();
}
public ActionForward validar(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
ActionForward forward = new ActionForward();
pruebaweb.forms.myForm myForm = (pruebaweb.forms.myForm) form;
if("Juanito".equalsIgnoreCase(myForm.getNombre()) &&
"19".equals(myForm.getRut())){
request.setAttribute("estado", "Ok");
}else{
request.setAttribute("estado", "No");
}
forward = mapping.findForward("inicio");
return (forward);
}
}

Creando el jsp (index.jsp)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html:html>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Ejemplo</TITLE>
<script language="JavaScript">
function ir(accion, idioma){
document.forms[0].accion.value = accion;
document.forms[0].idioma.value = idioma;
document.forms[0].submit();
}
</script>
</HEAD>
<BODY>
<html:errors/>
<html:form action="/myAct">
<input type="hidden" name="accion" value="validar">
<input type="hidden" name="idioma" value="">
<table width="40%">
<tr>
<td width="20%"><bean:message key="rut"/></td>
<td width="2%">:</td>
<td width="30%"><html:text name="myForm" property="rut"/></td>
</tr>
<tr>
<td><bean:message key="nombre"/></td>
<td>:</td>
<td><html:text name="myForm" property="nombre"/></td>
<tr>
<tr>
<td colspan="2"> </td>
<td><input type="submit" name="boton" value="Verificar"></td>
<tr>
</table>
<bean:message key="mensaje"/>
<br><br>
<logic:present name="estado">
<font style="color: blue;font-size: 26px"><bean:write name="estado"/></font>
</logic:present>
<br>
<a href="JavaScript:ir('cambiaIdioma','')">Español</a>
<a href="JavaScript:ir('cambiaIdioma','en')">Inglés</a>
</html:form>
</BODY>
</html:html>

Creando el archivo ApplicationResources.properties

mensaje=Enter your Rut and Name
rut=Rut
nombre=Name

Para agregar otro idioma basta con crear un archivo con el mismo nombre que el anterior y agregarle un guión bajo y una definición, por ejemplo para inglés ApplicationResources_en.properties
Creando el archivo ApplicationResources_en.properties

errors.header=<ul>
errors.footer=</ul>
error.rut=<li>Rut no válido</li>
error.nombre=<li>Nombre no válido</li>
error.general=<li>Error general</li>
mensaje=Enter your Rut and Name
rut=Rut
nombre=Name


Rimaster ®