domingo, 27 de septiembre de 2009

Obtener objetos de la session en JSF

Otro de los descubrimientos que he realizado tras trabajar en el último proyecto sobre JSF ha sido obtener instancias de objetos o variables creadas por el contenedor web. Como sabéis todos las clases java que utilices para trabajar con JSF (Backing bean, JavaBean...) deben estar dadas de alta en el faces-config.xml y deben de tener un constructor público sin argumentos. Esto es debido a que el contenedor de aplicaciones web (Tomcat, Glassfish ...) crearán instancias de estas clases para cada session (según el ambito especificado en faces-config.xml), esto plantea algunos problemas al querer usar singleton o simplemente al querer comunicar estas instancias de objetos ya que no existen referencias entre estas clases.

Bien pues desde cualquier clase java puedes escribir las siguientes líneas y obtendrás el valor de los atributos de otra instancia de las clases creadas por el contenedor.

FacesContext fc = FacesContext.getCurrentInstance();

String usr_id = (String)fc.getApplication().createValueBidding("#SessionScope.usr_id").getValue(fc);


Espero que os sea de utilidad a mi me ha venido de perlas.

viernes, 25 de septiembre de 2009

Validator en JSF

Este último més he estado trabajando en una aplicación sobre JSF, una tecnología que bajo mi punto de vista todavía le queda para ser madura, sobre todo por la cantidad de framework que puedes usar pero que luego mezclarlos es un verdadero dolor de cabezas. Despues de investigar ICEFace el cual me gustó mucho, ahora tenías que usar tiles para poder incluyectarle trozos y poder crear plantilla. Total que al final uso MyFaces (implementación de Apache de JSF) con Tomahawk que parece ser el más tolerante.


Entonces he descubierto muchas de las bondades de JSF entre ellas los validadores, unas clases java que te sirven para la validación de campos en los formularios, pudiendote olvidar del javascript. Esto me ha gustado mucho pero me encontre un escoyo que me gustaría ilustrar. Tenía un campo Año que quería validar. Bien pues cree el validador correspondiente:


public void validate(FacesContext facesContext, UIComponent uiComponent, Object object) throws ValidatorException {

try {

int anio = Integer.parseInt(object.toString());

if (anio < 1960 || anio > 2050) {



FacesMessage message = new FacesMessage();

message.setSummary("Año "+anio+" no válido");

throw new ValidatorException(message);

}

} catch (Exception e) {


FacesMessage message = new FacesMessage();

message.setSummary("Año "+object.toString()+" no válido");

throw new ValidatorException(message);

}

}



Y lo dí de alta en el faces-config.xml

<validator>

<validator-id>ValidaAnio</validator-id>

<validator-class>Validadores.ValidaAnio</validator-class>

</validator>

Ahora el problema es que al validar un campo:

<t:outputText id="Anyo" value="Año(aaaa):"/>

<t:inputText id="iAnyo" size="4" maxlength="4" value="#{ActasBusquedaBB.anyo}">

<f:validator validatorId="ValidaAnio"/>

</t:inputText>



pues el campo dentro del formulario se quedaba relleno con el valor erroreo.

Por ejemplo, si en el input anterior introduzco "abcd" como no es un año este falla en el validador
al hacer el casting a entero y sale el mensaje de "Año abcd no válido", pero no se borra el campo del formulario.

La pregunta es ¿ Como hacer desde la clase java ValidaAnio que el campo del formulario se borre si el valor es incorrecto?

Bien pues se hace en 2 lineas pero encontrarlas me costo sangre y por eso la pongo aquí.

public void validate(FacesContext facesContext, UIComponent uiComponent, Object object) throws ValidatorException {

try {

int anio = Integer.parseInt(object.toString());

if (anio < 1960 || anio > 2050) {

if (uiComponent instanceof UIInput)

((UIInput)uiComponent).setSubmittedValue("");

FacesMessage message = new FacesMessage();

message.setSummary("Año "+anio+" no válido");

throw new ValidatorException(message);

}

} catch (Exception e) {

if (uiComponent instanceof UIInput)

((UIInput)uiComponent).setSubmittedValue("");

FacesMessage message = new FacesMessage();

message.setSummary("Año "+object.toString()+" no válido");

throw new ValidatorException(message);

}

}



