Vaadin III: integración con Spring

Finalizo esta serie sobre Vaadin con esta tercera entrega cuyo título es Vaadin III: integración con Spring. En esta entrada, describiré la forma de integrar Spring con Vaadin aplicando el patrón MVP y, además, realizaré un ejemplo básico basado en los ejemplos descritos en la serie. Para aquel lector nuevo en la serie, en la primera entrada Vaadin I: introducción, realicé una breve descripción de Vaadin y un ejemplo básico tipo “Hola Mundo”; y, en la segunda entrada, Vaadin II: MVP con Guava, describo el patrón modelo vista presentador MVP utilizando el componente EventBus de la librería Guava para la gestión de eventos.

Definición del caso práctico

La aplicación ejemplo es prácticamente idéntica a los ejemplos de las entradas anteriores,la diferencia, la utilización del framework Spring. La funcionalidad que defino es muy sencilla ya que mi objetivo es la descripción de la integración y no realizar una aplicación compleja.

Visualmente, la aplicación es idéntica, pero en el objeto Label empleado para mostrar texto de salida, al arrancar la aplicación, se muestra un texto que se genera en un servicio Spring. La imagen de la aplicación es la siguiente:

VaadinIII_spring

VaadinIII_spring

Configuración de Spring en Vaadin

Para emplear Spring en la aplicación, es necesario definir en el fichero pom.xml del proyecto las dependencias de Spring. Las dependencias que utilizo son: spring-core, spring-beans, spring-context y spring-web; la versión de spring,  3.2.4.RELEASE . El contenido del pom es el siguiente:

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>${spring.version}</version>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>${spring.version}</version>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>${spring.version}</version>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-web</artifactId>
 <version>${spring.version}</version>
</dependency>

El contexto Spring se define en el fichero applicationContex.xml; en el cual, se define las referencias de los servicios de la aplicación. Los servicios se encuentran localizados en la carpeta es.directoandroid.service del proyecto. El contenido del fichero applicationContext.xml es el siguiente:

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd">
 <context:component-scan base-package="es.directoandroid.service" />
</beans>

En el fichero de configuración  web.xml, se añade la referencia del contexto spring, y, se añade el Listener del cargador del contexto Spring. El snippet con el contenido a añadir es el siguiente:

... 
<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param> 
...
<listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...

La funcionalidad que se añade en el servlet de la aplicación para la utilización de Spring es muy sencilla, simplemente, se referencia al contexto Spring y, además, definimos un método para obtener la referencia de los servicios definidos en la aplicación. Si se recuerda la entrada anterior, la idea es la misma que la utilizada para la obtención de la referencia al objeto EventBus. La funcionalidad que se añade al servlet MiVaadinServlet es la siguiente:

...
private ApplicationContext applicationContext;
…
@Override
public void init() throws ServletException {
 super.init();
 this.eventBus = new EventBus();
 this.applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); }
...
public Object getContextBean(final String name) {
 return applicationContext.getBean(name);
}
...

Se realiza la Definición del contexto Spring en el servlet de Vaadin porque no se pueden definir como componentes Spring los elementos que intervienen en el UI o CustomComponent de Vaadin para poder realizar la inyección de los elementos. Así, la única manera de realizar la integración de Spring en Vaadin es mediante el contexto de la aplicación Vaadin el cual contiene la referencia al contexto definido en el servlet. Para ello, he empleado un clase que encapsula el acceso al contexto de los servicios; esta clase, es la clase MiSpringInyector la cual define los métodos de los servicios existentes; en nuestro ejemplo, el método que carga el servicio es el siguiente:

public static Servicio servicio() {
 return (ServicioImpl) ((MiVaadinServlet) VaadinServlet.getCurrent()).getContextBean("servicio");
}

MVP (Modelo Vista Presentador) Y Spring

El modelo que he utilizado es una clase con los valores de entrada y de salida.

La vista es la misma que en la entrada anterior.

El presentador es el mismo que el caso anterior salvo que se utiliza la clase MiSpringInyector para cargar el servicio Spring definido como atributo de la clase presentadora. La carga del servicio se realiza en el método bind() de la siguiente forma:

