Mostrando las entradas con la etiqueta el nucleo de framework vaadin. Mostrar todas las entradas
Mostrando las entradas con la etiqueta el nucleo de framework vaadin. Mostrar todas las entradas

5.2. Interfaces y Abstracciones

Los componentes de la interfaz de usuario de Vaadin se basan en un esqueleto de interfaces y clases abstractas que definen e implementan las características comunes de todos los componentes y la lógica básica de cómo son serializados los estados del componente entre el servidor y el cliente.

Esta sección proporciona detalles sobre las interfaces de los componentes básicos y abstracciones. El diseño y otras abstracciones del contenedor de componentes se describen en el Capítulo 6, Administrar el Diseño. Las interfaces que definen el modelo de datos de Vaadin se describen en el Capítulo 9, Vincular Componentes a Datos.

Figura 5.2. Interfaces de Componentes y Abstracciones

Todos los componentes implementan la interfaz Paintable, que se utiliza para serializar ("pintando") los componentes para el cliente, y la interfaz inversa VariableOwner, que es necesaria para des serializar el estado del componente o la interacción del usuario desde el cliente.

Además de las interfaces definidas en el framework Vaadin, todos los componentes implementan la interfaz java.io.Serializable para permitir la serialización. La serialización es necesaria en muchas agrupaciones y soluciones de computación en la nube (cloud computing).

5.2.1 Interfaz Component

La interfaz Component se combina con la clase AbstractComponent, que implementa todos los métodos definidos en la interfaz.

Administración del Árbol de Componentes
Los componentes son presentados en la interfaz de usuario jerárquicamente. El diseño es administrado por los componentes de diseño, o más en general por los componentes que implementan la interfaz ComponentContainer. Este contenedor es el padre de los componentes contenidos.

El método getParent() permite recuperar el componente padre de un componente. Si bien existe un setParent(), que rara vez se necesita cuando por lo general agrega componentes con el método addComponent() de la interfaz ComponentContainer, el cual establece automáticamente al padre.

Un componente no conoce a su padre cuando el componente es creado, por lo que no puede referirse al padre en el constructor con getParent(). Además, no es posible traer una referencia al objeto application con getApplication() antes de tener un padre. Por ejemplo, lo siguiente es inválido:

public class EjemploAcoplar extends CustomComponent {
    public EjemploAcoplar() {
        // ERROR: No podemos tener acceso al objeto de application aún.
        ClassResource r = new ClassResource("smiley.jpg",
                                            getApplication());
        Embedded image = new Embedded("Image:", r); 
        setCompositionRoot(image);
    }
}

La adición de un componente a una aplicación provoca que se active el llamado del método attach() para el componente. En consecuencia, la eliminación de un componente de un contenedor activa el llamado al método detach(). Si el padre de un componente agregado ya está conectado a la aplicación, attach() es llamado inmediatamente desde setParent().

public class EjemploAcoplar extends CustomComponent {
    public EjemploAcoplar() {
    }
    
    @Override
    public void attach() {
        super.attach(); // Debe llamar.
        
        // Ahora sabemos quién es finalmente nuestro dueño.
        ClassResource r = new ClassResource("sonriente.jpg",
                                            getApplication());
        Embedded imagen = new Embedded("Imagen:", r); 
        setCompositionRoot(imagen);
    }
}

La lógica del acoplamiento es implementado en AbstractComponent, tal como se describe en la Sección 5.2.2, "AbstractComponent".

5.2.2 AbstractComponent

AbstractComponent es la clase base para todos los componentes de interfaz de usuario. Se trata (sólo) de la implementación de la interfaz Component, implementando todos los métodos definidos en la interfaz.

AbstractComponent tiene un único método abstracto, getTag(), el cual devuelve el identificador de la serialización de la clase de un componente en particular. Este tiene que ser implementado cuando (y sólo cuando) se creen componentes totalmente nuevos. AbstractComponent administra gran parte de la serialización de los estados de los componentes entre el cliente y el servidor. La creación de nuevos componentes y la serialización se describe en el Capítulo 11, Desarrollar Nuevos Componentes, y la API de serialización del lado del servidor en el Apéndice A, Definicion del Lenguaje de Interfaz de Usuario (UIDL).

Componentes Campo (Field y AbstractField)

Los Campos son los componentes que tienen un valor que el usuario puede cambiar a través de la interfaz de usuario. La Figura 5.3, "Componentes Campo", ilustra las relaciones de herencia y las interfaces importantes y las clases base.

Figura 5.3. Componentes Campo

Los componentes campo se basan en el framework definido en la interfaz Field y de la clase base AbstractField.

Los campos están fuertemente acoplados con el modelo de datos de Vaadin. El valor del campo es tratado como una Property del componente field. Los campos de selección permiten la administración de elementos seleccionables a través de la interfaz Container.

La descripción de las interfaces field y las clases base se divide en las siguientes secciones.

Interfaz Field
La interfaz Field hereda la superinterface Component y también la interfaz Property para tener un valor para el campo. AbstractField es la única clase que implementa directamente la interfaz Field. Las relaciones se ilustran en la Figura 5.4, "Diagrama de Herencia de la Interfaz Field".

Figura 5.4. Diagrama de Herencia de la Interfaz Field

Puede establecer el valor del field con setValue() y leerlo con el método getValue() definido en la interfaz Property. El tipo de valor actual depende del componente.

La interfaz Field define una serie de atributos, que se pueden recuperar o manipular con el setters y getters correspondiente.
  • description
    Todos los campos tienen una descripción. Tenga en cuenta que si bien, este atributo se define en el componente Field, el cual es implementado en AbstractField, que no implementa directamente a Field, pero sólo a través de la clase AbstractField.

    required
    Cuando está activado, un indicador de (por lo general el carácter * asterisco) es mostrado a la izquierda, arriba, o hacia la derecha del campo, dependiendo del diseño que lo contiene y si el campo tiene un título. Si estos campos son validados pero están vacíos y se activa la propiedad requiredError (ver más abajo), se muestra un indicador de error y el error del componente se establece en el texto definido con la propiedad error. Sin la validación, el indicador requerido no es más que una guía visual.

    requiredError
    Define el mensaje de error a mostrar cuando se requiere un valor para un campo, pero no se ingresa nada. El mensaje de error se establece como el error del componente para el campo y por lo general se muestra en un texto de ayuda cuando el puntero del mouse se desplaza sobre el indicador de error. El componente Form puede mostrar el mensaje de error en un área indicadora de error especial.
Controlar Cambios de Valor en Field
Field hereda a Property.ValueChangeListener para permitir escuchar los cambios de valor en los campos y Property.Editor para permitir editar los valores.

Cuando el valor de un campo cambia, es desencadenado un Property.ValueChangeEvent para el campo. No debería implementar el método valueChange() en una clase que herede a AbstractField, ya que se ha implementado en AbstractField. En su lugar, debe implementar el método explícitamente añadiendo la implementación del objeto como un oyente.

Clase Base AbstractField
AbstractField es la clase base para todos los componentes field. Además de las características de los componentes heredadas de AbstractComponent, esta implementa varias características definidas en las interfaces Property, Buffered, Validatable, y Component.Focusable.



Anterior
Capítulo 5. Componentes de Interfaz de Usuario
Siguiente
5.3. Características Comunes de los Componentes

Capítulo 5. Componentes de Interfaz de Usuario

Este capítulo proporciona una información general y una descripción detallada de todos los componentes de no-diseño en Vaadin.

5.1 Información General

Vaadin proporciona un conjunto completo de componentes de interfaz de usuario y le permite definir componentes personalizados. La Figura 5.1, "Diagrama de Herencia de los Componentes de Interfaz de Usuario" ilustra la jerarquía de herencia de las clases de los componentes de interfaz de usuario e interfaces. Las Interfaces se muestran en color gris, las clases abstractas en naranja, y las clases regulares en azul. Una versión anotada del diagrama aparece en la Hoja de Referencia de Vaadin.

Figura 5.1 Diagrama de Herencia de los Componentes de Interfaz de Usuario

En la parte superior de la jerarquía de interfaces, tenemos la interfaz Component. En la parte superior de la jerarquía de clases, tenemos la clase AbstractComponent. Que es heredada por otras dos clases abstractas AbstractField, heredada ademas por campos de componentes, y AbstractComponentContainer, heredada de varios contenedores y componentes de diseño. Los componentes que no están vinculados a un contenido de modelo de datos, tales como etiquetas y enlaces, heredan directamente de AbstractComponent.