Espero que os sirva ;)

jueves, 26 de marzo de 2009

Trabajar con Certificados SSL en Java

Este artículo es muy útil cuando desde java queremos comunicarnos a través del protocolo seguro SSL. Este articulo lo encontre en el blob Apaga y vámonos y espero que os sea tan útil como me lo fue a mi.

Cuando desarrollamos una aplicación en Java que va ha hacer uso de un recurso seguro (mediante un certificado), debemos asegurarnos que este certificado podrá ser validado por una entidad certificadora que reconozca Java. Debido a que Java es un lenguaje multi-plataforma, no utiliza la información de certificados alojada en el Sistema Operativo.

Por defecto, la máquina virtual de Java dispone de las Entidades Certificadoras (CA) más comunes, como Verisign o Thawte. Sin embargo, suele darse el caso, sobretodo en entornos de desarrollo, que necesitemos utilizar una Entidad Certificadora "de prueba". En este caso, debemos importar esta CA en el almacén de claves de la máquina virtual que estemos utilizando.


Importar Certificado en el almacén de certificados (keystore)


La máquina virtual de Java (JVM) cuenta con un almacén de claves (keystore) que incorpora las entidades más habituales y la posibilidad de agregar aquellas que nos sean necesarias. El keystore se encuentra en la ruta: JVM_PATH\lib\security\cacerts. Por ejemplo:


C:\Archivos de programa\Java\jre1.6.0_05\lib\security\cacerts
C:\Archivos de programa\Java\jdk1.5.0_15\jre\lib\security


Para añadir una nueva entidad certificadora a la JVM que estemos utilizando, debemos utilizar el comando keytool (JVM_PATH\bin\keytool):


keytool -import -keystore "C:\Archivos de
programa\Java\jre1.6.0_05\lib\security\cacerts" -file
c:\NuevaEntidadCertificadora.cer -alias CA_SwitchOffAndLetsGo -storepass
changeit




Puede observarse que el almacén de certificados contiene la contraseña por defecto 'changeit'. El nombre que especifiquemos en el alias, debe ser único en el keystore y servirá de referencia futura en el almacén. Podemos listar los certificados instalados utilizando la opción list del keytool:


keytool -list -keystore "C:\Archivos de
programa\Java\jre1.6.0_05\lib\security\cacerts" -storepass changeit




Importar Certificado utilizando el panel de control de Java (Windows)


Atención: con esta opción únicamente se añadirán los certificados a la instalación activa de la JVM en Windows.


Para añadir la nueva entidad, se accederá al Panel de Control de Windows, y se seleccionará la opción "Java". Seguidamente se marcará la pestaña "Seguridad" y se pulsará sobre el botón "Certificados".


En el apartado de Certificados, se seleccionará la opción "Importar" y se localizará el archivo que contiene el certificado (si el certificado tiene extensión .cer se tendrá que seleccionar la opción 'Todos los archivos'). El nuevo certificado aparecerá en la pestaña "Usuario".

miércoles, 11 de febrero de 2009

Como hacer la descarga de ficheros con servlets

Pues este es un problema muy curioso, como sabéis los servlet devuelven un stream como respuesta. La configuración más usada para los servlet es que la respuesta sea de tipo html, que especificamos:

response.setContentType("text/html");

Pero el contenido de la respuesta lo podemos cambiar a cualquier otro Mime type:

http://www.webmaster-toolkit.com/mime-types.shtml

Según esto podemos hacer que nuestro servlet devuelva cualquier tipo de fichero.

En el siguiente ejemplo escribo un servlet capaz de enviarnos un fichero zip de cualquier parte del disco del servidor. (Nota. esto hay que manejarlo con cuidado porque puede producir un hueco de seguridad gordisimo)

package org.company.servlet.readfile;


import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.net.*;


