Está en la página 1de 72

2014

Toolkit GWT y
AppEngine
Desarrollo de aplicaciones Web
Estudio teórico de la herramienta de desarrollo web creado por Google.

Rafael Manuel Reina Ramírez


rmreina79@gmail.com
28/03/2014
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 2
Contenido
FIGURAS ........................................................................................................................................................ 4
1. INTRODUCCIÓN......................................................................................................................................... 5
2. CREAR PROYECTO GWT. ......................................................................................................................... 14
3. DESARROLLO DE UN MÓDULO GWT ...................................................................................................... 23
4. DATASTORE ............................................................................................................................................. 32
5. EJEMPLO COMPLETO USANDO GWT ...................................................................................................... 44
La clase de entrada es Contacts.java .................................................................................................. 47
Controlador: Clase AppControler........................................................................................................ 49
Comunicación del Cliente con el Servidor. ......................................................................................... 58
6. Casos reales de aplicación de GWT......................................................................................................... 64
7. El Futuro de GWT .................................................................................................................................... 65
8. BIBLIOGRAFÍA.......................................................................................................................................... 70

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 3
FIGURAS
Ilustración 1. Compilación GWT. Imagen tomada del libro GWT in Action. Adam Tacy et al. Anaya, 2013. 5
Ilustración 2. Modelo de desarrollo típico. ................................................................................................... 6
Ilustración 3. Secuencia de ejecución. Imagen tomada del libro GWT in Action. Adam Tacy et al. Anaya,
2013. ............................................................................................................................................................. 8
Ilustración 4. Ejecución en modo desarrollo. Imagen tomada del libro GWT in Action. Adam Tacy et al.
Anaya, 2013. ................................................................................................................................................. 9
Ilustración 5. Available Software. ............................................................................................................... 12
Ilustración 6. Instalación del plugin GWT para el navegador. .................................................................... 16
Ilustración 7. Ejecución aplicación. ............................................................................................................. 18
Ilustración 8. Vista diseño del GWT Designer. ............................................................................................ 24
Ilustración 9. Creación de la aplicación en AppEngine ............................................................................... 28
Ilustración 10. Panel de control. ................................................................................................................. 29
Ilustración 11. Herramienta de configuración de AppEngine. .................................................................... 29
Ilustración 12. Excepciones de JDO............................................................................................................. 42
Ilustración 13. Modelo-Vista-Presentador.................................................................................................. 44
Ilustración 14. Arquitectura de la aplicación. ............................................................................................. 46
Ilustración 15. Respuesta al pulsar "Add" ................................................................................................... 47
Ilustración 16. Entrada a la applicación. ..................................................................................................... 47

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 4
1. INTRODUCCIÓN

El desarrollo de aplicaciones web requiere conocer un conjunto amplio de tecnologías HTML,


JavaScript, AJAX, CSS, PHP, JSP, Servlets, ASP.NET, Tomcat, Apache, J2EE, Python, Oracle,
MySQL… Además es necesario configurar una máquina física a la que realizar las peticiones del
servicio web.

Google proporciona mecanismos para independizar la implementación de esa cantidad de


tecnologías. Para ello proporciona dos tecnologías:

 AppEngine. Plataforma para alojar nuestras aplicaciones en la nube evitando tener que
configurar una máquina física.

 GWT. Toolkit de desarrollo Java. Usar GWT se basa en escribir código Java y compilarlo a
Javascript.

Ilustración 1. Compilación GWT. Imagen tomada del libro GWT in Action. Adam Tacy et al. Anaya, 2013.

GWT permite obtener de una misma implementación JAVA el código Javascript adaptado a cada
navegador. En el modelo tradicional el cliente hacía una petición HTTP al servidor y éste en función del
navegador ejecutaba un plugin u otro.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 5
Ilustración 2. Modelo de desarrollo típico.

Se usan estas alternativas de desarrollo web por ser las más maduradas actualmente, aunque
existen otras.

Un caso de uso de GWT es el juego de Angry Birds para entornos de escritorio. Otro ejemplo es
el uso por parte de Eureka Streams para administrar la gran cantidad de código basado en Java
que se usa en el back-end del aplicativo.

¿Qué necesitamos para desarrollar aplicaciones con GWT?

 GWT SDK

 Plugin para Eclipse que incluye el SDK anterior.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 6
AppEngine.

https://appengine.google.com/

Google App Engine es un servicio de alojamiento web que presta Google de forma gratuita
hasta determinadas cuotas, este servicio permite ejecutar aplicaciones sobre la infraestructura
de Google. Hay dos formas de alojar la aplicación web en Google:

1. A través de un dominio propio de Google Apps.


2. Si no se cuenta con un dominio propio, Google proporciona uno con la siguiente
estructura,

midominio.appspot.com.

Las cuentas gratuitas tienen un límite de 500 megabyte de almacenamiento permanente y la


suficiente cantidad de ancho de banda y CPU para cinco millones de visitas mensuales, y si la
aplicación supera estas cuotas, se pueden comprar cuotas adicionales.

Actualmente las aplicaciones Google App Engine se implementan mediante los lenguajes de
programación Python, Java, Go y PHP.

Se asocia a nuestra cuenta de Google. Por lo que es necesario autentificarse con una cuenta
Google.

1. Entrar en http://appengine.google.com
2. Autentificarse con la cuenta de Google.
3. Crear una aplicación en AppEngine. El ID será utilizado para desplegar la aplicación.
4. Desarrollar la aplicación Web.
Para desarrollar la aplicación Web se puede usar el IDE Eclipse añadiéndole el software de
GWT, adecuado a la versión de Eclipse, que se obtiene en la dirección
https://developers.google.com/eclipse/docs/download
5. Desplegar la aplicación Web en el AppEngine.
6. Ejecutar la aplicación desde el navegador web.
6.1. Usuario introduce la URL del navegador web.
6.2. El navegador realiza una petición al servidor.
6.3. El servidor identifica el tipo de navegador para generar el código Javascript adecuado a
través de una respuesta desde el cliente en javascript.
6.4. Se ejecuta la aplicación.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 7
Ilustración 3. Secuencia de ejecución. Imagen tomada del libro GWT in Action. Adam Tacy et al. Anaya, 2013.

Existen dos modos de ejecución:

 Local: entorno de producción y prueba.


o Botón derecho del ratón sobre el proyecto y Debug As-> Web Application.
o Cuando aparezca en la pestaña Development Mode la URL de nuestra aplicación,
hacemos doble click en dicha URL para que se abra el navegador con nuestra
aplicación (puede pedir instalar un plugin para el navegador).
 AppEngine: entorno final de ejecución.
o Configurar proyecto con nuestra aplicación en AppEngine. Botón derecho del
ratón sobre el proyecto y seleccionar Google -> App Engine Settings. Indicar el
Application ID elegido anteriormente.
o Para desplegar, botón derecho encima del proyecto y Google-> Deploy to
AppEngine.

A continuación se muestra una imagen con el ciclo de ejecución en modo desarrollo (en local)
entre navegador, plugin, código del servidor y el código de la aplicación.

1. El navegador solicita un servicio web al AppEngine local.


2. Se ejecutan los plugins correspondientes.
3. Se presta el servicio solicitado si está disponible.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 8
Ilustración 4. Ejecución en modo desarrollo. Imagen tomada del libro GWT in Action. Adam Tacy et al. Anaya, 2013.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 9
Framework GWT.

http://www.gwtproject.org/
GWT o Google Web Toolkit es un framework creado por Google que permite ocultar la complejidad de
varios aspectos de la tecnología AJAX.

Es compatible con varios navegadores, lo cual es notorio ya que cada navegador suele necesitar código
específico para lograr un front-end correcto en una aplicación web.

El concepto de Google Web Toolkit es bastante sencillo, básicamente lo que se debe hacer es crear el
código en Java usando cualquier IDE de Java y el compilador lo traducirá a HTML y JavaScript.

Historial:

• GWT 1.0 - 17 de mayo de 2006 • GWT 2.0.4 - 2 de julio de 2010


• GWT 1.1 - 11 de agosto de 2006 • GWT 2.1.0 - 19 de octubre de 2010
• GWT 1.2 - 16 de noviembre de 2006 • GWT 2.1.1 - 16 de diciembre de
• GWT 1.3 - 5 de febrero de 2007 2010
• GWT 1.4 - 28 de agosto de 2007 • GWT 2.2.0 - 11 de febrero de 2011
• GWT 1.5 - 27 de agosto de 2008 • GWT 2.3.0 - 3 de mayo de 2011
• GWT 1.6 - 7 de abril de 2009 • GWT 2.4.0 - 8 de septiembre de
• GWT 1.7 - 13 de julio de 2009 2011
• GWT 2.0 - 8 de diciembre de 2009 • GWT 2.5.0 - 27 de junio de 2012
• GWT 2.0.1 - 8 de diciembre de 2009 • GWT 2.5.1 - 15 de enero de 2013
• GWT 2.0.2 - 2 de febrero de 2010 actual
• GWT 2.0.3 - 12 de febrero de 2010

GWT no es sólo una interfaz de programación; proporciona un conjunto de herramientas que permiten
desarrollar funcionalidades Javascript de alto rendimiento en el navegador del cliente.

Una aplicación GWT puede ser ejecutada en dos modos:

• Modo desarrollo (Dev mode): La aplicación se ejecuta como código bytecode de Java dentro
de la Máquina Virtual de Java (JVM). Este modo es el más usado para desarrollo, soportando
el cambio de código en caliente y el depurado.
• Modo web (Web mode): La aplicación se ejecuta como código Javascript y HTML puro,
compilado a partir del código Java. Este modo se suele usar para el despliegue de la
aplicación.

Existen dos formas de trabajar con GWT:

 Usando la línea de comandos applicationCreator genera automáticamente todos los archivos


necesarios para iniciar un proyecto GWT, incluso permite crear un proyecto para Eclipse.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 10
 Mediante plugins de código abierto que ayudan a desarrollar en diferentes entornos de
desarrollo, como GWT4NB para NetBeans, Cypal Studio for GWT para Eclipse o gwtDeveloper
para JDeveloper.

Arquitectura de GWT:

• GWT Java-to-JavaScript Compiler: la función de este componente es traducir el código


desarrollado en Java al lenguaje JavaScript. Lo empleamos cuando usamos al GWT en modo
web.
• Hosted Web Browser: este componente ejecuta la aplicación Java sin traducirla a JavaScript,
en modo host usando la máquina virtual de Java.
• JRE Emulation Library: contiene las bibliotecas más importantes de las clases de Java:
java.lang en donde se encuentran las clases fundamentales para poder programar en Java y
un subconjunto de las clases del paquete java.util. Java.lang incluye, entre otras, la clase
java.lang.object que es la clase fundamental de la que heredan o extienden todas las clases
en Java. El resto de los paquetes no están soportados por GWT.
• GWT Web UI Class Library: contiene un conjunto de elementos de interfaz de usuario que
permite la creación de objetos tales como textos, cajas de texto, imágenes y botones.

Módulos GWT:

Una aplicación GWT se llama módulo. El módulo es la pieza fundamental.

Un módulo tiene un fichero de configuración nombredemodulo.gwt.xml que recoge la siguiente


información:
 estilo visual,
 dependencias con otros módulos,
 clase de entrada a la aplicación

Los módulos tienen tres paquetes principales.


 Client: En este paquete desarrollamos todo el código con el que GWT genera Javascript y HTML
que se procesa en el navegador.
 Server: En este paquete desarrollamos el código del lado de servidor (backend).
 Shared: Para implementar clases cuyos objetos se usarán tanto en cliente como en servidor (hay
algunas restricciones para esto).

Asociado a nuestro módulo tenemos un fichero HTML Nombredemodulo.html


 También llamado fichero host, es el html en el que se ejecuta todo el código que GWT genera
desde nuestro código JAVA en el paquete cliente de GWT.
 Todo el código HTML que se incluye aquí aparecerá en toda nuestra aplicación.
 Aquí podremos asociar nuestras hojas de estilos (css) o añadir código HTML estático (ej:
cabecera o pie de página).

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 11
GOOGLE PLUGIN PARA ECLIPSE

INSTALACIÓN

Los plugins de GWT se obtiene en https://developers.google.com/eclipse/docs/download. Se instalan en


Menú Help -> Install New Software.

Nuestro IDE es el Eclipse 4.2 por lo que el software a instalar es:


https://dl.google.com/eclipse/plugin/4.2

Ilustración 5. Available Software.

Esta instalación proporciona el SDK, las herramientas desarrollo, el plugin de Google y el GWT Designer
para ayudar con el diseño gráfico de la interfaz de usuario.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 12
API de GWT

http://www.gwtproject.org/javadoc/latest/overview-summary.html

Paquete Descripción
com.google.gwt.user.client.rpc Permite la comunicación del cliente con el
servidor mediante llamadas a procedimiento.
com.google.gwt.user.client.ui Widgets, Paneles y otros elementos de la interfaz
de usuario.
com.google.gwt. dom.client Clases para la programación DOM a bajo nivel.

com.google.event.dom.client Tipo para el tratamiento de eventos DOM de la


interfaz del cliente.

La base de los elementos de las aplicaciones web está en el DOM. Navegar por el DOM nos permite
acceder a cualquier elemento de una página HTML.

DOM (Document Object Model) es el modelo usado tradicionalmente por Javascript para programar la
parte lógica de la interfaz de usuario.

Cada widget y panel tiene su descripción DOM correspondiente. Se obtiene mediante el método
getElement().

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 13
2. CREAR PROYECTO GWT.

http://www.gwtproject.org/doc/latest/tutorial/gettingstarted.html

Los diferentes pasos que son necesarios dar para la creación de un proyecto de Google en Eclipse son
los siguientes:

• Paso 1: Crear un proyecto GWT.


Es un Google web Aplication Project.
En él se especifican el SDK para GWT y el SDK para AppEngine.
/src : contiene las fuentes de las clases Java
/gwt-unitCache: almacena ficheros que ayudan a agilizar la compilación. Se van generando en
las diferentes compilaciones del proyecto.
/war: despliegue de la aplicación web.

• Paso 2: Diseñar la aplicación.


2.1. Determinar la funcionalidad de la aplicación.
2.2. Diseñar la interfaz de usuario.

• Paso 3: Construir la interfaz de usuario.


3.1. Seleccionar los widgets necesarios (botones, etiquetas,...).
3.2. Seleccionar los paneles (horizontal, vertical, raiz).
http://www.gwtproject.org/doc/latest/RefWidgetGallery.html
3.3. Crear la página HTML en la que van embebidos los elementos anteriores. Se puede usar CSS
para mejorar el estilo.
3.4. Implementar una clase Java en la que se creen los widgets y paneles anteriores.
3.5. Probar la distribución en modo desarrollo. Menú Run as Web Application, el servidor se
ejecuta en el puerto 8888.

• Paso 4: Gestionar los eventos.

• Paso 5: Despliegue en AppEngine.

Ejemplo de aplicación simple:


En /src/prueba.gwt/PruebaAplicacionGoogle.gwt.xml se define el módulo que se va a cargar
en la página web (Clase de entrada que implementa OnModuleLoad de la interfaz EntryPoint.

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


<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.6.0//EN"
"http://google-web-toolkit.googlecode.com/svn/tags/2.6.0/distro-
source/core/src/gwt-module.dtd">

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 14
<module rename-to='pruebaaplicaciongoogle'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>

<!-- Inherit the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by uncommenting -->
<!-- any one of the following lines. -->
<inherits name='com.google.gwt.user.theme.clean.Clean'/>

<!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->


<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->

<!-- Other module inherits -->

<!-- CLASE DE ENTRADA A LA APLICACIÓN, implementa el método OnModuleLoad de


la interfaz EntityPoint -->
<entry-point class='prueba.gwt.client.PruebaAplicacionGoogle'/>

<!-- Specify the paths for translatable code -->


<source path='client'/>
<source path='shared'/>

<!-- allow Super Dev Mode -->


<add-linker name="xsiframe"/>
</module>

En /war se definen los css y html para cargar ese módulo.

Código HTML del PruebaAplicacionGoogle.html

<table align="center">
<tr>
<td colspan="2" style="font-weight:bold;">Please enter your
name:</td>
</tr>
<tr>
<td id="nameFieldContainer"></td>
<td id="sendButtonContainer"></td>
</tr>
<tr>
<td colspan="2" style="color:red;" id="errorLabelContainer"></td>
</tr>
</table>

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 15
<td id="nameFieldContainer"></td>
<td id="sendButtonContainer"></td>

Estas líneas muestran en pantalla la entrada de texto y el botón de enviar. El id permite que desde las
clases de Java se pueda hacer referencia a ellos usando la clase RootPanel.

RootPanel.get("sendButtonContainer").add(sendButton);

Con este código la clase que define la interfaz de usuario, añade un botón en el elemento HTML con
id="sendButtonContainer".

/src/prueba.gwt.client/PruebaAplicacionGoogle.java donde están definidos y que está definida como


clase de entrada a la aplicación ya que implementa el método OnModuleLoad de la interfaz EntryPoint.

Básicamente la clase crea los objetos de la interfaz de usuario com.google.gwt.user.client.ui que


necesita, le asigna los eventos de com.google.gwt.event.dom.client y los añade al RootPanel.

web.xml -> despliega los servlets y la página principal.

PruebaAplicacionGoogle.gwt.xml -> define la clase de entrada a la aplicación, cuyo OnModuleLoad se


aplicará a la página HTML especificada en web.xml.

La creación de un modulo en GWT se hace de la siguiente forma:

1. Sobre el proyecto pulsar botón derecho de ratón New -> Other.


2. En wizards poner Module y seleccionar el módulo de GWT.

Se genera un fichero HolaMundo.gwt.xml con la descripción del módulo.

Ilustración 6. Instalación del plugin GWT para el navegador.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 16
Clase de entrada prueba.gwt.client. PruebaAplicacionGoogle

package prueba.gwt.client;

import prueba.gwt.shared.FieldVerifier;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;

import com.google.gwt.user.client.rpc.AsyncCallback;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class PruebaAplicacionGoogle implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);

/**
* This is the entry point method.
*/
public void onModuleLoad() {
...
}
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 17
Método onModuleLoad() que crea un cuadro de texto y un botón enviar.

