Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Toolkit GWT y
AppEngine
Desarrollo de aplicaciones Web
Estudio teórico de la herramienta de desarrollo web creado por Google.
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.
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.
GWT SDK
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:
midominio.appspot.com.
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.
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.
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 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.
• 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.
Arquitectura de GWT:
Módulos GWT:
INSTALACIÓN
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.
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.
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().
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:
<!-- 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'/>
<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>
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".
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() {
...
}
}
Crear UI
// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();
...
}
...
}
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.
/**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;
}
serverResponseLabel.setHTML(SERVER_ERROR);
dialogBox.center();
closeButton.setFocus(true);
} //fin onFailure
Está basado en widgets. Entre los widgets tenemos contenedores (paneles), y controles (botones,
etiquetas, etc…).
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.
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:
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).
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
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.
Si no hemos utilizado Java para los servicios remotos podemos desplegar en cualquier servidor web http
como Apache.
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.
En "appcfg" podremos configurar la aplicación en función del tipo de lenguaje de programación que
utilicemos.
Debemos configurar las propiedades del proyecto App Engine para añadirle un ID al mismo.
https://developers.google.com/appengine/docs/java/datastore/overview
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:
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.
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
import javax.jdo.annotations.PersistenceCapable;
1. import javax.jdo.annotations.IdentityType;
2.
3. @PersistenceCapable(identityType = IdentityType.APPLICATION)
4. public class Tutorial { ... }
@Persistent
1. import javax.jdo.annotations.Persistent;
2.
3. @Persistent
4. private String autor;
@NotPersistent
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.
@PrimaryKey
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:
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
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.
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.
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;
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.
Create makePersistent()
Read getObjectById()
Update 1. recuperar objeto.
2. modificarlo.
Actualización automática
Delete deletePersistent()
Ilustración 14. Operaciones CRUD.
Create (creación)
Es posible utilizar JDOQL para realizar las consultas de objetos persistentes con JDO como se verá mas
adelante.
Update (actualización)
Delete (borrado)
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.
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:
es equivalente a
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 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.
Donde:
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.
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.
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.
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.
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.
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:
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.
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.
<body>
</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).
<entry-point class='com.google.gwt.sample.contacts.client.Contacts'/>
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;
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.
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.
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;
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);
}
}
}
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.
package com.google.gwt.sample.contacts.client.presenter;
import ...;
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));
}
}
display.setData(data);
}
display.setData(data);
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.
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
public ContactsView() {
DecoratorPanel contentTableDecorator = new DecoratorPanel();
initWidget(contentTableDecorator);
contentTableDecorator.setWidth("100%");
contentTableDecorator.setWidth("18em");
contentTableDecorator.add(contentTable);
}
if (cell != null) {
// Suppress clicks if the user is actually selecting the
// check box
return selectedRow;
}
return selectedRows;
}
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.
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() {}
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 {
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;
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 {
return getContactDetails();
}
Iterator<String> it = contacts.keySet().iterator();
while(it.hasNext()) {
Contact contact = contacts.get(it.next());
contactDetails.add(contact.getLightWeightContact());
}
return contactDetails;
}
package com.google.gwt.sample.contacts.client.presenter;
import ...;
Por ejemplo el Presentador para la vista de Contactos y los detalles quedaría de la siguiente forma:
display.setData(data);
}
GBST es un proveedor de software y servicios para la industria financiera global. Los objetivos son
los siguientes:
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.
https://vaadin.com/gwt/report-2012
Uso de GWT:
En Europa es dónde
es más frecuente el
uso de GWT..
La forma de generar
las interfaces de
usuario más
frecuente son a
mano.
La comunicación con
el servidor se hace a
través de llamadas
RPC.
Lo peor de GWT:
Lo mejor de GWT:
Alta
compatibiliad
de las
aplicaciones
con los
navegadores.
Competencia
con los servicios
REST.
Los cambios desde la versión de GWT desde 2012 son los siguientes:
BÁSICA
ENLACES