El diseño de los distintos componentes en una ventana es controlada, lógicamente, por componentes de diseño, al igual que el convencional conjunto de herramientas de interfaz de usuario de Java para aplicaciones de escritorio. Además, con el componente CustomLayout, puede escribir un diseño personalizado como una plantilla XHTML que incluye la ubicación de cualquiera de los componentes contenido. Al mirar el diagrama de herencia, podemos ver que los componentes de diseño heredan las interfaces AbstractComponentContainer y Layout. Los componentes de diseño se describen en detalle en el Capítulo 6, Administrar el Diseño.

Mirándolo desde la perspectiva de una jerarquía de objetos, tendríamos un objeto Window, que contiene una jerarquía de componentes de diseño, que a su vez contienen otros componentes de diseño, componentes de campo, y otros componentes visibles.

Puede navegar por los componentes de interfaz de usuario incorporados en la librería Vaadin en la aplicación Sampler de la Demo de Vaadin. Sampler muestra una descripción, documentación JavaDoc, y un código de ejemplo para cada uno de los componentes.

Además de los componentes incorporados, muchos componentes están disponibles como complementos, ya sea desde el Directorio de Vaadin o desde fuentes independientes. Existen tanto componentes comerciales como libres. La instalación de los complementos se describe en el Capítulo 15, Usar Complementos Vaadin.

Apunte Escondido Vaadin y Refcard

La Figura 5.1, "Diagrama de Herencia de los Componentes de Interfaz de Usuario" es incluida en el Apunte Escondido Vaadin que muestra la jerarquía de la relación básica de los componentes de interfaz de usuario y las clases para vincular datos e interfaces. Puede descargarlo en http://dev.vaadin.com/browser/doc/trunk/cheatsheet/vaadin-cheatsheet-duplex.pdf.

El diagrama también es incluido en las seis páginas del DZone Refcard, el cual puede encontrarlo en https://vaadin.com/refcard.



Anterior
4.8. Configurar el Entorno de la Aplicación
Siguiente
5.2. Interfaces y Abstracciones

4.6. Apagar una Aplicación

Un usuario puede cerrar la sesión o cerrar la página web o el navegador, por lo que una sesión y la instancia application asociada pueden terminarse. La finalización de una aplicación puede ser iniciada por la lógica de la aplicación. De lo contrario, será terminada automáticamente cuando la sesión del Servlet expire.

4.6.1 Cerrar una Aplicación

Si el usuario sale de la aplicación a través de la interfaz de usuario, un controlador de eventos debería llamar al método close() en la clase Application para cerrar la sesión.

En el siguiente ejemplo, tenemos un botón Salir, que termina la sesión del usuario.

Button botonCerrar = new Button("Salir");

botonCerrar.addListener(new Button.ClickListener() {
    @Override
    public void buttonClick(ClickEvent event) {
        getMainWindow().getApplication().close();
    } 
});
 
principal.addComponent(botonCerrar);

Notará que el cierre de la aplicación, simplemente recarga la aplicación con una nueva instancia de Application. Puede configurar la ventana para redirigir a una dirección URL diferente (que no recarga la aplicación) con setLogoutURL. En su clase application, escriba:

setLogoutURL("/salir.html");

4.6.2 Controlar el Cierre de una Ventana

El cierre de la ventana principal (o todas las ventanas de nivel de aplicación) no cierra la sesión y la instancia de la aplicación quedará colgando. Necesitará programar tal comportamiento controlando los eventos de cierre de las ventanas.

Si el usuario cierra una ventana del navegador, como la ventana principal o cualquier otra ventana de nivel de aplicación, la ventana enviará una petición final AJAX al servidor, el cual disparará un Window.CloseEvent para la ventana cerrada. Puede controlar el evento con un Window.CloseListener. En caso de que el usuario cierre el navegador, el evento es disparado para cada ventana abierta.

// Cerrar la aplicación si la ventana principal es cerrada.
principal.addListener(new Window.CloseListener(){
   @Override
    public void windowClose(CloseEvent e) {
       System.out.println("Cerrando la aplicación");
       getMainWindow().getApplication().close();
    } 
});

Tenga en cuenta que actualizar una ventana significa cerrarla y volverla a abrir. Por lo tanto, si tiene un controlador de cierre como el anterior, el usuario pierde la posibilidad de actualizar la ventana del navegador.

En el probable caso de que el navegador se bloquee, ningún evento de cierre es comunicado al servidor. Como el servidor no tiene manera de conocer acerca del problema, y la sesión quedará colgando hasta que expire el tiempo de espera de la sesión. Durante este tiempo, el usuario puede reiniciar el navegador, abrir el URL de la aplicación, y la ventana principal le mostrará donde el usuario le dejó. Esto puede ser un comportamiento deseado en muchos casos, pero a veces no lo es y puede crear un problema de seguridad.



Anterior
4.5. Referenciar Recursos
Siguiente
4.7. Controlar Errores

4.5. Referenciar Recursos

Las aplicaciones web trabajan sobre la web y tienen varios recursos, como imágenes o archivos descargables, que el navegador web tiene que obtener desde el servidor. Estos recursos son utilizados típicamente en los componentes de interfaz de usuario Embedded (imágenes) o Link (archivos descargables). Varios componentes, tales como TabSheet, también pueden incluir iconos, los cuales también son manejados como recursos.

Un servidor web puede manejar muchas de estas peticiones de recursos estáticos sin tener que pedirlas desde la aplicación, o desde el que el objeto Application puede proporcionarnos. Para los recursos dinámicos, la aplicación de usuario debe ser capaz de crearlos dinámicamente. Vaadin proporciona interfaces de petición de recursos para las aplicaciones de modo que puedan devolver los diversos tipos de recursos, tales como archivos o recursos creados dinámicamente. Esto incluye las clases StreamResource y URI y controladores de parámetros descritos en la Sección 12.5.1, "Controlador de URI" y la Sección 12.5.2, "Controlador de Parametros", respectivamente.

Vaadin proporciona también herramientas de bajo nivel para la recuperación del URI y otros parámetros de una petición HTTP. En primer lugar, examinaremos cómo las aplicaciones pueden ofrecer diversos tipos de recursos y luego buscar en interfaces de bajo nivel para el manejo de los URIs y parámetros para proporcionar los recursos y funcionalidades.

Observe que el uso del URI o controladores de parámetro para crear "páginas" no es significativo en Vaadin o en aplicaciones AJAX en general. Por favor, consulte la Sección 12.1, "Caracteristicas Especiales de Aplicaciones AJAX" para una explicación detallada.

4.5.1. Interfaz y Clases Resource

Vaadin tiene dos interfaces para los recursos: una interfaz genérica Resource y una interfaz ApplicationResource más específica para los recursos proporcionados por la aplicación.

Figura 4.4. Diagrama de la Interfaz y Clase Resource

Los recursos de ApplicationResource son manejados por la clase Application. Cuando usted crea tal recurso, le da el objeto application al constructor. El constructor registra el recurso en la aplicación usando el método addResource.

Application maneja peticiones de los recursos y permite acceder a los recursos utilizando un URI. El URI consiste en el nombre de la base de la aplicación y un nombre relativo del recurso. El nombre relativo es "APP/"+iddelrecurso+"/"+nombredelarchivo, por ejemplo "APP/1/miimagen.png". iddelrecurso es un identificador numérico generado para hacer recursos únicos, y nombredelarchivo es el nombre de fichero del recurso proporcionado en el constructor de su clase. Sin embargo, la aplicación que utiliza un recurso no suele tener en cuenta su URI. Sólo tiene que dar el recurso a un Embedded o Link apropiado o a algún otro componente de interfaz de usuario, que maneje el renderizado del URI.

4.5.2. Recursos de Archivos

Los recursos de archivos son archivos almacenados en cualquier parte del sistema de archivos. El uso de los recursos de archivo generalmente, se divide en dos categorías principales: los archivos descargados y las imágenes embebidas.

Un objeto file que puede ser accedido como un recurso de archivo es definido con la clase estándar java.io.File. Puede crear el archivo, ya sea con una ruta absoluta o con una relativa, pero la ruta base de la ruta de acceso relativa depende de la instalación del servidor web. Por ejemplo, en Apache Tomcat, el directorio actual por defecto es la ruta de instalación de Tomcat.

4.5.3. Recursos de Cargador de Clase

ClassResource permite que los recursos sean cargados desde el paquete desplegado de la aplicación utilizando el Cargador de Clase de Java. En el ejemplo de una línea más abajo, se carga un recurso de imagen desde el paquete de la aplicación y es mostrado en un componente Embedded.