...
private Servicio servicio;
...
bind(){
servicio = MiSpringInyector.servicio();
...
}
...

La clase de la aplicación VaadinIII, en su método init, realiza la creación del modelo, la vista y el presentador, así como, la creación del Layout y del bus para la gestión de eventos. El método init es el siguiente:

@Override
protected void init(VaadinRequest request) {
 final VerticalLayout content = new VerticalLayout();
 content.setMargin(true);
 setContent(content);
 EventBus bus = ((MiVaadinServlet) VaadinServlet.getCurrent()).getBus();
 EjemploModel model = new EjemploModel("Servicio Dummy", "Salida Spring:");
 EjemploVista vista = new EjemploVista();
 EjemploPresenter presenter = new EjemploPresenter(vista, model, bus);
 bus.register(presenter);
 content.addComponent(vista);
}

Conclusiones

El ejemplo descrito es muy sencillo y, simplemente, he querido reflejar la forma en la cual se integra Spring con Vaadin. La debilidad de Vaadin es que la integración con Spring es a través del contexto y no se puede aplicar la inyección de dependencias de los componentes Vaadin con los mecanismos que proporciona Spring.

Si se desea el código se puede acceder aquí.

Vaadin II: MVP con Guava

En la entrada anterior, Vaadin I: introducción, realicé una breve descripción de Vaadin y un ejemplo básico tipo “Hola Mundo”. En esta segunda entrada, Vaadin II: MVP con Guava, describiré el modelo vista presentador MVP utilizando el componente EventBus de la librería Guava para la gestión de eventos.

Definición conceptual de MVP (Modelo-Vista-Presentador)

El patrón Modelo-Vista-Presentador es una evolución del patrón Modelo-Vista-Controlador. En el MVP, el modelo no interactua con la vista y permite la creación de los tester del modelo como del presentador. Gráficamente, el modelo se puede definir de la siguiente forma:

mvp

Definición del EventBus de Guava

Guava es una librería de Google en la cual se definen unos componentes que facilitan el desarrollo de aplicaciones. En su momento, realicé una serie de entradas describiendo algunos componentes pertenecientes a esta librería. Para el lector interesado los enlaces son los siguientes:

Para esta entrada, utilizaré el componente EventBus. Este componente, implementa la funcionalidad para el patrón productor-consumidor de una forma muy sencilla; funcionalidad, que aplicaremos para la gestión de los eventos que se producen en los interfaces de usuario, es decir, eventos lanzados por un botón o por cualquier elemento de Vaadin que lance eventos; estos elementos de Vaadin, deberán ser registrados en EventBus.

Las operaciones que soporta EventBus son las siguientes:

  • Registro de un consumidor: eventBus.register( Object )

  • Registro de un productor: eventBus.post( (Object)evento )

  • El código de tratamiento de un evento se define con la anotación  @Subscribe .

Definición conceptual del ejemplo

La aplicación ejemplo está compuesta de una sola pantalla compuesta con los siguientes elementos: dos botones, para lanzar eventos; un campo TextField, como campo de entrada; y, un Label, como elemento de salida.

Configuración del ejemplo

La configuración de la aplicación es la misma configuración que la entrada anterior. La diferencia reside en el servlet de Vaadin; en este caso, hemos heredado el servlet de Vaadin para la creación y gestión del EventBus.

La definición del Servlet es la siguiente:

public class MiVaadinServlet extends VaadinServlet {
 private static final long serialVersionUID = -8603697988171270479L;
 private EventBus eventBus;
 public MiVaadinServlet() {
 }
 @Override
 public void init() throws ServletException {
 super.init();
 this.eventBus = new EventBus();
 }
 public EventBus getBus() {
 return this.eventBus;
 }
}

Lo único que se ha realizado es la definición del EventBus en el servlet y la definición de un método para obtener el bus. Para obtener el bus en un componente Vaadin, se realiza de la siguiente forma:

EventBus bus = ((MiVaadinServlet) VaadinServlet.getCurrent()).getBus();

En el ejemplo, se realiza en la clase VaadinII.

La configuración del Servlet en el fichero web.xml se realiza de la siguiente forma:

<servlet>
 <servlet-name>Vaadin</servlet-name>
 <servlet-class>es.directoandroid.servlet.MiVaadinServlet</servlet-class>
 <init-param>
 <description>Vaadin UI to display</description>
 <param-name>UI</param-name>
 <param-value>es.directoandroid.ui.VaadinII</param-value> 
 </init-param>
</servlet>
<servlet-mapping>
 <servlet-name>Vaadin</servlet-name>
 <url-pattern>/*</url-pattern>
</servlet-mapping>

Descripción de la aplicación

La aplicación se define en la clase VaadinII que hereda de la clase UI. En este ejemplo, es una clase muy sencilla que usa un modelo, un presentador y una vista, además, del bus de eventos representados por EventBus. El método principal es el método init cuyo código es el siguiente:

@Override
 protected void init(VaadinRequest request) {
 final VerticalLayout content = new VerticalLayout();
 content.setMargin(true);
 setContent(content);
 EventBus bus = ((MiVaadinServlet) VaadinServlet.getCurrent()).getBus();
 EjemploModel model = new EjemploModel("Dummy", "Hola Dummy");
 EjemploVista vista = new EjemploVista();
 EjemploPresenter presenter = new EjemploPresenter(vista, model, bus);
 bus.register(presenter);
 content.addComponent(vista);
 }

La funcionalidad del método consiste en lo siguiente: se crea un Layout vertical que es asignado al contenedor del aplicativo UI; se instancia el bus desde el servlet (en este caso, por la sencillez del aplicativo, se puede instanciar en la misma clase ); se instancia el modelo; se instancia la vista; y, se instancia el presentador asignándole el modelo, la vista y el bus; para finalizar, se registra en el bus el presentador el cual tratará los eventos que se lanzan en la vista.

Descripción del modelo

El modelo corresponde a la estructura de datos que se muestra en la vista y que es manipulado por la clase presentadora. En el ejemplo, corresponde con la clase EjemploModel, la cual está compuesta por dos atributos de tipo String: una para la entrada de datos; y, el segundo, para la salida.

Descripción de la vista

La vista está definida en la clase EjemploVista la cual está compuesta de un VerticalLayout con los siguientes componentes: un botón para escribir en un Label el contenido del campo de entrada; un botón para limpiar los componentes; un campo TextField para la entrada de datos por parte del usuario; y, por último, un campo Label para escribir aquello que se inserta en el campo de entrada. Además, la vista implementa la funcionalidad definida en la clase Display de la clase presentadora.

Descripción del presentador

El presentador está definido por la clase EjemploPresenter el cual define el interfaz Display con las operaciones de interacción de la vista representada en la clase EjemploVista. Además, el presentador, define los métodos de tratamiento de los eventos lanzados en la interfaz; estos métodos, son todos aquellos en cuya firma tienen la anotación @Subscribe, como por ejemplo,

@Subscribe
public void limpiar(LimpiarEvent statusEvent) { 
  ((TextField) this.display.getTfNombre()).setValue(""); 
  ((Label) this.display.getLbMensaje()).setValue("");
}

Si se desea el código se puede acceder aquí.

En la siguiente entrada, Vaadin III: integración con Spring, realizaré la descripción de los pasos a seguir para integrar Spring con Vaadin.

Vaadin I: Introducción

Inicio una serie de entradas sobre Vaadin en las cuales realizaré una descripción de esta tecnología desde un punto de vista práctico. En esta primera entrada, cuyo título es Vaadin I: Introducción, realizaré una breve presentación de la tecnología así como la creación de una aplicación básica de tipo “Hola Mundo”.

Vaadin es aquel framework de nivel de presentación que permite realizar la definición de interfaces de usuario desde el servidor y utilizando un motor JavaScript del lado del cliente. La ejecución de una aplicación Vaadin se ejecuta como un Servlets en una servidor Web Java.

Vaadin está basado en aplicaciones con tecnologías AJAX, GWT (Google Web Toolkit) y JSON; pero estas tecnologías, no son necesarias conocerlas en el desarrollo porque todo el código es Java. Vaadin contiene un conjunto de componentes y controladores. Los componentes que tiene, entre otros, son: Label, TextField, TextArea, Tree, Table,etc,…

La referencia del site oficial es la siguiente: http:/www.vaadin.com

Entorno de desarrollo

El entorno de desarrollo que utilizo es Eclipse, en concreto, STS SpringSource Tools Suite; para este IDE, existe un plugin cuyo nombre es Vaadin plugin for Eclipse. Para su instalación, se realiza desde Eclipse Marketplace en la opción Help/Eclipse Marketplace; tras realizar su búsqueda en el market, se instalada conforme al proceso de instalación de un plugin.

Para la gestión del ciclo de vida he utilizado Maven. He creado un proyecto a partir de los arquetipos de proyectos que ofrece Maven para Vaadin; y, en la configuración del arquetipo, se utiliza el servidor Jetty. El proyecto maven utiliza un plugin de Vaadin cuya definición es la siguiente:

<plugin>
 <groupId>com.vaadin</groupId>
 <artifactId>vaadin-maven-plugin</artifactId>
 <version>${vaadin.plugin.version}</version>
 <configuration>
   <extraJvmArgs>-Xmx512M -Xss1024k</extraJvmArgs>
   <webappDirectory>${basedir}/src/main/webapp/VAADIN/widgetsets
   </webappDirectory>
   <hostedWebapp>${basedir}/src/main/webapp/VAADIN/widgetsets
   </hostedWebapp>
   <noServer>true</noServer>
   <draftCompile>false</draftCompile>
   <compileReport>true</compileReport>
   <style>OBF</style>
   <strict>true</strict>
   <runTarget>http://localhost:8080/</runTarget>
 </configuration>
 <executions>
   <execution>
    <configuration>
    </configuration>
    <goals>
      <goal>resources</goal>
      <goal>update-widgetset</goal>
      <goal>compile</goal>
    </goals>
   </execution>
 </executions>
</plugin>

Ejemplo «Hola Mundo»

La aplicación está definida en una clase java que hereda de la clase com.vaadin.ui.UI. Esta clase representa la aplicación y es a la que se referencia desde la configuración del Servlet.

La definición de una clase básica UI es la siguiente:

@Title("Demo")
@SuppressWarnings("serial")
public class Vaadin1 extends UI
{
 @Override
 protected void init(VaadinRequest request) {
 final VerticalLayout layout = new VerticalLayout();
 layout.addComponent( new Label(“Hola Mundo”) );
 setContent(layout);
 }
}

El código anterior define una pantalla con el texto “Hola Mundo” dentro de un layout vertical y, el título de la pantalla, se define mediante la anotación @Title . Para la ejecución del código anterior, es necesario la configuración del servlet. Esta configuración se puede realizar de dos formas: utilizando anotaciones; o bien, utilizando el fichero web.xml. La configuración del servlet utilizando anotaciones, se realiza definiendo en la clase Vaadin1 el servlet de la siguiente forma:

@WebServlet(value = "/*", asyncSupported = true)
 @VaadinServletConfiguration(productionMode = false, ui = Vaadin1.class)
 public static class Servlet extends VaadinServlet {}

La configuración en el fichero web.xml, se realiza de la siguiente forma:

<servlet>
 <servlet-name>Vaadin</servlet-name>
 <servlet-class> com.vaadin.server.VaadinServlet</servlet-class>
 <init-param>
   <description>Vaadin UI to display</description>
   <param-name>UI</param-name>
   <param-value>es.directoandroid.vaadin.Vaadin1</param-value> 
 </init-param>
</servlet>
<servlet-mapping>
 <servlet-name>Vaadin</servlet-name>
 <url-pattern>/*</url-pattern>
</servlet-mapping>

Para la ejecución del proyecto, se realiza ejecutando los comandos característicos de maven en la carpeta del proyecto: mvn clean install, para la compilación y creación del war; y, jetty:run, para la iniciar el servidor. La url a insertar en el navegador para realizar las pruebas es http://localhost:8080.

Si se desea el código de este proyecto se puede acceder aquí.

En la siguiente entrada, Vaadin II: MVP con Guava, realizaré la descripción del modelado del patrón MVP con Vaadin.