viernes, 9 de septiembre de 2011

GWT Editor

El GWT Editor framework es un componente de Google Web Toolkit disponible a partir de la versión 2.1 que te permite de forma fácil enviar los datos de tus objetos del código a la interfaz de usuario y viceverza. Es decir hacer el vínculo de datos o data binding. Estuve probando un ejemplo sencillo del blog de Arthur Kalmenson CustomerDemo que muestra el uso del GWT Editor sin hacer uso de persistencia el código que recopilé ligeramente modificado pueden descargarlo aquí.
A continuación voy a explicar un poco el ejemplo.


Empezando por la lista de archivos.
CustomerDemo.java es el entry point o archivo de entrada de la aplicación y su método es el onModuleLoad() es como el void main() en java estandar.
Los archivos UiBinder EmailEditor.ui.xml y su clase manejadora EmailEditor.java los creé con el asistente New->UiBinder del GPE(Google Plugin for Eclipse), igualmente con los archivos CustomerEditor.ui.xml y CustomerEditor.java.
Las clases Customer.java y Email.java son simples POJO(Plain Old Java Object) files. Es decir no contienen código adicional además de sus propiedades y metodos. En Eclipse IDE una vez digitado las propiedades se pueden generar los métodos getters y setters haciendo click derecho en el código fuente y seleccionar del menú contextual Source->Generate Getters and Setters...

La clase Customer.java
public class Customer {
 private String firstName, lastName;
 private Email email;
 
 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 Email getEmail() {
  return email;
 }
 public void setEmail(Email email) {
  this.email = email;
 } 
}
Como puede notar una propiedad del bean(así se les llama a las clases POJO) Customer es email un objeto de la clase Email. En este ejemplo no se usa la persistencia(uso de un almacén de datos). Pero este bean podría almacenarse perfectamente en el DataStore del AppEngine(El servicio de alojamiento de aplicaciones de Google o servicio de hosting) el DataStore usa BigTable un almacen de datos NoSql es decir no relacional. Se puede pensar en que tus datos son almacenados en HashMaps dentro de HashMaps.Por tanto la clase Customer puede almacenar tipos primitivos como String hasta objetos embebidos como Email.

Los archivos EmailEditor.java y EmailEditor.ui.xml
Es el par de archivos necesarios para utilizar UiBinder. En GWT es posible definir las vistas de mi aplicación  utilizando código Java al estilo del Java Swing. Pero los desarrolladores web estamos acostumbrados a utilizar HTML y CSS para definir nuestras vistas de aplicación. UiBinder Permite mezclar HTML y Widgets GWT y permite el uso de hojas de estilo. Al mismo tiempo se logra una separación entre el código que define la interfaz(EmailEditor.ui.xml) y la lógica de aplicación(EmailEditor.java).
package com.customerdemo.client;

import com.customerdemo.shared.Email;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class EmailEditor extends Composite implements Editor<Email> {

 private static EmailEditorUiBinder uiBinder = GWT
   .create(EmailEditorUiBinder.class);

 interface EmailEditorUiBinder extends UiBinder<Widget, EmailEditor> {
 }
 
 @UiField
 TextBox email;

 public EmailEditor() {
  initWidget(uiBinder.createAndBindUi(this));
 }

}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
 xmlns:g="urn:import:com.google.gwt.user.client.ui">
 <ui:style>
  
 </ui:style>
 <g:HTMLPanel>
  <div>
   Email:
   <g:TextBox ui:field="email" />
  </div>
 </g:HTMLPanel>
</ui:UiBinder>
Esta clase manejadora implementa la interfaz parametrizada Editor<T> e indica que EmailEditor es un widget bindable(vinculable) con la clase Email.
En el constructor EmailEditor() es donde se carga e inicializa la interfaz.
Los widgets GWT tienen el prefijo <g: como <g:HTMLPanel> y <g:TextBox ui:field="email" /> para poder usar el TextBox en la aplicación es necesario incluirlo en la clasae manejadora EmailEditor  como atributo.

@UiField
TextBox email;

La anotación @UiField indica que el widget se encuentra en su respectivo archivo UiBinder EmailEditor.ui.xml. TextBox email Indica que es un TextBox y que tiene como atributo ui:field="email" .Este atributo ui:field es el que se utiliza para vincular los widgets del UiBinder con el código Java de su clase manejadora.
La clase EmailEditor es un widget personalizado que puede hacer uso de los beneficios del GWT Editor.