ventanaPrincipal.addComponent(new Embedded ("",
        new ClassResource("sonriente.jpg",
                  ventanaPrincipal.getApplication())));

4.5.4. Recursos de Tema (Estilo)

Los recursos de tema de la clase ThemeResource son archivos, generalmente imagenes, incluidas en un tema. Un tema es localizado en la ruta camino VAADIN/themes/nombredeltema en una aplicación web. El nombre de un recurso de tema es proporcionado como parámetro para el constructor, con una ruta relativa a la carpeta themes.

// Un recurso de tema en el actual tema ("book-examples")
// Localizado en: VAADIN/themes/book-examples/img/themeimage.png
ThemeResource recurso = new ThemeResource("img/themeimage.png");
 
// utilizar el recurso
Embedded imagen = new Embedded("Mi Imagen del Tema", recurso);

El resultado se muestra en la Figura 4.5, "Recursos de Tema", ilustra también la estructura de la carpeta para el archivo de recursos del tema en un proyecto de Eclipse.

Figura 4.5. Recursos de Tema

Para utilizar recursos de tema, debe establecer el tema para la aplicacion. Consulte el Capítulo 8, Temas para mayor informacion sobre los temas.

4.5.5. Recursos de Flujo

Los recursos de flujo son recursos de aplicaciones que permiten la creación de contenido dinámico de recursos. Los gráficos son ejemplos típicos de imágenes dinámicas. Para definir un recurso de flujo, es necesario implementar la interfaz StreamResource.StreamSource y su método getStream. El método debe devolver un InputStream desde el cual el flujo pueda ser leído.

El siguiente ejemplo muestra la creación de una simple imagen en formato de imagen PNG.

import java.awt.image.*;

public class MiFuenteImagen
             implements StreamResource.StreamSource {
    ByteArrayOutputStream bufferImagen = null;
    int recargas = 0;
    
    /* Necesitamos implementar este método que devuelve
     * el recurso como un flujo. */
    public InputStream getStream () {
        /* Crear una imagenn y dibujar algo en ella. */
        BufferedImage imagen = new BufferedImage (200, 200,
                               BufferedImage.TYPE_INT_RGB);
        Graphics dibujable = imagen.getGraphics();
        dibujable.setColor(Color.lightGray);
        dibujable.fillRect(0,0,200,200);
        dibujable.setColor(Color.yellow);
        dibujable.fillOval(25,25,150,150);
        dibujable.setColor(Color.blue);
        dibujable.drawRect(0,0,199,199);
        dibujable.setColor(Color.black);
        dibujable.drawString("Recargas = " + recargas, 75, 100);
        recargas++;

        try {
            /* Escriba la imagen en un búfer. */
            bufferImagen = new ByteArrayOutputStream();
            ImageIO.write(imagen, "png", bufferImagen);
            
            /* Devolver un flujo desde el buffer. */
            return new ByteArrayInputStream(
                         bufferImagen.toByteArray());
        } catch (IOException e) {
            return null;
        }
    }
}

El contenido de la imagen generada es dinámico, ya que actualiza el contador recargas en cada llamada. El método ImageIO escribe la imagen para un flujo de salida, mientras, tuvimos que devolver un flujo de entrada, por lo que almacenamos los contenidos de la imagen en un búfer temporal.

Puede utilizar los recursos de varias maneras. Algunos componentes de interfaz de usuario, como Link y Embedded, toman sus parámetros como un recurso.

A continuación se mostrará la imagen con el componente Embedded. El constructor StreamResource obtiene una referencia de la aplicación y se registra en los recursos de la aplicación. Supongamos que principal es una referencia a la ventana principal y this es el objeto application.

// Crear una instancia de nuestra fuente de flujo.
StreamResource.StreamSource fuenteImagen = new MiFuenteImagen();
 
// Crear un recurso que utiliza el origen de flujo y proporcinarle un nombre.
// El constructor registrará automáticamente el recurso en
// la aplicación.
StreamResource recursoImagen =
        new StreamResource(fuenteImagen, "miImagen.png", this);
 
// Crear un componente integrado que recibe su contenido
// del recurso.
principal.addComponent(new Embedded("Titulo de la imagen", recursoImagen));

La imagen se verá de la siguiente manera:

Figura 4.6. Pantallazo del ejemplo de recurso de flujo con una imagen embebida

Hemos llamado a este recurso como miImagen.png. La aplicación agrega una llave de recurso al nombre de archivo del recurso para hacerlo único. El URI completo será como http://localhost:8080/bancodepruebas/APP/1/miImagen.png. El APP/1/miImagen.png al final es la parte relativa del URI. Puede obtener la parte relativa de los recursos del URI desde la aplicación con Application.getRelativeLocation().

Otra solución para crear contenido dinámico es un controlador del URI, posiblemente junto con un controlador de parámetro. Vea la Sección 12.5.1, "Controlador de URI" y la Sección 12.5.2, "Controlador de Parametros".



Anterior
4.4. Controlar Eventos con Oyentes
Siguiente
4.6. Apagar una Aplicación

4.4. Controlar Eventos con Oyentes

Vamos a poner en práctica lo que aprendimos del manejo de eventos en la Sección 3.5, "Eventos y Oyentes". Puede manejar los eventos de tres formas básicas, como se muestra a continuación.

El siguiente ejemplo sigue un modelo típico en el que tiene un componente Button y un oyente que se encarga de la interacción del usuario (clics) comunicado a la aplicación por eventos. Aquí definimos una clase que escucha los eventos clic.

public class ElBoton implements Button.ClickListener {
    Button elBoton;

    /** Crear el botón en el contenedor proporcionado. */
    public ElBoton(AbstractComponentContainer contenedor) {
        elBoton = new Button ("No presione este botón");
        elBoton.addListener(this);
        contenedor.addComponent(elBoton);
    }
    
    /** Controlar los eventos clic del boton para el boton. */
    public void buttonClick (Button.ClickEvent event) {
        elBoton.setCaption ("No presione este botón de nuevo");
    }
}

Como una aplicación suele recibir eventos de varios componentes de la misma clase, tales como múltiples botones, esta tiene que ser capaz de distinguir entre los componentes individuales. Hay varias técnicas para hacer esto, pero probablemente la más fácil es utilizar la propiedad del evento recibido, que se establece en el objeto enviando el evento. Esto requiere tener a mano una referencia para cada objeto que emite los eventos.

public class ElBoton implements Button.ClickListener {
    Button elBoton;
    Button segundoBoton;

    /** Crear dos botones en el contenedor proporcionado. */
    public ElBoton(AbstractComponentContainer contenedor) {
        elBoton = new Button ("No presione este botón");
        elBoton.addListener(this);
        contenedor.addComponent(elBoton);
        
        segundoBoton = new Button ("Yo soy un botón también");
        segundoBoton.addListener(this);
        contenedor.addComponent (segundoBoton);
    }
    
    /** Controlar los eventos clic del boton para los dos boton. */
    public void buttonClick (Button.ClickEvent event) {
        if (event.getButton() == elBoton)
            elBoton.setCaption("No presione este botón de nuevo");
        else if (event.getButton() == segundoBoton)
            segundoBoton.setCaption("Yo no soy un número");
    }
}

Otra solución para manejar eventos múltiples de la misma clase implica vincular un origen de eventos a un método oyente en lugar de la clase. Un evento puede ser vinculado a un método utilizando otra versión del método addListener(), el cual toma el método que maneja el evento como un parámetro. El método puede ser pasado ya sea por el nombre del método o como un objeto Method. En el siguiente ejemplo, utilizamos el nombre del método como una cadena (el cual no es comprobado en tiempo de compilación).

public class ElBoton2 implements Button.ClickListener {
    Button elBoton;
    Button segundoBoton;

    /** Crear dos botones en el contenedor proporcionado. */
    public ElBoton2(AbstractComponentContainer contenedor) {
        elBoton = new Button ("No presione este botón");
        elBoton.addListener(Button.ClickEvent.class, this,
                              "elButtonClick");
        contenedor.addComponent(elBoton);
        
        segundoBoton = new Button ("Yo soy un botón también");
        segundoBoton.addListener(Button.ClickEvent.class, this,
                                 "segundoButtonClick");
        contenedor.addComponent (segundoBoton);
    }
    
    public void elButtonClick (Button.ClickEvent event) {
        elBoton.setCaption ("No presione este botón de nuevo");
    }

    public void segundoButtonClick (Button.ClickEvent event) {
        segundoBoton.setCaption("Yo no soy un número");
    }
}