El evento al pulsar el botón genera la siguiente respuesta:

Ilustración 7. Ejecución aplicación.

Crear UI

public void onModuleLoad() {


final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final Label errorLabel = new Label();

// We can add style names to widgets


sendButton.addStyleName("sendButton");

// Add the nameField and sendButton to the RootPanel


// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);

// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();

// Create the popup dialog box


final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 18
final Button closeButton = new Button("Close");

// We can set the id of a widget by accessing its Element


closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
final HTML serverResponseLabel = new HTML();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);

...
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 19
Paso 4: Gestionar los eventos.
En Java se gestión los eventos siguiendo el modelo de delegación de eventos. Este modelo consiste en
que el evento generado por una fuente es manejado por una clase diseñada y asignada a la fuente del
evento.

public void onModuleLoad() {


...

// Add a handler to close the DialogBox


closeButton.addClickHandler(
new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
sendButton.setEnabled(true);
sendButton.setFocus(true);
}
}); //fin addClickHandler

...
}

En el punto de entrada se crean y asignan los manejadores de eventos.

public void onModuleLoad() {


...

// Add a handler to send the name to the server


MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}

Clase MyHandler

Esta clase es el manejador que gestiona los eventos. Cada tipo de eventos está definido en una interfaz
que proporciona el comportamiento adecuado a dicho evento.

Por ejemplo el evento pulsar el botón está representado por ClinkEvent y su gestión se define en
ClickHandler que proporciona el método onClick que hay que implementar con la lógica a ejecutar
correspondiente a dicho evento.

// Create a handler for the sendButton and nameField

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 20
class MyHandler implements ClickHandler, KeyUpHandler {
/** Fired when the user clicks on the sendButton. */
public void onClick(ClickEvent event) {
sendNameToServer();
}

/**Fired when the user types in the nameField. */


public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendNameToServer();
}
}