/**
*

This class handles Streaming Data Content


**/
public class Readfile extends HttpServlet {

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    /*
    * This Method Handles Post
    *
    * @param HttpServletRequest request
    * @param HttpServletResponse response
    */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    /*
    * This Method Handles Get
    *
    * @param HttpServletRequest request
    * @param HttpServletResponse response
    */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String urlstr = null;
        UserBean user = (UserBean)         request.getSession().getAttribute("user");
        try {
            response.reset();
            urlstr = request.getParameter("filename");
            ServletOutputStream sOutStream = response.getOutputStream();
            streamBinaryData(user.getName(),             urlstr, sOutStream, response);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void streamBinaryData(String username, String file, ServletOutputStream outstr, HttpServletResponse resp) throws IOException{
        String ErrorStr = null;

        try {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        String inFile = "/midirectorio/" + file;
        int tam = (int) new File(inFile).length();
        bis = new BufferedInputStream(new FileInputStream(inFile));

        try {
            //Asignamos el tipo de fichero zip
            resp.setContentType("application/x-zip-compressed"); //Cualquier mime type
            //Seteamos el tamaño de la respuesta
            resp.setContentLength(tam);
            resp.setHeader("Content-Disposition", "attachment;filename=\"" + file + "\"");

            bos = new BufferedOutputStream(outstr);

            // Bucle para leer de un fichero y escribir en el otro.
            byte[] array = new byte[1000];
            int leidos = bis.read(array);
            while (leidos > 0) {
                bos.write(array, 0, leidos);
                leidos = bis.read(array);
            }


            } catch (Exception e) {
                e.printStackTrace();
                ErrorStr = "Error Streaming the Data";
                outstr.print(ErrorStr);
            } finally {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
                if (outstr != null) {
                    outstr.flush();
                    outstr.close();
                }
            }

            } catch (Exception e) {
                System.out.println("Fichero no encontrado");
                resp.sendRedirect("fileNotFound.jsp");

            }

        }
    }

Con este servlet conseguimos que en el navegador aparezca la típica ventanita de "descargas" al hacer una llamada al servlet, que recibe como parámetro el nombre del fichero. Este es el motivo por el que debemos tener cuidado al usar esto ya que podríamos crear un hueco de seguridad y que el usuario final se pueda descargar cualquier fichero de nuestro servidor.

Lo mejor sería tener un directorio controlado del que sacar los ficheros como en el ejemplo, o que se filtre el filename de entrada para saber que está entre los permitidos, etc ...

Configurar la red manualmente en Ubuntu

Hace tiempo que no escribo en el blog, el motivo es que ando muy muy liado con el trabajo y no me ha dejado tiempo para escribir los artículos que tenía en mente. Pero hoy me ha pasado que al instalarme una máquina nueva con la ultima versión de ubuntu. Si uso la configuración gráfica de red, está no se porqué no se guarda, sólo está activa mientras esté el ordenador encendido pero al reiniciarlo toda la configuración se pierde.

Bueno pues este artículo intenta explicar como configurarla manualmente para que se quede permanente ya que desde el UI no lo he conseguido.

1 Paso:

> vi /etc/network/interfaces

El contenido debemos editarlo para que quede:

auto lo
iface lo inet loopback

iface eth0 inet static
address XXX.XXX.X.XXX
netmask 255.255.255.XXX
gateway XXX.XXX.X.XXX
nameserver XXX.XXX.X.XXX
domain midominio.es

auto eth0


Esta configuración especifica:
address -> dirección ip
netmask -> máscara de red
gateway -> la puerta de enlace, suele ser la dirección ip del rooter
nameserver -> (opcional) dirección ip del servidor de dns, puedes poner tantos como servidores dns tengas
domain -> para configurar el dominio de red en el que te encuentras


Nota. Esta configuración está hecha para una conexión cableada por eso usa eth0

Paso 2:

Aunque en este fichero podemos especificar los dns, lo suyo es especificarlos en el fichero

> vi /etc/resolv.conf

El contenido del fichero debería ser:

nameserver XXX.XXX.X.XXX

Nota. Tantos nameserver como servidores de dns tengamos.

Bueno pues con esto, tu configuración quedará permanetemente configurada, de hecho
si el NetworkManager (UI para la configuración de red de ubuntu) funcionara bien, en estos ficheros debe poner algo así como

# Generated by NetworkManager

Eso es todo.