Agregar un método oyente con addListener() es realmente sólo un wrapper que crea un objeto oyente com.vaadin.event.ListenerMethod, que es un adaptador desde una clase oyente a un método. Este implementa la interfaz java.util.EventListener y por lo tanto puede trabajar para cualquier origen de eventos utilizando la interfaz. Tenga en cuenta que no todas las clases oyentes necesariamente heredan la interfaz EventListener.

La tercera forma, que utiliza definiciones de clases locales anónimas, es a menudo la más fácil ya que no necesita obstaculizar la administración de la clase con nuevas interfaces o métodos. En el siguiente ejemplo se define una clase anónima que hereda la interfaz Button.ClickListener e implementa el método buttonClick().

public class ElBoton3 {
    Button elBoton;
    Button segundoBoton;

    /** Crear dos botones en el contenedor proporcionado. */
    public ElBoton3(AbstractComponentContainer contenedor) {
        elBoton = new Button ("No presione este botón");

        /* Define un oyente en una clase anonima. */
        elBoton.addListener(new Button.ClickListener() {
            /* Controlar el clic. */
            public void buttonClick(ClickEvent event) {
                elBoton.setCaption (
                        "No presione este botón de nuevo");
            }
        });
        contenedor.addComponent(elBoton);
        
        segundoBoton = new Button ("Yo soy un botón también");
        segundoBoton.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                segundoBoton.setCaption ("Yo no soy un número!");            
            }
        });
        contenedor.addComponent (segundoBoton);
    }
}

También existen otras técnicas para la separación entre las diferentes fuentes. Ellas incluyen el uso de las propiedades de los objetos, nombres o títulos para separarlos entre ellos. Utilizar títulos o cualquier otro texto visible es generalmente desalentador, ya que puede crear problemas para la internacionalización. Utilizar otras cadenas simbólicas también puede ser peligroso, porque la sintaxis de estas cadenas se verifican sólo en tiempo de ejecución.

Los eventos son generalmente emitidos por el framework, pero también las aplicaciones pueden necesitar emitirlos en algunas situaciones, como cuando se requiere actualizar alguna parte de la interface de usuario. Los eventos pueden emitirse utilizando el método fireEvent(Component.Event) de AbstractComponent. El evento entonces es retransmitido a todos los oyentes del evento en particular de la clase para el objeto. Algunos componentes tienen un tipo de evento por defecto, por ejemplo, un Button tiene una clase Button.ClickEvent anidada y una correspondiente interfaz Button.ClickListener. Estos eventos pueden ser desencadenados con fireComponentEvent().



Anterior
4.3. Ventanas Secundarias
Siguiente
4.5. Referenciar Recursos

4.3. Ventanas Secundarias

Una ventana de nivel de aplicación puede tener varias ventanas secundarias flotantes. Están son manejadas por JavaScript del lado del cliente en tiempo de ejecución con características HTML utilizando Vaadin. Vaadin permite abrir y cerrar ventanas secundarias, refrescar una ventana desde otra, cambiar el tamaño de las ventanas, y desplazar el contenido de la ventana. Las ventanas secundarias normalmente son utilizadas por Ventanas de Diálogo y aplicaciones de Interfaz de Múltiples Documentos. Las ventanas secundarias son por defecto no modales; puede establecerlas a modales como se describe en la Sección 4.3.4, "Ventanas Modales".

Al igual que con todos los componentes de interfaz de usuario, la apariencia de una ventana y sus contenidos son definidos con los temas.

El control del usuario a una ventana secundaria está limitada a mover, redimensionar y cerrar la ventana. Maximizar o minimizar aún no están soportados.

4.3.1. Abrir y Cerrar Ventanas Secundarias

Puede abrir una ventana nueva creando un nuevo objeto Window y agregarlo a la ventana principal con el método addWindow() de la clase Application.

miVentana = new Window("Mi Ventana");
ventanaPrincipal.addWindow(miVentana);


Cierre la ventana de una manera similar, llamando a removeWindow() de la clase Application.

miAplicacion.removeWindow (miVentana);


El usuario puede, por defecto, cerrar una ventana secundaria haciendo clic en el botón de cierre en la esquina superior derecha de la ventana. Puede desactivar el botón estableciendo la ventana como de sólo lectura con setReadOnly(true). Tenga en cuenta que también puede deshabilitar el botón haciéndolo invisible en CSS con el formato "display: none". El problema con esta deshabilitación estética es que un usuario malintencionado podría volver a habilitar el botón y cerrar la ventana, lo que podría causar problemas y, posiblemente, ser un agujero de seguridad. Configurando la ventana como de sólo lectura no sólo desactiva el botón de cierre del lado del cliente, sino que también impide procesar el evento cerrar del lado del servidor.

El siguiente ejemplo demuestra el uso de una ventana secundaria en una aplicación. El ejemplo maneja la ventana con un componente personalizado que contiene un botón para abrir y cerrar la ventana.

/** El componente contiene un botón que permite abrir una ventana. */
public class AbridorVentana extends CustomComponent
                          implements Window.CloseListener {
    Window ventanaPrincipal;  // Referencia a la ventana principal
    Window miVentana;    // La ventana que se abrirá
    Button botonAbrir;  // El botón para abrir la ventana
    Button botonCerrar; // Un botón en la ventana
    Label  explicacion; // Un texto descriptivo

    public AbridorVentana(String label, Window principal) {
        ventanaPrincipal = principal;

        // El componente contiene un botón que abre la ventana.
        final VerticalLayout disenio = new VerticalLayout();
        
        botonAbrir = new Button("Abrir Ventana", this,
                                "abrirButtonClick");
        explicacion = new Label("Explicación");
        disenio.addComponent(botonAbrir);
        disenio.addComponent(explicacion);
        
        setCompositionRoot(disenio);
    }

    /** Controlar los clics de los dos botones. */
    public void abrirButtonClick(Button.ClickEvent event) {
        /* Crear una nueva ventana. */
        miVentana = new Window("Mi Cuadro de Diálogo");
        miVentana.setPositionX(200);
        miVentana.setPositionY(100);

        /* Agregar la ventana dentro de la ventana principal. */
        ventanaPrincipal.addWindow(miVentana);

        /* Escuchar los eventos 'cerrar' para la ventana. */
        miVentana.addListener(this);

        /* Agregar los componentes en la ventana. */
        miVentana.addComponent(
                new Label("Una etiqueta de texto en la ventana."));
        botonCerrar = new Button("Cerrar", this, "cerrarButtonClick");
        miVentana.addComponent(botonCerrar);

        /* Permitir abrir sólo una ventana a la vez. */
        botonAbrir.setEnabled(false);

        explicacion.setValue("Ventana abierta");
    }

    /** Controlar el clic del botón botonCerrar y cierre de la ventana. */
    public void cerrarButtonClick(Button.ClickEvent event) {
        /* Las ventanas son manejadas por el objeto application. */
        ventanaPrincipal.removeWindow(miVentana);

        /* Volver al estado inicial. */
        botonAbrir.setEnabled(true);

        explicacion.setValue("Cerrado con el botón");
    }

    /** En caso de que la ventana sea cerrada de otro modo. */
    public void windowClose(CloseEvent e) {
        /* Volver al estado inicial. */
        botonAbrir.setEnabled(true);

        explicacion.setValue("Cerrado con controles de la ventana");
    }
}

El ejemplo implementa un componente personalizado que hereda la clase CustomComponent. Este consiste de un Button que se utiliza para abrir una ventana y un Label para describir el estado de la ventana. Cuando la ventana es abierta, el botón es deshabilitado. Cuando la ventana es cerrada, el botón es habilitado de nuevo.

Puede utilizar el componente personalizado de arriba en la clase application con:

 public void init() { 
    Window principal = new Window("La Ventana Principal"); 
    setMainWindow(principal);

    principal.addComponent(new AbridorVentana("Abridor de Ventana", principal));
}

Cuando se agrega a una aplicación, la pantalla se verá cómo se ilustra en el siguiente pantallazo:

Figura 4.2. Abriendo una Ventana Secundaria

4.3.2. Posicionar una Ventana

Cuando es creada, una ventana tendrá un tamaño y una posición predeterminada. Puede especificar el tamaño de una ventana con los métodos setHeight() y setWidth(). Puede establecer la posición de la ventana con los métodos setPositionX() y setPositionY().

/* Crear una ventana nueva. */
miVentana = new Window("Mi Cuadro de Dialogo");
 