/**Send the name from the nameField to the server and wait for
a response. */
private void sendNameToServer() {
// First, we validate the input.
errorLabel.setText("");
String textToServer = nameField.getText();
if (!FieldVerifier.isValidName(textToServer)) {
errorLabel.setText("Please enter at least four characters");
return;
}

// Then, we send the input to the server.


sendButton.setEnabled(false);
textToServerLabel.setText(textToServer);
serverResponseLabel.setText("");
greetingService.greetServer(
textToServer, new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox.setText("Remote Procedure Call -
Failure");
serverResponseLabel.addStyleName("
serverResponseLabelError");

serverResponseLabel.setHTML(SERVER_ERROR);
dialogBox.center();
closeButton.setFocus(true);
} //fin onFailure

public void onSuccess(String result) {


dialogBox.setText("Remote Procedure Call");

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 21
serverResponseLabel.removeStyleName("
serverResponseLabelError");
serverResponseLabel.setHTML(result);
dialogBox.center();
closeButton.setFocus(true);
}
}); //fin greetService
}
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 22
3. DESARROLLO DE UN MÓDULO GWT

Desarrollo de la interfaz de usuario.

Está basado en widgets. Entre los widgets tenemos contenedores (paneles), y controles (botones,
etiquetas, etc…).

Los widgets los podemos encontrar en:

 Galería de GWT: (https://developers.google.com/web-toolkit/doc/1.6/RefWidgetGallery):


o Widgets: Button PushButton RadioButton CheckBox DatePicker ToggleButton
TextBox PasswordTextBox TextArea Hyperlink ListBox CellList MenuBar Tree
CellTree SuggestBox RichTextArea FlexTable Grid CellTable CellBrowser TabBar
DialogBox
o Paneles: PopupPanel StackPanel StackLayoutPanel HorizontalPanel VerticalPanel
FlowPanel VerticalSplitPanel HorizontalSplitPanel SplitLayoutPanel DockPanel
DockLayoutPanel TabPanel TabLayoutPanel DisclosurePanel
 Ejemplos (http://gwt.googleusercontent.com/samples/Showcase/Showcase.html )

El plugin para Eclipse de GWT cuenta con el GWT Designer basado en Windows Builder que permite la
construcción de la interfaz de usuario en un entorno gráfico más amigable y muy fácil de usar. Permite
alternar entre ambas vistas código y diseño. Para ello basta con abrir el widget con el GWT Designer.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 23
Ilustración 8. Vista diseño del GWT Designer.

Todos los widgets heredan de RootPanel que se obtiene de la siguiente forma:


Panel p= RootPanel.get();

El punto de entrada a la aplicación es la clase que implemente el método onModuleLoad()

Una misma ventana puede tener varias vistas (partes en las que se divide una interfaz de usuario.
Podemos trabajar con la misma ventana pero con distintas vistas.
Cada vista es una clase que extiende a Composite.

Gestión de eventos.
Los eventos pueden ser de dos tipos:

 por defecto, como pulsar un botón, seleccionar un checkbox,...


 definidos por el usuario.

El tratamiento de eventos se realiza indicando sobre el objeto que va a manejar el evento (por ejemplo
un botón), el evento a tratar (por ejemplo pulsar un botón).

Button bt = new Button(“Aceptar");


bt.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
//acción al pulsar el botón
}
});

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 24
Añadir APIs de Google al proyecto

En nuestro proyecto GWT podemos hacer uso de API's ya diseñadas como el Calendario de Google. Para
ello debemos, sobre el proyecto, hacer click con el botón derecho del ratón Google -> App Google APIs

Ilustración 10. Añadir APIs de Google al App

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 25
Ilustración 11. APIs de Google.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 26
API y tecnologías

 Google+
o Aumenta el tráfico y la interacción con tu contenido utilizando API y complementos
de Google+.
 Android
o Utiliza las API de Google en tus aplicaciones de Android.
 Cloud Platform
o Desarrolla y ejecuta tus sitios web y tus aplicaciones en la infraestructura de Google.
 Chrome
o Crea aplicaciones web de alto rendimiento utilizando las últimas tecnologías
ofrecidas por la Web libre.
 Games
o Desarrolla juegos interactivos para la Web y para teléfonos móviles mediante
tecnologías de vanguardia.
 Google Maps
o Crea fácilmente visualizaciones de datos interactivas en un mapa y en aplicaciones
basadas en ubicaciones.
 Google Apps
o Amplía la experiencia de Google Apps para tus usuarios.
 Google TV
o Crea aplicaciones para la gran pantalla.
 Google Wallet
o Aumenta las conversiones, procesa pagos e implica a tus clientes con ofertas y
programas de fidelización.
 YouTube
o Integra la funcionalidad y el contenido de los vídeos de YouTube en tu sitio web,
aplicación o dispositivo.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 27
DESPLIEGUE DE UNA APLICACIÓN EN APP ENGINE

Las aplicaciones de GWT se empaquetan en un war y se pueden desplegar en cualquier contenedor de


Servlets estándar.

Si no hemos utilizado Java para los servicios remotos podemos desplegar en cualquier servidor web http
como Apache.

Se puede utilizar ant o maven para automatizar el proceso de compilación, empaquetamiento y


despliegue.

GWT genera un archivo optimizado para cada navegador soportado por el compilador.

Cuando un navegador se conecta a GWT el archivo nocache.js detecta el navegador del cliente y le envía
el código JavaScript generado para ese navegador.

Para poder desplegar la aplicación es necesario definir un identificador de aplicación disponible en


AppEngine que será utilizado en el Eclipse cuando se lleve a cabo el proceso de despliegue.

Ilustración 9. Creación de la aplicación en AppEngine

Si pulsamos "dashboard" podremos acceder al panel de control de la aplicación:

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 28
 Tráfico
 Logs
 Gestión de versiones
 Gestión de datos
 Facturación

Ilustración 10. Panel de control.

En "appcfg" podremos configurar la aplicación en función del tipo de lenguaje de programación que
utilicemos.

Ilustración 11. Herramienta de configuración de AppEngine.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 29
Una vez creado el ID en el AppEngine, se siguen los siguientes pasos:
1. Compilar el proyecto GWT.
2. Desplegar en AppEngine

Debemos configurar las propiedades del proyecto App Engine para añadirle un ID al mismo.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 30
Ilustración 12. Propiedades del proyecto App Engine

La URL de la aplicación será http://application-id.appspot.com/ donde application-id


será holaMundoRMRR ( http:// holaMundoRMRR.appspot.com/ ).

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 31
4. DATASTORE

Es un almacén distribuídos de datos (entidades) diferentes unos de otros.

No es una base de datos relacional.

Información sobre el DataStore:

https://developers.google.com/appengine/docs/java/datastore/overview

Hay 3 maneras de operar en Java con el datastore de App Engine:

 JDO (Java Data Objects)


 JPA (Java Persistence API)
 El API de nivel inferior: es necesario explicar qué y cómo se almacena.

CÓMO UTILIZAR EL DATASTORE DE GOOGLE APP ENGINE CON JDO

JDO ( Java Data Objects, 'objetos de datos de java) es una especificación de almacenamiento de
objetos en Java, la cual no se limita a lo que es el almacenamiento de datos en bases de datos
relacionales únicamente, pudiendo utilizarse contra ficheros XML, documentos de OpenOffice, objetos
JSON, etc. Esto facilita la integración entre JDO y el datastore ya que el datastore no utiliza un modelo
relacional por debajo.

Lo que sí utiliza JDO por debajo, sin embargo, es el API de nivel inferior:

Ilustración 13. Estructura del Datastore.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 32
El API Java de almacén de datos

https://developers.google.com/datastore/docs/concepts/overview

JDO permite que los desarrolladores pueden centrarse más en qué quieren buscar, modificar, borrar,
etc. que en cómo. Es por ello que esta tecnología permite tener un grado de abstracción alto,
claramente mayor al que tendríamos si tuviéramos que desarrollar nuestra aplicación con el API de nivel
inferior, pero por contra perderemos el disponer de un control absoluto sobre lo que hacemos.

Del estándar JDO existen varias versiones, funcionando la 2.3 en Google App Engine y siendo la
implementación una variante de DataNucleus Access Plataform
(http://www.datanucleus.org/ ). El plugin para usar DataNucleus en GWT se
puede descargar en https://code.google.com/p/datanucleus-appengine/.

Sin embargo hay funciones de JDO que no podremos utilizar si queremos hacer funcionar nuestra
aplicación en Google App Engine. Estas limitaciones son las siguientes:

1- relaciones sin propiedad (se pueden implementar relaciones sin propiedad a través de valores
de Key explícitos; es posible que se admita la sintaxis de JDO para relaciones sin propiedad en
una futura versión),
2- relaciones de propiedad varios a varios,
3- consultas con "Join", (no se puede utilizar un campo de una entidad secundaria en un filtro si se
realiza una consulta en la entidad principal),
4- agrupación JDOQL y otras consultas agrupadas,
5- consultas polimórficas (no se puede realizar una consulta de una clase para obtener instancias
de una subclase; cada clase está representada por un tipo de entidad independiente del
almacén de datos),
6- IdentityType.DATASTORE para la anotación @PersistenceCapable (sólo se admite
IdentityType.APPLICATION),
7- en la actualidad existe un error que evita que los campos persistentes se guarden en el almacén
de datos.

Las entidades de JPO son objetos persistentes.

Un objeto persistente es una clase java bastante simple (POJO: una clase con atributos los cuales son
accedidos mediante getters y setters) que puede ser almacenado en el datastore. Para poder indicarle a
JDO cómo debe tratar a los objetos persistentes es necesario utilizar anotaciones. La implementación de
JDO, por debajo, convertirá los objetos persistentes anotados en entidades con los que el datastore
pueda operar.

Para convertir objetos persistentes de JDO en entidades del datastore necesitamos anotar dichos
objetos. Las anotaciones que podemos utilizar son las siguientes:

@PersistenceCapable

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 33
Indica que una clase puede ser recuperada y almacenada mediante el soporte de JDO (restricción 6).

import javax.jdo.annotations.PersistenceCapable;

1. import javax.jdo.annotations.IdentityType;
2.
3. @PersistenceCapable(identityType = IdentityType.APPLICATION)
4. public class Tutorial { ... }

@Persistent

Indica que queremos poder almacenar el campo de la entidad en el datastore.

1. import javax.jdo.annotations.Persistent;
2.
3. @Persistent
4. private String autor;

El tipo de campo que podremos almacenar puede ser:

 uno de los tipos principales compatibles con el almacén de datos,


 una colección (como, por ejemplo, java.util.List<...>) o un conjunto de valores de tipo principal
del almacén de datos,
 una instancia o colección de instancias de una clase @PersistenceCapable,
 una instancia o colección de instancias de una clase serializable (@Persistent(serialized =
"true")),
 una clase insertada y almacenada como propiedades de la entidad

@NotPersistent

Indica que queremos que el campo de la entidad no se almacene.

1. import javax.jdo.annotations.NotPersistent;
2.
3. @NotPersistent
4. private String fechaFormateadaParaPresentacion;

Por lo general prácticamente todos los tipos de datos son persistentes a no ser que se diga lo contrario,
ya que hay tipos de datos que por defecto no son persistentes. En la siguiente dirección se pueden ver
los tipos persistentes y los que no
: http://www.datanucleus.org/products/accessplatform_1_1/jdo/types.html.

Se recomienda poner anotaciones directamente en todas las variables que declaremos.

@PrimaryKey

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 34
Indica que el campo va a ser la clave primaria, e irá acompañada de la anotación @Persistent ya que la
clave también será almacenada.

1. import javax.jdo.annotations.IdGeneratorStrategy;
2. import javax.jdo.annotations.Persistent;
3. import javax.jdo.annotations.PrimaryKey;
4.
5. @PrimaryKey
6. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
7. private Long id;

En Google App Engine hay 4 maneras de definir claves primarias, y en función al tipo de datos de esta
clave primaria hay que configurar la anotación @Persistent de una manera u otra. Las 4 maneras de
definir claves primarias son las siguientes:

 Como objetos de tipo Long, cuyo id se genera de manera automática.


 Como objetos de tipo String, cuyo id deberemos generar nosotros.
 Como objetos de tipo Key numérico, cuyo id se genera de manera automática.
 Como objetos de tipo Key representados como una cadena, cuyo id se genera de manera
automática.

Las claves primarias de tipo Long y String se utilizan en entidades fuertes, mientras que las claves de
tipo Key son claves compuestas que contienen el id de la aplicación y el id de la entidad padre,
utilizándose por tanto en entidades débiles.

@EmbeddedOnly y @Embedded

Se utilizan para insertar unas clases dentro de otras (parecido a Hibernate).

En un coche podemos guardar un montón de información relacionada con el dueño, con el seguro, con
el estado del vehículo, con las revisiones que ha pasado, con las averías que ha sufrido, etc.

Podemos poner toda esta información campo a campo en el coche o podemos dividirla en subclases:
una será la claseSeguro, y en ella almacenaremos la información del seguro, otra será la clase Estado y
en ella almacenaremos la información acerca del estado del coche, otra será Revisión y en ella
almacenaremos la información acerca de las revisiones, etc. de tal modo que insertaremos (no
relacionaremos) esta información en la clase Coche.

Relaciones

Con el soporte de JDO se pueden crear relaciones entre clases persistentes de manera sencilla
referenciando a unas desde las otras.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 35
Relaciones 1:N

Para relacionar una entidad con varias, por ejemplo a una persona con varios coches, lo que debe hacer
es crear un campo de tipo 'persona' en la clase Coche y un campo que sea una lista de tipo 'coche' en la
clase Persona.

1. import javax.jdo.annotations.Persistent;
2.
3. @PersistenceCapable(identityType = IdentityType.APPLICATION)
4. public class Coche {
5.
6. @PrimaryKey
7. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
8. private Long id;
9.
10. @Persistent
11. private Persona persona;
12.
13. ...
14. }

1. import javax.jdo.annotations.Persistent;
2.
3. @PersistenceCapable(identityType = IdentityType.APPLICATION)
4. public class Persona {
5.
6. @PrimaryKey
7. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
8. private Long id;
9.
10. @Persistent
11. private List< Coche> coches;
12.
13. ...
14. }

Con esto lo que se consigue es indicar que una persona puede tener varios coches, mientras que un
coche sólo puede ser poseído por una persona. Ambas son entidades fuertes puesto que ambas tienen
un id de tipo Long, y a su vez ambas forman parte del mismo grupo de objetos persistentes.

También podemos indicar qué ordenación vamos a querer en los coches. Esto es, podemos indicar en
qué orden queremos almacenar y recuperar los coches de una persona en el datastore.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 36
1.
2. import javax.jdo.annotations.Persistent;
3.
4. @PersistenceCapable(identityType = IdentityType.APPLICATION)
5. public class Persona {
6.
7. @Persistent
8. @Order(extensions = @Extension(vendorName="datanucleus", key="list-
ordering", value="matricula asc"))
9. private List< Coche> coches;
10.
11. ...
12. }

En este caso estaríamos ordenando los coches de una persona por matrícula en orden ascendente.

Relaciones 1:1

En caso de relacionar una entidad con otra, por ejemplo a un empleado con un empleo, haciendo que
una entidad sea fuerte y la otra débil, habría que crear una relación entre los objetos persistentes como
la que sigue:

1. import javax.jdo.annotations.IdentityType;
2. import javax.jdo.annotations.IdGeneratorStrategy;
3. import javax.jdo.annotations.PersistenceCapable;
4. import javax.jdo.annotations.Persistent;
5.
6. @PersistenceCapable(identityType = IdentityType.APPLICATION)
7. public class Empleado {
8.
9. @PrimaryKey
10. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
11. private Long id;
12.
13. @Persistent
14. private Empleo empleo;
15.
16. ...
17. }

1. import javax.jdo.annotations.IdentityType;
2. import javax.jdo.annotations.IdGeneratorStrategy;
3. import javax.jdo.annotations.PersistenceCapable;

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 37
4. import javax.jdo.annotations.Persistent;
5.
6. @PersistenceCapable(identityType = IdentityType.APPLICATION)
7. public class Empleo {
8.
9. @PrimaryKey
10. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
11. private Key key;
12.
13. @Persistent(mappedBy = "empleo")
14. private Empleado empleado;
15.
16. ...
17. }

Con esto lo que conseguiremos es que la clave de la entidad débil, en este caso Empleo, utilice
automáticamente la clave de Empleado.

Cómo operar con los datos

Create makePersistent()
Read getObjectById()
Update 1. recuperar objeto.
2. modificarlo.
Actualización automática
Delete deletePersistent()
Ilustración 14. Operaciones CRUD.

Create (creación)

Para poder guardar un objeto persistente en el datastore es necesario ejecutar el


método makePersistent() del gestor de persistencia.

1. final PersistenceManager gestorPersistencia = PersistenceManagerFactory.getInstance().getPers


istenceManager();
2. final Tutorial tutorial = new Tutorial("adictosaltrabajo", "Google App Engine", "nivel medio");
3. try {
4. gestorPersistencia.makePersistent(e);
5. } finally {
6. gestorPersistencia.close();
7. }

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 38
Read (lectura)

Para poder recuperar un objeto persistente del datastore es necesario ejecutar el


método getObjectById() del gestor de persistencia.

1. final PersistenceManager gestorPersistencia = PersistenceManagerFactory.getInstance().getPers


istenceManager();
2. final Tutorial tutorial = gestorPersistencia.getObjectById(Tutorial.class, "Google App Engine");

Es posible utilizar JDOQL para realizar las consultas de objetos persistentes con JDO como se verá mas
adelante.

Update (actualización)

1. Recuperar el objeto persistente que queremos modificar


2. modificarlo.
3. No será necesario indicar explícitamente que queremos almacenar los cambios en base de datos
ya que el gestor de persistencia se encargará de ello.

1. final PersistenceManager gestorPersistencia = PersistenceManagerFactory.getInstance().getPers


istenceManager();
2. try {
3. final Tutorial tutorial = gestorPersistencia.getObjectById(Tutorial.class, "Google App Engine");

4. tutorial.setNivel ("nivel bajo");


5. } finally {
6. pm.close();
7. }

Delete (borrado)

1. recuperar el objeto persistente que queremos borrar


2. borrarlo: Para ello utilizaremos el método deletePersistent() del gestor de persistencia.

1. final PersistenceManager gestorPersistencia = PersistenceManagerFactory.getInstance().getPers


istenceManager();
2. final Tutorial tutorial = gestorPersistencia.getObjectById(Tutorial.class, "Google App Engine");
3. gestorPersistencia.deletePersistent (tutorial);

Hay que tener en cuenta que si se borra una entidad fuerte que tenía otras entidades débiles
relacionadas se realizará un borrado en cascada.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 39
Cómo realizar consultas

JDO posee un lenguaje de consultas llamado JDOQL que devuelve objetos persistentes en vez de tuplas
con datos.

Este lenguaje posee varias maneras de ser ejecutado. Los códigos mostrados a continuación, por
ejemplo, son equivalentes:

1. final Query query = persistenceManager.newQuery(Tutorial.class);


2. query.setFilter("nombreTutorial == nombreTutorialParam");
3. query.setOrdering("fecha DESC");
4. query.declareParameters("String nombreTutorialParam");
5. query.execute("Google App Engine");

es equivalente a

1. final Query query = persistenceManager.newQuery("select from Tutorial where nombreTutorial


== nombreTutorialParam order by fecha DESC parameters String nombreTutorialParam");
2. query.execute("Google App Engine");

Es importante destacar que el datastore mantiene varios índices en nuestros datos. A medida que la
aplicación realiza cambios en las entidades del datastore éste actualiza los índices para extraer los
resultados directamente del índice correspondiente cuando la aplicación ejecute una consulta. Esto es
bastante sensato, ya que el datastore está pensando para poder recuperar información muy
rápidamente.

Transacciones

Una transacción, según la wikipedia, es:

"[...] una interacción con una estructura de datos compleja, compuesta por varios procesos que se han
de aplicar uno después del otro. La transacción debe ser equivalente a una interacción atómica. Es decir,
que se realice de una sola vez y que la estructura a medio manipular no sea jamás alcanzable por el resto
del sistema hasta que haya finalizado todos sus procesos."

Las transacciones deben cumplir 4 propiedades para poder ser consideradas como tal que se las conoce
como ACID (Atomicity, Consistency, Isolation and Durability) y lo que aseguran es que o se aplica el
resultado de todas las operaciones englobadas dentro de una misma transacción o no se aplica el de
ninguna.

El datastore es transaccional, lo que hace que sea consecuente y evita que se den inconsistencias en los
datos.

La transaccionalidad en el datastore puede conseguirse de dos maneras:

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 40
 Declarando explícitamente los márgenes de la transacción, utilizando para ello el API de JDO.
 Creando grupos de entidades, lo que vendría a ser una declaración implícita.

La declaración explícita es bastante simple de utilizar:

1. final PersistenceManager gestorPersistencia = PersistenceManagerFactory.getInstance().get


PersistenceManager();
2. final Transaction transaccion = gestorPersistencia.currentTransaction();
3. try {
4. transaccion.begin();
5. // hacer lo que sea
6. transaccion.commit();
7. } finally {
8. if (transaccion.isActive()) {
9. transaccion.rollback();
10. }
11. }

Donde:

 transaccion.begin() inicia la transacción.


 transaccion.commit() hace que se apliquen los cambios efectuados desde que se inició la
transacción y que ésta termine.
 transaccion.rollback() hace que se deshagan los cambios efectuados desde que se inició la
transacción y que ésta termine.

Todas las operaciones de escritura en el datastore son atómicas, lo que permite que nuestros datos
siempre se encuentren en un estado consistente. Una operación de modificación o de creación puede
producirse completamente o no producirse en absoluto.

Acciones no permitidas en el ámbito de una transacción

Hay una serie de acciones que no se pueden realizar mientras estemos en una transacción activa. Dichas
acciones son las siguientes:

 Puesto que cada grupo de entidades maneja una transacción propia no se pueden guardar
objetos de más de un grupo de entidades en una misma transacción, con lo que no podrás
asegurar que en una misma operación puedas almacenar entidades de más de un grupo de
entidades. Es una limitación importante, aunque siempre se puede utilizar la lógica de la
aplicación para controlar estos casos.
 No es posible recuperar objetos persistentes mediante consultas cuando estamos en medio de
una transacción, aunque se puede recuperar por id sin tener ningún problema. Esto estaría
vinculado con las declaración explícita de transacciones. Si vas a necesitar lanzar una consulta
debes asegurarte de lanzarla fuera del ámbito de una transacción.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 41
 No es posible crear ni actualizar el mismo objeto persistente más de una vez en una misma
transacción. Esto es lógico ya que por un lado los objetos sólo pueden ser creados una vez, y por
otro cada vez que actualizamos lo que hacemos es crear nuevas entidades del datastore. Si
actualizamos más de una vez estaríamos, sin ser conscientes de ello, tratando de guardar
entidades en el datastore a las que no vamos a poder acceder nunca.

Sin embargo JDO tiene multitud de excepciones que podremos capturar en cada caso y obrar en
consecuencia para solucionar los posibles problemas que nos podamos encontrar.

Las excepciones se clasifican en:

 Errores de programa que se pueden corregir y por tanto, reintentar la ejecución.


 Errores de programa que no se pueden corregir porque el estado de los componentes se ha
modificado.
 Errores lógicos internos a la implementación de JDO y que son responsabilidad del desarrollador
de la interface.
 Errores asociados al datastore subyacente y que pueden ser corregidos.
 Errores asociados al datastore subyacente pero que no pueden ser corregidos debido a un error
en el propio datastore o en la comunicación con éste.

Ilustración 12. Excepciones de JDO

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 42
DatastoreService

Otra alternativa es usando el DatastoreService:

db= DatastoreServiceFactory.getDatastoreService();

Cada elemento del Datastore es una entidad (objeto de Entity). Las entidades son un conjunto de
propiedades con un nombre y un valor que pueden ser consultads (getProperties) y modificadas
(setProperties). Cada entidad pertenece a una clase (kind) y posee una clave (key).

El datastore es un mapa que almacena pares <clave, valor>, donde el valor es la entidad.

Las consultas se hacen a través de un objeto de tipo Query que se ejecuta a través de un prepareQuery.

Query q= new Query(entidad).setFilter(


new FilterPredicate (prop,
Query.FilterOperator.EQUAL, val));
PreparedQuery pq=db.prepare(q);
Iterable<Entity> e=pq.asIterable();

Operaciones CRUD:

• Create
– put (Entity e): añade la entidad al datasotore y devuelve la clave que le asigna.
• Read
– get (int key): devuelve la entidad almacenada con esa clave.
• Update
– get entidad
– actualizar entidad auxiliar
– delete entidad del datastore original
– put auxiliar en el datastore
• Delete
– delete (Key … keys): elimina las entidades almacenadas con las claves pasadas por
parámetro.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 43
5. EJEMPLO COMPLETO USANDO GWT

Este ejemplo es una aplicación que gestiona (añade y elimina) los contactos de una lista. En el diseño se
ha tenido como referencia el modelo de arquitectura llamado Modelo-Presentador-Vista:

Ilustración 13. Modelo-Vista-Presentador

Cuando el usuario interactúa con la vista, se genera un evento, el presentador analiza el evento y
actualiza el modelo, el cambio de estado en el modelo provoca una actualización de la vista que es
realizada por el presentador.

La arquitectura de la aplicación resultante de aplicar el modelo anterior es la siguiente:

El controlador (AppController) decide que manejador de eventos debe actuar, actualiza el histórico de
interacción del usuario y delega responsabilidades al presentador adecuado.

La distribución del código fuente está organizada en los siguientes paquetes:


 Client: En este paquete desarrollamos todo el código Java con el que GWT genera Javascript y
HTML que se procesa en el navegador.
o paquete cliente: Controlador, punto de entrada, interfaces de servicio.
o paquete presentador: Presentador para los contactos y para el detalle de los contactos.
Un presentador enlaza el modelo con la vista y con la lógica definida en los
manejadores.
o paquete eventos: define los eventos y especifica los manejadores de los mismos. La
implementación de los manejadores se lleva a cabo en el Controlador.
o paquete vista: define la distribución de widgets y paneles que se añaden al RootPanel.
Son dos las vistas que define la aplicación, una con respecto a la consulta de datos de los
contactos y otra de edición de esos datos.
 Server: En este paquete desarrollamos el código del lado de servidor (backend).

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 44
o ContactsServiceImpl : Implementación del servlet con los servicios de borrado, añadir,
obtener, actualizar datos del contacto.
 Shared: Para implementar clases cuyos objetos se usarán tanto en cliente como en servidor. En
el ejemplo se implementa el modelo de negocio.
o Clase Contact: Definición de contacto.
o Clase DetailContact: Definición de los detalles del contacto.

Esta organización se especifica en el fichero Contacts.gwt.xml


<!-- Specify the paths for translatable code -->
<source path='client'/>
<source path='shared'/>
<source path='test'/>

El servlet principal definido en el web.xml será:


package com.google.gwt.sample.contacts.server;
...
@SuppressWarnings("serial")
public class ContactsServiceImpl extends RemoteServiceServlet implements
ContactsService {
//inicializar la lista de contactos
//implementar añadir, borrar, obtener y actualizar los contactos
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 45
Ilustración 14. Arquitectura de la aplicación.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 46
Vistas de usuario:

Ilustración 16. Entrada a la applicación. Ilustración 15. Respuesta al pulsar "Add"

<body>

<!-- OPTIONAL: include this if you want history support -->

<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1'


style="position:absolute;width:0;height:0;border:0"></iframe>

</body>

El fichero HTML incorpora un iframe para el soporte del histórico de las interacciones del usuario. Esto
será relevante para el controlador de la aplicación que será el encargado de la transición entre vistas (lo
que se almacena es el estado de las mismas).

Otro de los puntos principales de la aplicación es el módulo de entrada. En el fichero Contacts.gwt.xml


se especifica la clase definida como punto de entrada a la aplicación y las rutas client, shared, test.

<entry-point class='com.google.gwt.sample.contacts.client.Contacts'/>

La clase de entrada es Contacts.java


package com.google.gwt.sample.contacts.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.ui.RootPanel;

public class Contacts implements EntryPoint {

public void onModuleLoad() {


ContactsServiceAsync rpcService = GWT.create(ContactsService.class);
HandlerManager eventBus = new HandlerManager(null);
AppController appViewer = new AppController(rpcService, eventBus);
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 47
appViewer.go(RootPanel.get());
}
}

1. La clase GWT contiene un método que crea una instancia de una clase vinculada al punto de
entrada (ContactsService). Esta clase tendrá el comportamiento definido en la interfaz
ContactsServiceAsync que contiene los métodos que el servidor invoca como respuesta a la
petición de servicio del cliente. Esta clase se crea automáticamente por GWT cuando se define la
interfaz ContactService que será implementada por el servlet ContactServiceImpl encargado de
prestar el servicio al cliente.
2. Crea el manejador principal de eventos de la aplicación (HandlerManager).
3. Crea el controlador (AppController): es el encargado de añadir los diferentes GwtEvent creados
al HandlerManager, los contenedores de widgets y el servlet con la lógica principal.
4. Crea la vista (AppViewer): appViewer.go(RootPanel.get());
añade como contenedor de la aplicación el panel raíz definido por GWT. Es el contenedor
principal de widgets.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 48
Controlador: Clase AppControler
Con la clase com.google.gwt.user.client.History, el controlador lleva un histórico con la
interacción del usuario con el navegador.

A continuación vamos a ver cómo se desarrolla la lógica del mismo distinguiendo entre los eventos,
presentadores y vistas.

Manejadores de Eventos
El controlador crea y asigna al HandlerManager los diferentes manejadores creados para los diferentes
tipos de eventos a los que hay que responder en la aplicación.

Los eventos y manejadores de eventos están definidos en las siguientes clases:

a. AddContactEvent y el manejador AddContactEventHandler.


b. ContactDeletedEvent y el manejador ContactDeletedEventHandler.
c. ContactUpdatedEvent y el manejador ContactUpdatedEventHandler.
d. EditContactEvent y el manejador EditContactEventHandler.
e. EditContactCancelledEvent y el manejador EditContactCancelledEventHandler.

Como ejemplo se analizará en detalle la lógica para añadir un nuevo contacto, el evento está definido en
AddContactEvent y el manejador es el AddContactEventHandler.

package com.google.gwt.sample.contacts.client.event;
import com.google.gwt.event.shared.GwtEvent;
public class AddContactEvent extends GwtEvent<AddContactEventHandler> {
public static Type<AddContactEventHandler> TYPE = new Type<AddContactEventHandler>();
@Override
public Type<AddContactEventHandler> getAssociatedType() { return TYPE; }
@Override
protected void dispatch(AddContactEventHandler handler) { handler.onAddContact(this); }
}

Para registrar el evento concreto al que dará respuesta el manejador, se usa el tipo Type:
Type<AddContactEventHandler>.

El manejador es una interfaz que será definida e instanciada en el controlador. Define el método en el
que se implementará la lógica concreta para el evento que se desea manejar.

package com.google.gwt.sample.contacts.client.event;

import com.google.gwt.event.shared.EventHandler;

public interface AddContactEventHandler extends EventHandler {


void onAddContact(AddContactEvent event);
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 49
El código en el que se ve reflejada la asociación del evento al manejador está en el controlador y es el
siguiente:
eventBus.addHandler(AddContactEvent.TYPE,
new AddContactEventHandler() {
public void onAddContact(AddContactEvent event) {
doAddNewContact();
}
});
donde eventBus es un HandlerManager creado en el punto de entrada.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 50
Presentadores
Los presentadores son los encargados de enlazar el modelo (Contacto y Detalles) con la vista y dotar de
inteligencia a la misma (manejadores de eventos). Los manejadores serán cargado en el contenedor
principal. El controlador determina que presentador se ejecuta en cada momento.

public void onValueChange(ValueChangeEvent<String> event) {


String token = event.getValue();

if (token != null) {
Presenter presenter = null;

if (token.equals("list")) {
presenter = new ContactsPresenter(rpcService, eventBus, new ContactsView() );
}
else if (token.equals("add")) {
presenter = new EditContactPresenter(rpcService, eventBus, new EditContactView());
}
else if (token.equals("edit")) {
presenter = new EditContactPresenter(rpcService, eventBus, new EditContactView());
}

if (presenter != null) {
presenter.go(container);
}
}
}

Existen dos presentadores en la aplicación (dos vistas):

 ContactsPresenter. Muestra la vista con el listado de todos los contactos dados de alta en la
aplicación.
o Define el modelo:
private List<ContactDetails> contactDetails;
o Define la vista ContactsView.
 EditContactPresenter. Muestra un formulario para editar los detalles de un contacto
determinado.
o modelo es un objeto de la clase Contact.
o vista es EditContactView.

Como ejemplo se analizará el código del presentador ContactsPresenter:

package com.google.gwt.sample.contacts.client.presenter;
import ...;

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 51
public class ContactsPresenter implements Presenter {
public interface Display {
HasClickHandlers getAddButton();
HasClickHandlers getDeleteButton();
HasClickHandlers getList();
void setData(List<String> data);
int getClickedRow(ClickEvent event);
List<Integer> getSelectedRows();
Widget asWidget();
}

private List<ContactDetails> contactDetails;


private final ContactsServiceAsync rpcService;
private final HandlerManager eventBus;
private final Display display;

public ContactsPresenter(ContactsServiceAsync rpcService, HandlerManager eventBus, Display view){


this.rpcService = rpcService;
this.eventBus = eventBus;
this.display = view;
}

public void bind() {


display.getAddButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
eventBus.fireEvent(new AddContactEvent());
}
});

display.getDeleteButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
deleteSelectedContacts();
}
});

display.getList().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
int selectedRow = display.getClickedRow(event);

if (selectedRow >= 0) {
String id = contactDetails.get(selectedRow).getId();
eventBus.fireEvent(new EditContactEvent(id));
}
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 52
});
}

public void go(final HasWidgets container) {


bind();
container.clear();
container.add(display.asWidget());
fetchContactDetails();
}

public void sortContactDetails() {


for (int i = 0; i < contactDetails.size(); ++i) {
for (int j = 0; j < contactDetails.size() - 1; ++j) {
if (contactDetails.get(j).getDisplayName().compareToIgnoreCase(contactDetails.get(j +
1).getDisplayName()) >= 0) {
ContactDetails tmp = contactDetails.get(j);
contactDetails.set(j, contactDetails.get(j + 1));
contactDetails.set(j + 1, tmp);
}
}
}
}

public void setContactDetails(List<ContactDetails> contactDetails) {


this.contactDetails = contactDetails;
}

public ContactDetails getContactDetail(int index) {


return contactDetails.get(index);
}

private void fetchContactDetails() {


rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() {
public void onSuccess(ArrayList<ContactDetails> result) {
contactDetails = result;
sortContactDetails();
List<String> data = new ArrayList<String>();

for (int i = 0; i < result.size(); ++i) {


data.add(contactDetails.get(i).getDisplayName());
}

display.setData(data);
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 53
public void onFailure(Throwable caught) {
Window.alert("Error fetching contact details");
}
});
}

private void deleteSelectedContacts() {


List<Integer> selectedRows = display.getSelectedRows();
ArrayList<String> ids = new ArrayList<String>();

for (int i = 0; i < selectedRows.size(); ++i) {


ids.add(contactDetails.get(selectedRows.get(i)).getId());
}

rpcService.deleteContacts(ids, new AsyncCallback<ArrayList<ContactDetails>>() {


public void onSuccess(ArrayList<ContactDetails> result) {
contactDetails = result;
sortContactDetails();
List<String> data = new ArrayList<String>();

for (int i = 0; i < result.size(); ++i) {


data.add(contactDetails.get(i).getDisplayName());
}

display.setData(data);

public void onFailure(Throwable caught) {


Window.alert("Error deleting selected contacts");
}
});
}
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 54
Vistas
Las vistas son un conjunto de widgets añadidos a los paneles y al RootPanel en último lugar.

Los widgets y paneles son códigos en Java del lado del cliente usados para construir interfaces de
usuario.
También añade la lógica propia del cliente.

Existen dos vistas en la aplicación (dos vistas):

 ContactsView. Muestra la vista con el listado de todos los contactos dados de alta en la
aplicación.
 EditContactView. Muestra un formulario para editar los detalles de un contacto determinado.

ContactView.java

Widgets de GWT usados en esta vista Button, FlexTable.

El panel es tipo DecoratorPanel y HorizontalPanel.

public class ContactsView extends Composite implements ContactsPresenter.Display {


private final Button addButton;
private final Button deleteButton;
private FlexTable contactsTable;
private final FlexTable contentTable;

public ContactsView() {
DecoratorPanel contentTableDecorator = new DecoratorPanel();
initWidget(contentTableDecorator);
contentTableDecorator.setWidth("100%");
contentTableDecorator.setWidth("18em");

contentTable = new FlexTable();


contentTable.setWidth("100%");
contentTable.getCellFormatter().addStyleName(0, 0, "contacts-ListContainer");
contentTable.getCellFormatter().setWidth(0, 0, "100%");
contentTable.getFlexCellFormatter().setVerticalAlignment(0, 0, DockPanel.ALIGN_TOP);

// Create the menu


//
HorizontalPanel hPanel = new HorizontalPanel();
hPanel.setBorderWidth(0);
hPanel.setSpacing(0);
hPanel.setHorizontalAlignment(HorizontalPanel.ALIGN_LEFT);
addButton = new Button("Add");
hPanel.add(addButton);
deleteButton = new Button("Delete");
hPanel.add(deleteButton);
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 55
contentTable.getCellFormatter().addStyleName(0, 0, "contacts-ListMenu");
contentTable.setWidget(0, 0, hPanel);

// Create the contacts list


//
contactsTable = new FlexTable();
contactsTable.setCellSpacing(0);
contactsTable.setCellPadding(0);
contactsTable.setWidth("100%");
contactsTable.addStyleName("contacts-ListContents");
contactsTable.getColumnFormatter().setWidth(0, "15px");
contentTable.setWidget(1, 0, contactsTable);

contentTableDecorator.add(contentTable);
}

public HasClickHandlers getAddButton() {


return addButton;
}

public HasClickHandlers getDeleteButton() {


return deleteButton;
}

public HasClickHandlers getList() {


return contactsTable;
}

public void setData(List<String> data) {


contactsTable.removeAllRows();

for (int i = 0; i < data.size(); ++i) {


contactsTable.setWidget(i, 0, new CheckBox());
contactsTable.setText(i, 1, data.get(i));
}
}

public int getClickedRow(ClickEvent event) {


int selectedRow = -1;
HTMLTable.Cell cell = contactsTable.getCellForEvent(event);

if (cell != null) {
// Suppress clicks if the user is actually selecting the
// check box

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 56
//
if (cell.getCellIndex() > 0) {
selectedRow = cell.getRowIndex();
}
}

return selectedRow;
}

public List<Integer> getSelectedRows() {


List<Integer> selectedRows = new ArrayList<Integer>();

for (int i = 0; i < contactsTable.getRowCount(); ++i) {


CheckBox checkBox = (CheckBox)contactsTable.getWidget(i, 0);
if (checkBox.getValue()) {
selectedRows.add(i);
}
}

return selectedRows;
}

public Widget asWidget() {


return this;
}
}

El resultado de esta vista es:

Ilustración 17. Vista lista de contactos.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 57
Comunicación del Cliente con el Servidor.
La comunicación se realiza a través de llamadas asíncronas RCP, por lo tanto el navegador no se queda
bloqueado esperando la respuesta del servidor.

Por cada clase del modelo, se crea en el cliente una interfaz que extienda a RemoteService, con los
métodos que permitan realizar las operaciones CRUD sobre el modelo. Automáticamente se genera una
interfaz con el parámetro AsyncCallback que será ejecutado por el servidor como respuesta al cliente.

Modelo de Datos: Contacto

package com.google.gwt.sample.contacts.shared;
import java.io.Serializable;
import com.google.gwt.sample.contacts.shared.ContactDetails;

@SuppressWarnings("serial")
public class Contact implements Serializable {
public String id;
public String firstName;
public String lastName;
public String emailAddress;

public Contact() {}

public Contact(String id, String firstName, String lastName, String emailAddress) {


this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.emailAddress = emailAddress;
}

public ContactDetails getLightWeightContact() {


return new ContactDetails(id, getFullName());
}

public String getId() { return id; }


public void setId(String id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getEmailAddress() { return emailAddress; }
public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; }
public String getFullName() { return firstName + " " + lastName; }
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 58
Diseño de servicios

El modelo de acceso al servicio desde el cliente al servidor se hace a través de un objeto de tipo
RemoteService.

package com.google.gwt.sample.contacts.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import java.util.ArrayList;

import com.google.gwt.sample.contacts.shared.Contact;
import com.google.gwt.sample.contacts.shared.ContactDetails;

@RemoteServiceRelativePath("contactsService")
public interface ContactsService extends RemoteService {

Contact addContact(Contact contact);


Boolean deleteContact(String id);
ArrayList<ContactDetails> deleteContacts(ArrayList<String> ids);
ArrayList<ContactDetails> getContactDetails();
Contact getContact(String id);
Contact updateContact(Contact contact);
}

A partir de la interfaz anterior se genera automáticamente el servicio asíncrono del cliente. Esta interfaz
es necesaria ya que contiene el parámetro AsyncCallback que será ejecutada por el servidor cuando el
cliente invoque un servicio al mismo.

package com.google.gwt.sample.contacts.client;

import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.ArrayList;

import com.google.gwt.sample.contacts.shared.Contact;
import com.google.gwt.sample.contacts.shared.ContactDetails;

public interface ContactsServiceAsync {

public void addContact(Contact contact, AsyncCallback<Contact> callback);


public void deleteContact(String id, AsyncCallback<Boolean> callback);
public void deleteContacts(ArrayList<String> ids, AsyncCallback<ArrayList<ContactDetails>> callback);
public void getContactDetails(AsyncCallback<ArrayList<ContactDetails>> callback);
public void getContact(String id, AsyncCallback<Contact> callback);
public void updateContact(Contact contact, AsyncCallback<Contact> callback);
}

Implementación del servicio que atiende a las peticiones del cliente:

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 59
package com.google.gwt.sample.contacts.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import com.google.gwt.sample.contacts.client.ContactsService;
import com.google.gwt.sample.contacts.shared.Contact;
import com.google.gwt.sample.contacts.shared.ContactDetails;

@SuppressWarnings("serial")
public class ContactsServiceImpl extends RemoteServiceServlet implements
ContactsService {

private static final String[] contactsFirstNameData = new String[] {...};


private final String[] contactsLastNameData = new String[] {...};
private final String[] contactsEmailData = new String[] {...};
private final HashMap<String, Contact> contacts = new HashMap<String, Contact>();

public ContactsServiceImpl() { initContacts(); }

private void initContacts() {


// TODO: Create a real UID for each contact

for (int i = 0; i < contactsFirstNameData.length && i < contactsLastNameData.length && i <


contactsEmailData.length; ++i) {
Contact contact = new Contact(String.valueOf(i), contactsFirstNameData[i],
contactsLastNameData[i], contactsEmailData[i]);
contacts.put(contact.getId(), contact);
}
}

public Contact addContact(Contact contact) {


contact.setId(String.valueOf(contacts.size()));
contacts.put(contact.getId(), contact);
return contact;
}

public Contact updateContact(Contact contact) {


contacts.remove(contact.getId());
contacts.put(contact.getId(), contact);
return contact;
}

public Boolean deleteContact(String id) {


contacts.remove(id);
return true;
}

public ArrayList<ContactDetails> deleteContacts(ArrayList<String> ids) {

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 60
for (int i = 0; i < ids.size(); ++i) {
deleteContact(ids.get(i));
}

return getContactDetails();
}

public ArrayList<ContactDetails> getContactDetails() {


ArrayList<ContactDetails> contactDetails = new ArrayList<ContactDetails>();

Iterator<String> it = contacts.keySet().iterator();
while(it.hasNext()) {
Contact contact = contacts.get(it.next());
contactDetails.add(contact.getLightWeightContact());
}

return contactDetails;
}

public Contact getContact(String id) {


return contacts.get(id);
}
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 61
Lado del cliente.

Consumo del servicio desde los presentadores del cliente:


 ¿qué hacer en cada evento de usuario?
 ¿qué respuesta da el cliente al servidor al invocar un servicio?
 siguiente vista a mostrar
La estructura de la lógica del Presentador para los contactos queda como sigue:

package com.google.gwt.sample.contacts.client.presenter;

import ...;

public class ContactsPresenter implements Presenter {


public interface Display {...}
public ContactsPresenter(ContactsServiceAsync rpcService, HandlerManager eventBus, Display view) {
this.rpcService = rpcService;
this.eventBus = eventBus;
this.display = view;
}
public void bind() {...}
public void go(final HasWidgets container) {... }
public void sortContactDetails() {... }
public void setContactDetails(List<ContactDetails> contactDetails) {...}
public ContactDetails getContactDetail(int index) {...}
private void fetchContactDetails() {... }
private void deleteSelectedContacts() {... }
}

Por ejemplo el Presentador para la vista de Contactos y los detalles quedaría de la siguiente forma:

 Los atributos del presentador son:


private List<ContactDetails> contactDetails;
private final ContactsServiceAsync rpcService;
private final HandlerManager eventBus;
private final Display display;

 Con la interfaz de Display representamos el comportamiento necesario para interactuar con la


vista, en nuestro caso con la clase ContactsView.
public interface Display {
HasClickHandlers getAddButton();
HasClickHandlers getDeleteButton();
HasClickHandlers getList();
void setData(List<String> data);
int getClickedRow(ClickEvent event);
List<Integer> getSelectedRows();
Widget asWidget();
}

El presentador asigna a cada componente de la vista el manejador de eventos y define el evento a


tratar. Por ejemplo para el caso del botón "Add" asigna el comportamiento de añadir un nuevo

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 62
contacto, este comportamiento está definido en el AddContactEvent y manejado por el método
onClick() del manejador ClickHandler.

public void bind() {


display.getAddButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
eventBus.fireEvent(new AddContactEvent());
}
});
...
}

 Desde el controlador (AppController) se invoca al método go del presentador correspondiente.


Este método ejecuta la carga de manejadores de eventos así como la interfaz de usuario
correspondiente. Por ejemplo, para "añadir un contacto", se ejecuta el siguiente método
implementado en el presentador correspondiente. Este método hace uso de otro que define la
respuesta que el servidor da al cliente cuando éste solicita el servicio.

public void go(final HasWidgets container) {


bind();
container.clear();
container.add(display.asWidget());
fetchContactDetails();
}

El siguiente método imprime los nombres de los contactos en la vista de usuario.

private void fetchContactDetails() {


rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() {
public void onSuccess(ArrayList<ContactDetails> result) {
contactDetails = result;
sortContactDetails();
List<String> data = new ArrayList<String>();

for (int i = 0; i < result.size(); ++i) {


data.add(contactDetails.get(i).getDisplayName());
}

display.setData(data);
}

public void onFailure(Throwable caught) {


Window.alert("Error fetching contact details");
}
});
}

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 63
6. Casos reales de aplicación de GWT.

 GBST : software para servicios financieros.


o Mejora de la productividad
 DayZipping : servicios de hosting.
o Mejora de la representación visual y de la productividad del desarrollo.
 Eureka Streams: plataforma de redes sociales empresariales de código libre.
o Gestión del código Java base del portal. Mejora la modularidad del código.
 Rovio : diseño de aplicaciones destinadas al entretenimiento.
o Desarrollo del juego Angry Birds para escritorio.

Caso de Estudio GBST.

GBST es un proveedor de software y servicios para la industria financiera global. Los objetivos son
los siguientes:

- distribuir la experiencia a través de los navegadores.


- optimizar la interfaz gráfica de la aplicación.
- proporcionar confidencialidad en su tecnología.

Para alcanzar estos objetivos, se han centrado en el estudio de la estandarización del desarrollo web,
la consistencia y rapidez en los datos y la ventaja competitiva que supone el talento y la habilidad de
las personas.

Los resultados han demostrado que el uso de Java aumenta fuertemente la productividad, que son
necesarios nuevas capacidades dinámicas y nuevos modelos de estados en las transacciones y que la
plataforma de Google es estable y solida.

El uso de GWT ayuda a la compañía GBST a crear aplicaciones soportadas por un mayor número de
navegadores, ha aumentado la productividad en el desarrollo (más rápido y estable) y ha mejorado la
flexibilidad y optimizado la interfaz de usuario.

Todo el código generado es abierto y completamente libre.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 64
7. El Futuro de GWT

En Vaadin han creado un informe sobre el futuro de GWT para el 2012.

Este informe responde a respuestas como:


 ¿Cuándo debo usar GWT?
 ¿Tiene sentido usar GWT en mi próximo proyecto?
 ¿Qué es lo peor de GWT?
 ¿Qué nuevas características debe incluir GWT 3?

El informe se ha creado a través de las respuestas de más de 1300 personas que


trabajan con GWT (y Vaadin):
 80 % de las aplicaciones son para los negocios.
 46 % desarrolladas en US y soportadas por tablets.
 89 % de las personas encuestadas usarían GWT en su próximo proyecto.

https://vaadin.com/gwt/report-2012

Uso de GWT:

La mitad del uso de


GWT es pagando.

Distribución del uso de GWT:

En Europa es dónde
es más frecuente el
uso de GWT..

Tamaño del Javascript generado por la aplicación GWT:

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 65
Las aplicaciones
generadas son de
pequeño tamaño.

Cómo se construyen las ventanas:

La forma de generar
las interfaces de
usuario más
frecuente son a
mano.

Comunicación con el backend:

La comunicación con
el servidor se hace a
través de llamadas
RPC.

Uso de Javascript desde GWT:

Lo peor de GWT:

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 66
Elevado tiempo
de compilación.

Lo mejor de GWT:

Alta
compatibiliad
de las
aplicaciones
con los
navegadores.

Competidores (para los desarrolladores de aplicaciones GWT):

Competencia
con los servicios
REST.

Los cambios desde la versión de GWT desde 2012 son los siguientes:

 Nuevo repositorio Git


o http://gwt.googlesource.com
 Código revisado
o http://gwt-review.googlesource.com
 Imágenes en GitHub
o http://github.com/gwtproject
 Integración de hosting con Red Hat
o http://build.gwtproject.org
 Nueva Website

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 67
o http://gwtproject.org

El foco de interés actualmente está puesto en las siguientes áreas:

 Código abierto y simple


o Reducción de dependencias.
o Reducción de necesidad de ficheros .gwt.xml.
 Agilidad desarrollo
o Compilación 50 % más rápida.
o Uso de la máquina virtual JS VM
 Interoperabilidad
o Mejora interacción Java-Javascript
 Mobilidad
o Optimización de widgets para móviles.
o Adaptación a los nuevos navegadores.
 Código embebido.
o Integración con otras herramientas.
o GWT SDK de pequeño tamaño.

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 68
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 69
8. BIBLIOGRAFÍA

BÁSICA

GWT in Action, Second Edition

Adam Tacy, Robert Hanson, Jason Essington, and Anne Tökke

January 2013 | 680 pages


ISBN: 9781935182849

ENLACES

 [1] Sitio oficial de Google Web Toolkit (en inglés)


 [2] http://www.gwtproject.org/doc/latest/tutorial/gettingstarted.html
 [3] Tutorial de GWT con PHP y MySQL
 [4] www.ongwt.com : News web site on GWT
 [5] Widgets de GWT (I):
https://developers.google.com/web-toolkit/doc/1.6/RefWidgetGallery
 [6] Widgets de GWT (II):
http://gwt.googleusercontent.com/samples/Showcase/Showcase.html
 [7] API GWT.
http://www.gwtproject.org/javadoc/latest/overview-summary.html
 [8] Datastore con JDO:
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=datastoreJDO
 [9] El API Java de almacén de datos:
https://developers.google.com/datastore/docs/concepts/overview
 [10] Futuro de GWT:
http://unpocodejava.wordpress.com/2012/12/12/el-futuro-de-gwt/
https://vaadin.com/tools-and-services
http://commondatastorage.googleapis.com/io-2013/presentations/251%20-
%20I_O%202013%20GWT%20Roadmap%20for%20the%20Future.pdf

Framework GWT. © Rafael Manuel Reina Ramírez


Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 70
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 71
Framework GWT. © Rafael Manuel Reina Ramírez
Desarrollo de Aplicaciones Web. Máster Ingeniería y Tecnología del Software. Página 72

También podría gustarte