Los archivos CustomerEditor.java y CustomerEditor.ui.xml
package com.customerdemo.client;

import com.customerdemo.shared.Customer;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class CustomerEditor extends Composite implements Editor<Customer> {

 private static CustomerEditorUiBinder uiBinder = GWT
   .create(CustomerEditorUiBinder.class);

 interface CustomerEditorUiBinder extends UiBinder<Widget, CustomerEditor> {
 }
 
 @UiField
 TextBox firstName;

 @UiField
 TextBox lastName;

 @UiField
 EmailEditor emailEditor;

 public CustomerEditor() {
  initWidget(uiBinder.createAndBindUi(this));
 }

}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
 xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:d="urn:import:com.customerdemo.client">
 <ui:style>
  
 </ui:style>
 <g:HTMLPanel>
  <h3>Customer</h3>
  <div>
   First Name:
   <g:TextBox ui:field="firstName" />
  </div>
  <div>
   Last Name:
   <g:TextBox ui:field="lastName" />
  </div>  
  <div>   
   <d:EmailEditor ui:field="emailEditor" />
  </div>
 </g:HTMLPanel>
</ui:UiBinder>
La única diferencia con el anterior es que aquí esta haciendo uso el widget personalizado EmailEditor  para poder incluirlo en el archivo UiBinder es necesario importar el paquete donde se encuentra haciendo uso de un namespace xmlns:d="urn:import:com.customerdemo.client". Esto indica que los widgets personalizados estan en el paquete com.customerdemo.client y xmlns:d indica que voy a acceder a los widgets por medio del prefijo <d: en este caso <d:EmailEditor ui:field="emailEditor" /> .

El entry point CustomerDemo.java

package com.customerdemo.client;

import com.customerdemo.shared.Customer;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.SimpleBeanEditorDriver;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;

public class CustomerDemo implements EntryPoint {
 interface Driver extends SimpleBeanEditorDriver<Customer, CustomerEditor> {
 }

 Driver driver = GWT.create(Driver.class);

 public void onModuleLoad() {
  CustomerEditor editor = new CustomerEditor();
  driver.initialize(editor);
  driver.edit(new Customer());

  RootPanel.get().add(editor);

  Button button = new Button("Get Data");
  RootPanel.get().add(button);

  button.addClickHandler(new ClickHandler() {

   public void onClick(ClickEvent arg0) {
    Customer customer = driver.flush();
    Window.alert("first name: "
      + customer.getFirstName() + ", last name: "
      + customer.getLastName());
   }
  });
 }
}
Para decirle a la aplicación que este archivo es el archivo de arranque debe implementar la interfaz EntryPoint . El GWT Editor utiliza clases Driver para vincular un POJO con su vista o un bean con su editor. Estas clases son SimpleBeanEditorDriver y RequestFactoryEditorDriver. El botón se ha creado utilizando código java y se le agregó un evento onClick. La vista y el botón se agregó al cuerpo de la página web haciendo uso de RootPanel.get() que te devuelve el <body> de la página. Dentro del evento obtengo los datos ingresados llamando al método flush() del Driver.

El archivo de módulo CustomerDemo.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='customerdemo'>  
  <inherits name='com.google.gwt.user.User'/>
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <entry-point class='com.customerdemo.client.CustomerDemo'/>  
  <source path='client'/>
  <source path='shared'/>
</module>
En este archivo xml se indica los módulos que utilizará nuestra aplicación. Un módulo es una librería diseñado exclusivamente para su uso dentro de GWT. Aquí también le indico a mi aplicación donde está mi archivo de arranque o entry point. Además se indica los paquetes que se traducirán a Javascript que son el client y shared. El paquete shared se llama así porque su contenido es utilizado por el cliente (Javascript) y el servidor(Java).

El archivo web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app> 
  
  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>CustomerDemo.html</welcome-file>
  </welcome-file-list>

</web-app>

Como toda aplicación web Java aquí es donde es definen los servlets y la página por defecto CustomerDemo.html y otras configuraciones.

No hay comentarios:

Publicar un comentario