/* Establecer el tamaño de la ventana. */
miVentana.setHeight("200px");
miVentana.setWidth("400px");
 
/* Establecer la posición de la ventana. */
miVentana.setPositionX(200);
miVentana.setPositionY(50);

Tenga en cuenta que el tamaño de la ventana principal es desconocido y los métodos getHeight y getWidth devolverán -1.

4.3.3. Desplazamiento del Contenido en Ventanas Secundarias

Si una ventana secundaria tiene un tamaño fijo o porcentual y su contenido es demasiado grande para ajustarse al área del contenido, una barra de desplazamiento aparecerá para la dirección en particular. Por otro lado, si la ventana secundaria tiene un tamaño indefinido en la dirección, este se ajustará al tamaño del contenido y nunca obtener una barra de desplazamiento. Las barras de desplazamiento en las ventanas secundarias regulares son manejadas con características HTML, es decir, la propiedad overflow: auto en CSS.

Como Window extiende a Panel, las ventanas también son Scrollable. Tenga en cuenta que la interfaz define un desplazamiento programático, no un desplazamiento por el usuario. Por favor, consulte la Sección 6.6, "Panel".

4.3.4. Ventanas Modales

Una ventana modal es una ventana secundaria que tiene que ser cerrada por el usuario antes de poder continuar para usar la ventana padre. Las ventanas de cuadro de diálogo son generalmente modales. La ventaja de las ventanas modales es la simplificación de la interacción del usuario, que puede contribuir a la claridad de la interfaz de usuario. Las ventanas modales también son fáciles de utilizar desde una perspectiva de desarrollo, porque, la interacción del usuario es aislada para ellos, los cambios en el estado de la aplicación son más limitados, mientras que la ventana modal esté abierta. La desventaja de las ventanas modales es que pueden restringir demasiado el flujo de trabajo.

Figura 4.3. Pantallazo de la Aplicación Demostracion Ventana Modal

Dependiendo de la configuración del tema, la ventana padre puede ser atenuada, mientras la ventana modal esté abierta.

La aplicación demo de Vaadin incluye un ejemplo del uso de ventanas modales. La Figura 4.3, "Pantallazo de la Aplicación Demostracion Ventana Modal" arriba es de la aplicación demo. El ejemplo incluye el código fuente.

Advertencia de Seguridad
La modalidad de las ventanas secundarias es meramente una característica del lado del cliente y puede ser burlado con el ataque por código del lado del cliente. No debe confiar en la modalidad de las ventanas secundarias en situaciones críticas de seguridad tales como las ventanas de inicio de sesión.



Anterior
4.2. Administrar la Ventana Principal
Siguiente
4.4. Controlar Eventos con Oyentes

4.2 Administrar la Ventana Principal

Como se explicó en la Sección 12.1, "Caracteristicas Especiales de Aplicaciones AJAX", una aplicación web de AJAX por lo general se ejecuta en una sola "página web" en una ventana del navegador. Generalmente la página no es recargada después de que es abierta al principio, pero comunica la interacción del usuario con el servidor a través de comunicaciones AJAX. Una ventana en una aplicación AJAX es por lo tanto más como una ventana en una aplicación de escritorio y menos como una página web.

Window es el contenedor de nivel superior de una interfaz de usuario mostrado en una ventana de navegador. Cuando una aplicación AJAX normalmente se ejecuta en una sola "página" (URL), por lo general hay una sola ventana, la ventana principal. Se puede acceder a la ventana principal utilizando la dirección URL de la aplicación. Establezca la ventana principal con el método setMainWindow() de la clase Application.

import com.vaadin.ui.*;

public class HolaMundo extends com.vaadin.Application {
    public void init() { 
        Window principal = new Window("La Ventana Principal"); 
        setMainWindow(principal);

        ... llene la ventana principal con componentes ...     }
}

Puede agregar componentes a la ventana principal, o a cualquier otra ventana, con el método addComponent(), que en realidad añade el componente al componente de diseño raíz vinculado a la ventana. Si desea utilizar otro diseño raíz por defecto, puede establecerlo con setContent(), como se explica en la Sección 6.2, "Diseño Raiz Window y Panel".

Vaadin tiene dos tipos básicos de ventana: las ventanas de nivel de aplicación, tales como la ventana principal y las ventanas secundarias (o sub-ventanas) dentro de las ventanas de nivel de aplicación. Las ventanas secundarias se explican en la siguiente sección, mientras que las ventanas de nivel de aplicación se tratan en la Sección 12.2, "Ventanas de Nivel de Aplicación".



Anterior
Capítulo 4. Escribir una Aplicación Web
Siguiente
4.3. Ventanas Secundarias

Capítulo 4. Escribir una Aplicación Web

Este capítulo proporciona los fundamentos del desarrollo de aplicaciones web con Vaadin, concentrándose en los elementos básicos de una aplicación desde un punto de vista práctico.

Si eres un principiante en el desarrollo con AJAX, puede beneficiarse de la Sección 12.1, "Caracteristicas Especiales de Aplicaciones AJAX". En él se explica el rol de las páginas en aplicaciones web AJAX, y proporciona algunos modelos de diseño básico para las aplicaciones.

4.1. Información General

Una aplicación hecha con Vaadin se ejecuta como un Servlet Java en un contenedor de Servlets. El punto de entrada es la clase application, que necesita crear y administrar todos los componentes de la interfaz de usuario necesarios, incluyendo las ventanas. La interacción del usuario es manejada con oyentes de eventos, simplificado directamente por las vinculaciones de los componentes de interfaz de usuario a los datos. El aspecto visual es definido en temas como archivos CSS. Los iconos, otras imágenes, y archivos descargables son manejados como recursos, que pueden ser externos o servidos por el servidor de aplicaciones o por la propia aplicación.

Figura 4.1. Arquitectura de una Aplicación

La Figura 4.1, "Arquitectura de una Aplicación" arriba es la arquitectura básica de una aplicación hecha con el framework Vaadin, con todos los elementos principales, que se presentan a continuación y discutidos en detalle en este capítulo.

Primero que todo, una aplicación que utiliza Vaadin debe definir una clase application que hereda la clase abstracta com.vaadin.Application. La clase application debe implementar el método init().

public class MiApp extends com.vaadin.Application {

    public void init() { 
        ... el código de inicialización va aquí ...
    }
}

Además de actuar como el punto de entrada en el servlet, la clase Application proporciona facilidades para acceder a la ventana, el control de ejecución y la selección de temas. La API de application puede parecer similar a la API de Java Servlet, pero sólo es superficial. El framework Vaadin asocia las peticiones con sesiones, de modo que una instancia de la clase application es realmente un objeto de sesión. Debido a esto, puede desarrollar aplicaciones web, como lo haría con el desarrollo de aplicaciones de escritorio.

Reiniciar la Sesión de la Aplicación

Cuando abre la dirección URL de la aplicación, se crea una nueva sesión de usuario. La sesión se conserva incluso si vuelve a cargar la página. Sin embargo, ya que a Eclipse le gusta hacer el despliegue en caliente para Tomcat, y a Tomcat le gusta persistir sesiones en el cierre del servidor, usted puede experimentar un problema y es que la aplicación no vuelve a su estado inicial después de modificar el código o incluso reiniciar el servidor.

Añadiendo el parámetro ?restartApplication en la URL le indica al servlet Vaadin que cree una nueva instancia de Application cuando se recarge la página.

Lo más importante en la inicialización, es la creación de la ventana principal (véase más adelante), que cualquier aplicación tiene. Esto, y el despliegue de la aplicación como un Servlet Java en el contenedor de Servlets, tal como se describe en la Sección 4.8, "Configurar el Entorno de la Aplicación", son los requisitos mínimos para una aplicación.

A continuación se muestra una breve descripción de los elementos básicos de una aplicación:

Ventanas
Una aplicación siempre tiene una ventana principal, tal como se describe en la Sección 4.2, "Administrar la Ventana Principal". Una aplicación puede realmente tener varias ventanas de nivel de aplicación, todas unidas a la misma sesión de la aplicación, como se describe en la Sección 12.2, "Ventanas de Nivel de Aplicación". Las ventanas de nivel de aplicación pueden contener sub-ventanas no nativas, que son esencialmente los componentes de diseño flotante manejados dentro del navegador.

Componentes de Interfaz de Usuario
La interfaz de usuario se compone de los componentes de interfaz de usuario (UI) que son creados y presentados por la aplicación. La interacción del usuario con los componentes causa eventos (véase abajo) relacionados con el componente que la aplicación debe manejar. La mayor parte de los componentes están vinculados a algun dato utilizando el Modelo de Datos (véase abajo). Puede hacer sus propios componentes de interfaz de usuario ya sea a través de herencia o composición. Para una referencia completa de los componentes de interfaz de usuario, véase el Capítulo 5, Componentes de Interfaz de Usuario, para los componentes de diseño, vea el Capítulo 6, Admnistrar el Diseño, y para la composición de componentes, consulte la Sección 5.23 "Composición de Componentes con CustomComponent".

Eventos y Oyentes
Los eventos y oyentes que manejan los eventos, son la base del manejo de la interacción del usuario en una aplicación. La Sección 3.5, "Eventos y Oyentes" aportó una introducción a los eventos y oyentes desde un punto de vista arquitectónico, mientras que la Sección 4.4, "Controlar Eventos con Oyentes", más adelante este capítulo tiene una visión más práctica.

Recursos
Una interfaz de usuario puede mostrar imágenes o enlaces a páginas web o documentos descargables. Estos son recursos, que pueden ser externos o proporcionados por el servidor web o la propia aplicación. La Sección 4.5, "Referencias Recursos" proporciona una visión práctica de los diferentes tipos de recursos.

Temas (Estilos)
La presentación y la lógica de la interfaz de usuario están separadas. Mientras que la lógica de la interfaz de usuario es controlada como código de Java, la presentación es definida en temas como CSS. Vaadin proporciona un tema predeterminado. Los temas definidos por el usuario pueden, ademas de las hojas de estilo, incluir plantillas HTML que definen diseños personalizados y otros recursos temáticos, tales como imágenes. Los temas son discutidos en detalle en el Capítulo 8, Temas, los diseños personalizados en la Sección 6.13, "Diseños Personalizados", y los recursos de temas en la Sección 4.5.4, "Recursos de Temas".

Vincular Datos
Los campos de los componentes son esencialmente vistas a datos, representados en un modelo de datos. Utilizando el modelo de datos, los componentes pueden actualizar los datos de la aplicación directamente, sin la necesidad de ningún código de control. Un modelo de componentes de un campo siempre está vinculado a una propiedad, un elemento, o un contenedor, dependiendo del tipo de campo. Si bien todos los componentes tienen un modelo de datos por defecto, que pueden vincularse a un origen de datos definido por el usuario. Por ejemplo, puede vincular un componente table a la respuesta de una consulta SQL. Para una descripción completa de vinculación de datos en Vaadin, por favor, consulte el Capítulo 9, "Vincular Componentes a Datos".



Anterior
3.5. Eventos y Oyentes
Siguiente
4.2. Administrar la Ventana Principal

3.5. Eventos y Oyentes

Vaadin ofrece un modelo de programación orientada a eventos para el manejo de la interacción del usuario. Cuando un usuario hace algo, como hacer clic en un botón o seleccionar un elemento, la aplicación necesita tener conocimiento de esto. Muchos frameworks basados en interfaz de usuario Java siguen el modelo Evento-Oyente (conocido tambien como el modelo de diseño Observador) para comunicar la entrada de datos por el usuario a la lógica de la aplicación. Vaadin también lo hace. El modelo de diseño implica dos clases de elementos: un objeto que genera ("dispara" o "emite") eventos y un número de oyentes que escuchan los eventos. Cuando ocurre un evento, el objeto envía una notificación de ello a todos los oyentes. En un caso típico, sólo hay un oyente.

Los eventos pueden servir para muchos propósitos. En Vaadin, el propósito habitual de los eventos es manejar la interacción del usuario en una interfaz de usuario. La administración de sesiones puede requerir eventos especiales, tales como el tiempo-muerto, cuyo caso el evento es en realidad la falta de interacción del usuario. El tiempo-muerto es un caso especial de eventos programados o previstos, donde un evento ocurre en una fecha y hora específica o cuando se ha cumplido una hora. Las bases de datos y otros tipos de comunicación asincrónica también pueden causar eventos.

Para recibir eventos de un tipo en particular, una aplicación debe registrar un objeto oyente con el origen del evento. Los oyentes son registrados en los componentes con el addListener(). El método tiene una versión genérica definida en el nivel de AbstractComponent, la clase base de todos los componentes.

La mayoría de los componentes que tienen eventos relacionados definen su propia clase de evento y sus respectivas clases oyentes. Por ejemplo, Button tiene eventos Button.ClickEvent, el cual puede ser escuchado a travéz de la interfaz Button.ClickListener.

A continuación, manejamos los clics de button con un oyente implementado como una clase anónima:

final Button button = new Button("Presionalo!");

button.addListener(new Button.ClickListener() {
    public void buttonClick(ClickEvent event) {
        button.setCaption("Lo presionaste!");
    }
});

La Figura 3.3, "Diagrama de Clases de un Oyente de Clic de Button" ilustra un ejemplo donde una clase específica de la aplicación hereda la interfaz Button.ClickListener capaz de escuchar eventos clic de button. La aplicación debe crear instancias de la clase oyente y registrarla con addListener(). Cuando ocurre un evento, el evento de un objeto es instanciado, en este caso un ClickEvent. El evento del objeto conoce el componente de interfaz de usuario relacionado, en este caso Button.

Figura 3.3. Diagrama de Clases de un Oyente de Clic de Button

En los viejos tiempos de programación en C, las retrollamadas a funciones llenaron en gran parte la misma necesidad como los oyentes lo hacen ahora. En lenguajes orientados a objetos, sólo tenemos clases y métodos, no funciones, por lo que la aplicación tiene que proporcionar una clase interface en lugar de un puntero a una retrollamada de función al framework. Sin embargo, Vaadin también admite la definición de un método como un oyente, utilizando el wrapper MethodListener.

Tenga en cuenta que muchas interfaces oyentes heredan de la superinterface java.util.EventListener, pero generalmente no es necesario heredarlo.

La Sección 4.4, "Controlar Eventos con Oyentes" explica en detalle como manejar eventos en la práctica.



Anterior
3.4. Motor del Lado del Cliente
Siguiente
Capítulo 4. Escribir una Aplicación Web

3.4. Motor del Lado del Cliente

Esta sección proporciona una descripción de la arquitectura del lado del cliente de Vaadin. El conocimiento de las tecnologías de lado del cliente no es generalmente necesario a menos que desarrolle o use componentes GWT personalizados. El motor del lado del cliente se basa en Google Web Toolkit (GWT), que permite el desarrollo del motor y de los componentes del lado del cliente únicamente con Java.

El Capítulo 11, Desarrollar Nuevos Componentes proporciona información acerca de la integración de los componentes de la interfaz de usuario basados en GWT con Vaadin.

Figura 3.2 Arquitectura del Motor de Lado del Cliente de Vaadin

La Figura 3.2, "Arquitectura del Motor de Lado del Cliente de Vaadin" ilustra la arquitectura del motor del lado del cliente utilizando un componente button como ejemplo. La interfaz de usuario es manejada por la clase ApplicationConnection, la cual maneja las peticiones AJAX al servidor y renderiza la interfaz de usuario de acuerdo a las respuestas. Las comunicaciones se realizan a través de HTTP(S), utilizando el formato de intercambio de datos JSON y el Lenguaje de Definición de Interfaz de Usuario (UIDL). Del lado del servidor en la aplicación, button utiliza la clase Button de Vaadin. En el lado del cliente, la interfaz de usuario se compone de varios componentes GWT que heredan la clase Widget. En la figura anterior, la clase Button de GWT se utiliza para renderizar el botón en el navegador (la herencia de Button se ha simplificado en la figura). Vaadin proporciona una clase VButton, que implementa la interfaz Paintable necesaria para renderizar el componente con GWT.

La actual página web inicial que es cargada en el navegador es una página en blanco que carga el código JavaScript del Motor del Lado del Cliente de Vaadin. Después de que es cargado e iniciado, maneja las peticiones AJAX al servidor. Todas las comunicaciones del servidor se realizan a través de la clase ApplicationConnection.

La comunicación con el servidor se realiza como mensajes UIDL (Lenguaje de Definición de Interfaz de Usuario) usando el formato de intercambio de mensajes JSON sobre una conexión HTTP(S). UIDL es descrito en el Apéndice A, Lenguaje de Definición de Interfaz de Usuario (UIDL) y JSON en la Sección 3.2.3, "JSON" y la Sección A.2, "Renderizar JSON".



Anterior
3.3. Aplicaciones como Sesiones de Java Servlet
Siguiente
3.5. Eventos y Oyentes

3.3. Aplicaciones como Sesiones de Java Servlet

El Framework Vaadin hace básicamente todo lo que hace en la parte superior de la API Java Servlet, la cual se encuentra oculta bajo la capucha, con el adaptador de terminal que es la capa de nivel más baja para el manejo de las peticiones del contenedor web.

Cuando el contenedor web recibe la primera solicitud de una dirección URL registrada para una aplicación, se crea una instancia de la clase ApplicationServlet en el framework Vaadin que hereda la clase HttpServlet definida en la API Java Servlet. De ello resultan sesiones utilizando la interfaz HttpSession y asociando una instancia de Application con cada sesión. Durante el tiempo de vida de una sesión, el framework transmite las acciones del usuario a la instancia application correcta y, además, a un componente de interfaz de usuario.



Anterior
3.2. Antecedentes Tecnológicos
Siguiente
3.4. Motor del Lado del Cliente

3.2. Antecedentes Tecnológicos

Esta sección proporciona una introducción a varias tecnologías y diseños en los cuales Vaadin está basado: las aplicaciones web basadas en AJAX en general, Google Web Toolkit, y el formato de intercambio de datos JSON. Este conocimiento no es necesario para usar Vaadin, pero proporciona algunos antecedentes, si necesita hacer extensiones de bajo nivel a Vaadin.

3.2.1. AJAX

AJAX (JavaScript y XML asincrónico) es una técnica para desarrollar aplicaciones web con la interacción de las respuestas del usuario, similar a las aplicaciones de escritorio tradicionales. Mientras que JavaScript este habilitado para las páginas HTML puede recibir nuevo contenido sólo con actualizaciones de la página, las páginas con AJAX habilitado envían la interacción del usuario con el servidor utilizando una solicitud asincrónica y reciben el contenido actualizado en la respuesta. De esta manera, sólo una pequeña parte de los datos de la página pueden ser cargados. Esta meta se logra usando un determinado conjunto de tecnologías: XHTML, CSS, DOM, JavaScript XMLHttpRequest y XML.

Con todo el alboroto y el estruendo que recibe, AJAX, es esencialmente hecho posible gracias a una sencilla API, es decir, la clase XMLHttpRequest en JavaScript. La API está disponible en todos los principales navegadores y, a partir del 2006, la API está en camino a convertirse en un estándar del W3C.

Las comunicaciones entre el navegador y el servidor por lo general requieren de alguna clase de serialización (o clasificación) de objetos de datos. AJAX sugiere el uso de XML para la representación de datos en las comunicaciones entre el navegador y el servidor. Mientras que la versión 4 de Vaadin utiliza XML para el intercambio de datos, la versión 5 utiliza JSON más eficientemente. Para obtener más información acerca de JSON y su uso en Vaadin, véase la Sección 3.2.3, "JSON".

Si es un principiante en Ajax, la Sección 12.1, "Caracteristicas Especiales de Aplicaciones AJAX", trata sobre la historia y motivaciones para aplicaciones web basadas en AJAX, así como algunas características especiales que diferencian tanto las aplicaciones web tradicionales como las aplicaciones de escritorio.

3.2.2. Google Web Toolkit

Google Web Toolkit es un kit de desarrollo de software para desarrollar aplicaciones web del lado cliente de forma fácil, sin necesidad de tener que utilizar directamente JavaScript u otras tecnologías de navegador. Las aplicaciones que utilizan GWT son desarrolladas con Java y compiladas en JavaScript con el Compilador de GWT.

GWT es esencialmente una tecnología del lado del cliente, normalmente se utiliza para desarrollar la lógica de la interfaz de usuario en el navegador web. Las aplicaciones de GWT necesitan comunicarse con un servidor utilizando llamadas RPC y la serialización de cualquier dato. Vaadin oculta de manera eficaz todas las comunicaciones cliente-servidor, permite al usuario manejar la lógica de interacción en un servidor de aplicaciones, y les permite el desarrollo de software en un único servidor de aplicaciones. Esto hace mucho más simple la arquitectura de una aplicación web basada en AJAX.

Vaadin usa GWT para hacer interfaces de usuario en el navegador web y manejar las tareas de bajo nivel de interacción del usuario en el navegador. El uso de GWT es prácticamente invisible en Vaadin para las aplicaciones que no necesiten ningún componente GWT personalizado.

Vea la Sección 3.4, "Motor del Lado del Cliente" para una descripción de cómo se utiliza GWT en el Motor de Lado del Cliente de Vaadin. El Capítulo 11, Desarrollar Nuevos Componentes proporciona información sobre la integración de los componentes de la interfaz de usuario basada en GWT con Vaadin.

3.2.3. JSON

JSON es un formato ligero de intercambio de datos que es fácil y rápido de generar y analizar. Con la tecnología actual del navegador se dice que los mensajes JSON son posiblemente cien veces más rápido de analizar que XML. El formato es un subgrupo del lenguaje JavaScript, que permite evaluar los mensajes JSON directamente como expresiones JavaScript. Esto hace que JSON sea muy fácil de utilizar en aplicaciones JavaScript y por lo tanto también en aplicaciones AJAX.

El Motor del Lado del Cliente de Vaadin utiliza JSON a través de Google Web Toolkit, que soporta comunicaciones JSON en el paquete com.google.gwt.json.client. Junto con la optimización de actualización avanzada y el almacenamiento en caché, Vaadin es capaz de actualizar los cambios en la interfaz de usuario al navegador de una forma muy eficiente.

El uso de JSON es completamente invisible para un desarrollador que utiliza Vaadin. La implementación de la serialización del cliente-servidor en los widgets personalizados utiliza interfaces abstractas que se pueden implementar como cualquier formato de intercambio de bajo nivel, tales como XML o JSON. Detalles sobre las comunicaciones JSON se ofrecen en la Sección A.2, "Renderizar JSON".



Anterior
Capítulo 3. Arquitectura
Siguiente
3.3. Aplicaciones como Sesiones de Servlets Java

Capítulo 3. Arquitectura

Este capítulo proporciona una introducción a la arquitectura de Vaadin en un nivel un tanto técnico.

3.1. Información General

En el Capítulo 1, Introducción, dimos una breve introducción a la arquitectura general de Vaadin. Ahora vamos a profundizar en ella. La Figura 3.1, "Arquitectura de Vaadin" proporciona una ilustración básica de la arquitectura.

Figura 3.1. Arquitectura de Vaadin

Vaadin consiste de una API de aplicación web, una multitud de componentes de interfaz de usuario, temas para controlar la apariencia, y un modelo de datos que le permite vincular los componentes de interfaz de usuario directamente a los datos. Detrás de las cortinas también se emplea un adaptador de terminal para recibir las peticiones de los navegadores web y hacer las respuestas renderizando las páginas.

Una aplicación que utiliza Vaadin se ejecuta como un servlet en un servidor web de Java, sirviendo peticiones HTTP. El adaptador de terminal recibe solicitudes de los clientes a través del servidor web de la API de Java Servlet, y los interpreta para los eventos de usuario para una determinada sesión en particular. Las sesiones son rastreadas utilizando cookies. Los eventos están asociados con los componentes de interfaz de usuario (UI) y entregados a la aplicación, el cual es manejado con oyentes (listeners). Si la lógica de la aplicación realiza cambios en los componentes de interfaz de usuario del lado del servidor, el adaptador de terminal los renderiza en el navegador web generando una respuesta. El motor del lado del cliente que se ejecuta en el navegador recibe las respuestas y los utiliza para hacer los cambios necesarios en la página en el navegador.

El nivel superior de una aplicación de usuario consiste en una clase application que hereda de com.vaadin.Application. Esto crea los componentes de interfaz de usuario que necesita (véase más adelante), recibe los eventos relacionados con ellos, y hace los cambios necesarios en los componentes. Para obtener información detallada sobre heredamiento de Application, vea el Capítulo 4, Escribir una Aplicación Web.

Las partes más importantes de la arquitectura y su función son las siguientes:
  • Componentes de Interfaz de Usuario
    Los componentes de la interfaz de usuario se componen de los componentes de interfaz de usuario que son creados y presentados por la aplicación. Cada componente del lado del servidor tiene una contraparte del lado del cliente, con la cual el usuario interactúa. Los componentes del lado del servidor pueden serializar la conexión del cliente con un adaptador de terminal. Los componentes del lado del cliente, a su vez, pueden serializar la interacción del usuario de nuevo a la aplicación, que es recibida en los componentes del lado del servidor como eventos. Los componentes transmiten estos eventos a la lógica de la aplicación. La mayoría de los componentes están vinculados a un origen de datos (véase más adelante). Para una descripción completa de la arquitectura de los componentes de interfaz de usuario, véase el Capítulo 5, Componentes de Interface de Usuario.

    Motor de Lado del Cliente
    El Motor del Lado del Cliente de Vaadin gestiona la renderización en el navegador web a través de Google Web Toolkit (GWT). Este comunica la interacción del usuario y los cambios de la interfaz de usuario con el Adaptador de Terminal del lado del servidor usando el Lenguaje de Definición de Interfaz de Usuario (UIDL), un lenguaje basado en JSON. Las comunicaciones se realizan mediante HTTP asincrónico o peticiones HTTPS. Vea la Sección 3.4. "Motor del Lado del Cliente".

    Adaptador de Terminal
    Los componentes de interfaz de usuario no se renderizan ellos mismos directamente como una página web, pero usan un Adaptador de Terminal. Esta capa de abstracción permite a los usuarios utilizar aplicaciones Vaadin con prácticamente cualquier navegador web. Las Versiones 3 y 4 de IT Mill Toolkit soporaba HTML y un simple renderizado basado en AJAX, mientras que la versión 5 de Vaadin soporta renderizaciones avanzadas basadas en AJAX utilizando Google Web Toolkit (GWT). Se podría imaginar alguna otra tecnología de navegador, ni siquiera basada en HTML, y usted - o en realidad - podríamos hacerlo trabajar sólo escribiendo un nuevo adaptador. Su aplicación todavía vería la API de Vaadin. Para permitir este tipo de abstracción, los componentes de interfaz de usuario comunican sus cambios al Adaptador de Terminal, que los renderiza para el navegador del usuario. Cuando el usuario hace algo en la página web, los eventos son comunicados al adaptador de terminal (a través del servidor web) como peticiones asincrónicas AJAX. El adaptador de terminal entrega los eventos del usuario a los componentes de interfaz de usuario, que se los entrega a la lógica de la aplicación de interfaz de usuario.

    Temas (Estilos)
    La interfaz de usuario se separa entre la presentación y la lógica. Mientra que la lógica de interfaz de usuario se maneja como código de Java, la presentación se define en temas como CSS. Vaadin proporciona unos temas por defecto. Los temas del usuario pueden, además de las hojas de estilo, plantillas HTML que definen diseños personalizados y otros recursos, tales como imágenes. Los temas se discuten en detalle en el Capítulo 8, Temas.

    UIDL
    El Adaptador de Terminal dibuja la interfaz de usuario a la página web y cualquier cambio en él usando un especial Lenguaje de Definición de Interfaz de Usuario (UIDL). Las comunicaciones UIDL se realizan mediante JSON (JavaScript Object Notation), que es un formato de intercambio de datos ligero que es especialmente eficaz para interconectar con el código AJAX basadas en JavaScript en el navegador. Consulte la Sección 3.2.3, "JSON" y el Apéndice A, Lenguaje de Definición de Interfaz de Usuario (UIDL) para mas detalles.

    Eventos
    La interacción del usuario con los componentes de interfaz de usuario crea eventos, que primero son procesados del lado del cliente con JavaScript y luego son pasados todo el camino a través del servidor HTTP, el adaptador de terminal, y las capas de los componentes de usuario a la aplicación. Vea la Sección 3.5, "Eventos y Oyentes".

    Modelo de Datos
    Además del modelo de interfaz de usuario, Vaadin proporciona un modelo de datos para interconectar los datos presentados en los componentes de interfaz de usuario. Usando el modelo de datos, los componentes de interfaz de usuario pueden actualizar los datos de la aplicación directamente, sin necesidad de ningún código de control. Todos los componentes de interfaz de usuario utilizan este modelo de datos internamente, pero pueden ser vinculados a una fuente de datos separada. Por ejemplo, puede vincular un componente table a una respuesta de las consultas SQL. Para una descripción completa del Modelo de Datos de Vaadin, por favor, consulte el Capítulo 9, Vincular Componentes a Datos.



Anterior
2.5. Crear un Proyecto con Maven
Siguiente
3.2. Antecedentes Tecnológicos

2.5. Crear un Proyecto con Maven

La librería principal de Vaadin y todo los complementos Vaadin están disponibles a través de un repositorio Maven y por lo tanto puede utilizarse fácilmente con Apache Maven. Puede utilizar Maven con un interfaz-grafica de Eclipse o NetBeans, o utilizando la línea de comandos como se describe en esta sección.

Puede crear un nuevo proyecto Maven con el siguiente comando:
$ mvn archetype:generate
    -DarchetypeGroupId=com.vaadin
    -DarchetypeArtifactId=vaadin-archetype-clean
    -DarchetypeVersion=LATEST
    -DgroupId=tu.compania -DartifactId=nombre-proyecto -Dversion=1.0 -Dpackaging=war
Los parámetros son los siguientes:

archetypeGroupId
El group ID del arquetipo es com.vaadin para arquetipos Vaadin.

archetypeArtifactId
El archetype ID. Vaadin es compatible actualmente con los siguientes arquetipos:

  • vaadin-archetype-clean es un nuevo proyecto con un esqueleto barebone para una aplicación Vaadin regular. El archivo pom.xml incluye como-comentario las definiciones para los widgets adicionales.
  • vaadin-archetype-widget es un esqueleto para un proyecto con widgets personalizados.
  • vaadin-archetype-sample también es para el proyecto con widgets personalizados, pero el esqueleto incluye el ejemplo Color Picker utilizado en el Capítulo 11, Desarrollar Nuevos Componentes.
  • vaadin-archetype-addon es para proyectos de complementos Vaadin. Este empaqueta el complemento para que pueda ser publicado en el Directorio Vaadin. El arquetipo es para complementos del lado del servidor y no incluye las definiciones necesarias para la construcción de un conjunto de widgets. Si su complemento incluye o requiere que no sean los widgets de la librería principal Vaadin, debe copiar las definiciones necesarias desde un POM de un proyecto vaadin-arquetipo-clean.
  • vaadin-archetype-touchkit es para proyectos con Vaadin TouchKit, descrito en el Capítulo 19, Aplicaciones Mobiles con TouchKit. Tenga en cuenta que este arquetipo utiliza la versión con licencia AGPL de TouchKit, que exige que el proyecto también debe ser licenciado bajo la licencia AGPL.

archetypeVersion
Versión del arquetipo a usar. Este normalmente debería ser LATEST.

groupId
Este es utilizado para el nombre del paquete Java y normalmente debe ser su nombre de dominio invertido, tal como com.example.myproject. El group ID es utilizado también para el nombre del paquete fuente de Java de su proyecto, por lo que debe ser compatible con Java - sólo caracteres alfanuméricos y un subrayado.

artifactId
Identificador del artifact, este es, su proyecto. El identificador puede contener caracteres alfanuméricos, menos, y subrayado.

version
Número de la versión inicial de su aplicación. El número debe obedecer al formato de la numeración de la versión de Maven.

packaging
Como será empaquetado el proyecto. Normalmente este es un war.

La creación de un proyecto puede tardar un poco ya que Maven busca todas las dependencias. La estructura del proyecto creado se muestra en la Figura 2.8, "Un Nuevo Proyecto Vaadin con vaadin-archetype-clean".

Figura 2.8. Un Nuevo Proyecto Vaadin con vaadin-archetype-clean

Compilar y Ejecutar la Aplicación

Antes de que la aplicación pueda ser desplegada, debe ser compilada y empaquetada como un paquete WAR. Usted puede hacer esto con el goal package de la siguiente manera:

$ mvn package
La ubicación del paquete WAR resultante debe mostrarse en el comando de salida. Luego puede desplegarlo en su servidor de aplicaciones favorito.

La forma más fácil de ejecutar aplicaciones Vaadin con Maven es utilizar el servidor web ligero Jetty. Después de compilar el paquete, todo lo que necesita hacer es teclear:

$ mvn jetty:run
El goal especial arranca el servidor Jetty en el puerto 8080 y despliega la aplicación. Luego puede abrirlo en un navegador web en http://localhost:8080/nombre-proyecto.

Utilizar Complementos y Conjuntos de Widget Personalizados

Si utiliza complementos Vaadin que incluyen un conjunto de widgets o hace sus widgets personalizados, necesita habilitar la compilación de conjunto de widget en el POM. La configuración requerida se describe en la Sección 15.5, "Usar Complementos en un Proyecto Maven".



Anterior
2.4. Crear un Proyecto con Netbeans
Siguiente
Capítulo 3. Arquitectura