GWT

RECU-0139 (Recurso Referencia)

Descripción

Google Web Toolkit (GWT) es un framework de desarrollo en Java de código abierto, que te permite escapar de la “matriz” de tecnologías usadas actualmente para escribir aplicaciones AJAX, las cuales son difíciles de manejar y propensas a errores. Con GWT, puedes desarrollar y depurar aplicaciones AJAX usando el lenguaje de programación Java en el entorno de desarrollo de tu preferencia (nos referimos al sistema operativo y a los IDEs). Cuando la aplicación escrita en Java esta finalizada, GWT compila y traduce dicho programa a JavaScript y HTML compatible con cualquier navegador web.

El ciclo de Desarrollo de GWT sería el siguiente:

  1. Usa tu entorno de desarrollo integrado (IDE) favorito para escribir y depurar una aplicación en Java, usando las librerías GWT que necesites.
  2. Usa el compilador de Java a JavaScript de GWT para transformar tu aplicación en un conjunto de archivos JavaScript y HTML que puedes colgar en cualquier servidor y ejecutar desde un navegador web.
  3. Verifica que tus aplicaciones trabajan sobre todos y cada uno de los navegadores que consideres que tus clientes usarán. 

En GWT puedes usar componentes de interfaz de usuario llamados Widgets, para construir aplicaciones AJAX con GUIs (interfaz de usuario gráfico) atractivas. Al igual que en la mayoría de los lenguajes de programación, los componentes de la UI (interfaz de usuario) son agrupados en paneles que determinan la ubicación de los mismos. A continuación veamos una completa aplicación que utiliza un botón y un manejador de eventos:

public class Hola implements EntryPoint{
       public void onModuleLoad(){
              Button b = new Button(“Click aquí”, new ClickListener(){
              public void onClick(Widget sender){
              Window.alert(“Hola,”);
              }
              });
              RootPanel.get().add(b);
       }
}

GWT soporta una gran cantidad de widgets que son útiles en el desarrollo de aplicaciones AJAX, incluyendo árboles, pestañas, barras de menú y menús de dialogo. GWT también soporta invocación de métodos remotos (RPC) y otras características.

Modo de Empleo

A continuación procedemos a describir el proceso de instalación de Google Web Toolkit.

Instalación

En primer lugar es descargar el archivo adecuado de acuerdo al sistema operativo que usemos:

http://code.google.com/webtoolkit/download.html

Instalación sobre Windows

Después de descargar la versión de GWT para Windows, descomprimimos el archivo y añadimos su ruta en el path de nuestro sistema operativo. Para ello, hacemos clic derecho en "Mi Pc" -> Propiedades -> Variables de entorno, y en Variables del sistema le damos doble clic a Path, y añadimos la ruta donde descomprimimos el GWT, del siguiente modo:

Ficha_GWT2.jpg

Esto se hace para nuestra comodidad a la hora de desarrollar, ya que de esta manera no es necesario que nos situemos en el path de instalación, desde la línea de comandos, para ejecutar los comandos más comunes.

Instalación sobre sistemas operativos GNU/Linux

Después de descargar el archivo correspondiente para GNU/Linux, lo descomprimimos con nuestro gestor de archivos comprimidos preferido, así:

tar xvzf gwt-linux-1.4.60.tar.bz2

Luego es necesario añadir la ruta donde descomprimimos los archivos al PATH de nuestros sistema. Para ello debemos editar el archivo .bashrc de nuestra sesión:

echo "#Path GWT" >> ~/.bashrc
echo "PATH=$PATH:/ruta/gwt" >> ~/.bashrc
echo "export PATH" >> ~/.bashrc
source ~/.bashrc

Hacemos esto para añadir la ruta donde se encuentra GWT a la variable de entorno PATH de tu sistema, con lo que podremos ejecutar los programas desde la línea de comandos, sin necesidad de situar la misma sobre la ruta del GWT.

Herramientas en la Línea de Comandos

GWT te ofrece un pequeño set de herramientas de línea de comandos fáciles de manejar, para realizar diferentes tareas de una manera rápida. Éstas son también útiles para añadir nuevas cosas a los proyectos existentes. Por ejemplo, projectCreator podría ser usado para crear un proyecto Eclipse para uno de los ejemplos que viene con GWT.

  • projectCreator: Genera el esqueleto de un proyecto básico y un archivo Ant opcional y/o proyecto para Eclipse.
  • aplicationCreator: Genera el lanzador de una aplicación
  • junitCreator: Genera un test JUnit
  • i18nCreator: Genera un archivo de propiedades i18n y un script de sincronización
  • benchmarkViewer: Muestra resultados benchmark

Documentos de Formación

“GWT in Action” by Robert Hanson & Adam Tacy (Editorial Manning)

“GWT in Practice” by Robert Cooper & Charles Collins (Editorial Manning)

“Google™ Web Toolkit Solutions (Digital Short Cut): Cool & Useful Stuff” by David Gery(Editorial Prentice Hall)

“Google Web Toolkit: Taking the Pain Out of Ajax” by de Burnette (Editorial The PragmaticProgrammer)

Características

Características principales que aporta utilizar Google Web Toolkit:

  • Componentes de la interfaz de usuario dinámicos y reutilizables
    Crea un Widget para construir otros. Coloca los Widgets automáticamente en Paneles. Envía tus Widget a otros desarrolladores en archivos JAR.
  • RPC realmente fácil
    Para comunicarte desde el navegador que lanza tu aplicación con tu servidor web, solamente necesitas definir clases de Java serializables para las peticiones y respuestas. En producción, GWT serializa automáticamente las peticiones del navegador y de-serializa las respuestas desde el servidor web. El mecanismo de RPC de GWT puede incluso manejar jerarquía de polimorfismo en clases, y puedes manejar las posibles excepciones.
  • Administración del historial del navegador
    Las aplicaciones en AJAX no necesitan utilizar el botón “Atrás” (o Back) del navegador. Y GWT no es la excepción, es decir, no es necesario que llames a otras páginas para realizar las diferentes acciones, ni recargar el navegador.
  • Depuración en tiempo real
    Para cuando tu aplicación esté lista, el código de la misma es traducido a JavaScript, pero mientras lo estás desarrollando este corre sobre una máquina virtual de Java (JVM). Lo que significa que en la fase de desarrollo tienes la posibilidad de depurar tu aplicación con los avanzados sistemas de debugging y manipulación de excepciones incluidos en IDEs como NetBeans.
  • Compatibilidad con los navegadores
    Tus aplicaciones en GWT serán automáticamente soportadas por navegadores como FireFox, Internet Explorer, Mozilla, Safari, y Opera sin ningún tipo de operación para la detección de los mismos, en la mayoría de los casos.
  • Integración con JUnit
    Mediante la integración de JUnit en GWT, puedes probar tus aplicaciones y depurarlas en un navegador mientras las construyes. Puedes testear llamadas asíncronas a procedimientos remotos RPC.
  • Internacionalización
    Crea aplicaciones y librerías de Internacionalización rápida y fácilmente.
  • Interoperabilidad y control
    Si las librerías de clases de GWT no son suficientes para lo que necesitas, puedes mezclar JavaScript en el código de tu aplicación usando la interfaz nativa de scripts de Java (JavaScript Native Interface, JSNI).
  • GWT es un proyecto de código abierto
    Todo el código de GWT está disponible bajo la licencia Apache 2.0.

Buenas prácticas y recomendaciones de uso

Buenas Prácticas

A la hora de definir clases del lado de servidor que implemente a una interfaz, esta clase debe llamarse igual que la interfaz más el sufijo “Impl” y debe extender la clase “RemoteServiceServlet”

El hecho de heredar de “RemoteServiceServlet”, hace que nos ahorremos el trabajo de implementar los típicos métodos de un Servlet (doGet() , doPost(),etc) y es esta clase la que se encarga de deserializar los parámetros recibidos y serializar la respuesta. Por lo tanto nuestra clase sólo se debe encargar de implementar los métodos específicos ya que del resto se encarga GWT.

Es importante tener en cuenta que los resultados de los métodos que van a ser serializados cuando los invoquemos desde el lado cliente, GWT impone los siguientes tipos:

  • Tipos primitivos.
  • Clases String y java.util.Date
  • Clases que implementan la interfaz isSerializable y cuyos campos no transient sean a su vez serializables.
  • Array de tipos de los anteriores

Recomendaciones de uso

Estructura de un proyecto GWT

Los proyectos Google Web Toolkit están cubiertos con una capa de paquetes de Java. Si estás iniciando un proyecto Google Web Toolkit desde cero, debes usar la capa de paquetes estándar de Google Web Toolkit, que permite diferenciar fácilmente el código del lado del cliente del código del lado del servidor. Por ejemplo, supongamos que tu nuevo proyecto es llamado "Calendar". La capa de paquetes estándar deberá verse así:

  • com/example/cal/:El paquete raíz del proyecto contiene archivos del módulo en XML com/example/cal/client/ Código del lado del cliente y subpaquetes
  • com/example/cal/server/: Código del lado del servidor y subpaquetes
  • com/example/cal/public/: Recursos estáticos que pueden ser servidos públicamente

Y archivos de dentro de los paquetes así:

  • com/example/cal/Calendar.gwt.xml: Un módulo básico para tu proyecto que hereda del módulo com.google.gwt.user.User
  • com/example/cal/CalendarApp.gwt.xml: Hereda del módulo com.example.cal.Calendar (arriba) y añade una clase de punto de entrada (entry-point)
  • com/example/cal/CalendarTest.gwt.xml: Un módulo definido por tu proyecto
  • com/example/cal/client/CalendarApp.java: Código fuente Java del lado del servidor para la clase entry-point
  • com/example/cal/client/spelling/SpellingService.java: Un interfaz del servicio RPC service definida en un subpaquete
  • com/example/cal/server/spelling/SpellingServiceImpl.java: Código fuente Java que implementa la lógica del servicio de verificación de sintaxis
  • com/example/cal/public/Calendar.html: Una página HTML que carga la aplicación
  • com/example/cal/public/Calendar.css: Una hoja de estilo para la aplicación
  • com/example/cal/public/images/logo.gif: Un logo

Los Módulos en GWT

Las unidades individuales de configuraciones en GWT son archivos XML llamados módulos. Un módulo reúne todos los datos de configuración que tu proyecto GWT necesita, es decir:

  • Módulos heredados
  • Un nombre de clase: esto es opcional, aunque cualquier módulo referido a un HTML debe tener al menos una clase entry-point especificada.
  • Entradas a los source paths
  • Entradas a los public paths

Los módulos pueden aparecer en cualquier paquete en tu classpath, aunque es altamente recomendable que estos aparezcan en el paquete raíz de un proyecto estándar.

Clases entry-point

Un módulo entry-point es cualquier clase que es asignable a EntryPoint y que puede ser construida sin parámetros. Cuando un módulo es cargado, cada clase entry point es instanciada y el método EntryPoint.onModuleLoad() es llamado.

Source Path

Los módulos pueden especificar qué subpaquetes contienen código fuente traducible, provocando que el paquete nombrado y sus subpaquetes sean añadidos al source path. Solamente los archivos encontrados en el source path son candidatos para ser traducidos a JavaScript, haciendo posible que se mezclen códigos fuentes del lado del cliente (client-side) con los del lado del servidor (server-side) en el mismo classpath sin ningún tipo de conflicto.

Cuando un módulo hereda de otro, sus source path son combinados así que cada módulo tendrá acceso al código fuente traducible que requiera.

Public path

Los módulos pueden especificar qué subpaquetes son públicos, provocando que el paquete nombrado y sus subpaquetes sean añadidos al public path. Cuando compilas tú aplicación a JavaScipt, todos los archivos que pueden ser encontrados sobre tu public path son copiados al directorio de salida de los módulos. El efecto en la red es que las URLs visibles al usuario no necesitan incluir un nombre de paquete completo.

Cuando un módulo hereda de otro módulo, sus public paths son combinados así que cada módulo tendrá acceso al recurso estático que requiera.

Especificaciones

  • Formato de módulos XML: Los módulos son definidos en XML y situados dentro de la jerarquía de paquetes de tu proyecto
  • Inclusión automática de paquetes: Los módulos contienen referencias a archivos JavaScript y CSS externos, causando que estos sean cargados cuando el módulo mismo es cargado.
  • Filtrado de paquetes públicos: Filtra archivos dentro y fuera de tu public path para evitar la publicación accidental de archivos.

Interfaces de Usuario

Las clases de interfaces de usuario de Google Web Toolkit son muy similares a las de los distintos frameworks como Swing o SWT, excepto que los widgets son creados y renderizados usando HTML creado dinámicamente.

Mientras sea posible manipular el DOM del navegador directamente usando la interfaz DOM, es más fácil usar las clases desde la jerarquía de widgets. Raramente necesitaremos usar DOM directamente. Usando widgets puedes construir interfaces de usuario rápidamente, y que se comporten de manera adecuada sobre todos lo navegadores.

Especificaciones
  • Widgets y panales: Los widgets y paneles son códigos en Java del lado del cliente usados para construir interfaces de usuario.
  • Galerías de Widgets: En esta entrada se listan los objetos de clase para construir interfaces de usuario
  • Events y Listeners: Los widgets pueden emitir eventos (Events) que son escuchados (Listener) por los manejadores de eventos respectivos.
  • Creando Widgets personalizados: Crea tu propio widget completamente usando Java
  • Entendiendo los layout: En esta entrada se exponen los contenedores de Widgets más utilizados.
  • Hoja de estilo: Del cómo se usan las Hojas de Estilo en Cascada en Google Web Toolkit
  • Atado de imágenes (imagen bundle): Optimiza el funcionamiento de tu aplicación reduciendo el número de peticiones HTTP al servidor

Ejemplos

GWT incluye una amplia colección de controles (widgets) que van desde los más simples (Labels, Button, etc) hasta algunos más complejos y no disponibles en HTML de forma directa (MenuBar , Tree y StackPanel). El modelo de eventos es similar al de Swing o SWT. Ejemplo muy básico:

Button button = new Button("Click me");
       final Label label = new Label();
       button.addClickListener() {
               public void onClick(Widget sender) {
               label.setText("Hola Mundo");
               }
       }

Antes de abordar un ejemplo debemos entender la estructura de directorio que exige GWT para nuestro proyecto.

Un proyecto GWT, a pesar de contener una aplicación web, se parece más a un proyecto Java que a un proyecto J2EE. GWT necesita ciertos ficheros adicionales y el seguimiento de una cierta nomenclatura en los paquetes.

En este ejemplo utilizaremos el nombre de paquete “com.sp.gwt”. La estructura entonces debe ser:

  • Src/
  • Src/com/sp/gwt/Ejemplo.gwt.xml : Descriptor de módulo

GWT basa sus aplicaciones en módulos , y cada módulo debe tener su fichero de configuración.

Similar al descriptor J2EE, en este fichero se declaran los servicios RCP que van a ser invocados desde el cliente así como los puntos de entrada a nuestra aplicación (entrypoints).

  • Src/com/sp/gwt/client/: Fuentes Java que serán compilados a Javascript
  • Src/com/sp/gwt/client/Ejemplo.java
  • Src/com/sp/gwt/server/: Fuentes de los servicios RPC del servidor (que se compilaran a .class)ç
  • Src/com/sp/gwt/public/: Recursos estáticos (imagenes , css, js, etc)
  • Src/com/sp/gwt/public/Ejemplo.html: Página contenedora

Al menos debe existir una pagina HTML que debe invocarse para lanzar la aplicación GWT.

  • bin/

Aquí están los .class resultado de compilar las clases java mediante el compilador javac

  • www/

Aquí va la aplicación lista para desplegar en un servidor web. Es decir aquí tenemos las clases cliente Javascript compiladas por el GWT. Aquí se copia la carpeta public.

Para probar la aplicación basta con abrir el fichero www/.../Ejemplo1.html en un navegador y estaremos ejecutando nuestra aplicación en el modo web. Todo el contenido de esta carpeta se puede ejecutar en un servidor web ya que todo es HTML, Javascript y XML

No obstante, no tenemos que crear todas esas carpetas, GWT trae una herramienta que las crea por nosotros “applicationCreator.cmd”

Tan solo creamos el directorio base de nuestro ejemplo e invocamos esta herramienta.

También se crean dos scripts:

Ejemplo1-compile.cmd : invoca al compilador GWT y genera código cliente en www

  • Abrimos Ejemplo.html en nuestro navegador

Ejemplo1-shell.cmd: con esto se ejecuta la aplicación en “hosted mode” mientras estemos desarrollando la aplicación.

Veamos que el fichero generado “Ejemplo.java” ya contiene el esqueleto suficiente para hacer un Hola mundo. Por lo que podemos lanzar los scripts anteriores y ver sus resultados:

package com.sp.gwt.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Ejemplo1 implements EntryPoint {
          /**
         * Se ejecuta cuando una página HTML declara el uso de un módulo GWT
          */
         public void onModuleLoad() {
                  final Button button = new Button("Click me");
                  final Label label = new Label();
                  button.addClickListener(new ClickListener() {
                            public void onClick(Widget sender) {
                                     if (label.getText().equals(""))
                                               label.setText("Hello World!");
                                     else
                                               label.setText("");
                            }
                  });
         // RootPanel nos permite acceder a los elementos HTML que tengamos en la pagina
         RootPanel.get("slot1").add(button);
         RootPanel.get("slot2").add(label);
         }
}

Ahora vemos el código html de “Ejemplo.html

<html>
       <head>
              <title>Ejemplo</title>
              <style>
                       body,td,a,div,.p{font-family:arial,sans-serif}
                       div,td{color:#000000}

                            a:link,.w,.w a:link{color:#0000cc}
                            a:visited{color:#551a8b}
                            a:active{color:#ff0000}
                  </style>
                  <meta name='gwt:module' content='com.sp.gwt.Ejemplo'>
         </head>
         <body>
<!-- Referencia al Javascript que se encarga de ejecutar el codigo del modulo que
declare la pagina.Ha sido creado por applicationCreator.cmd y no es necesario que
modifiquemos su contenido -->

        <script language="javascript" src="/servicios/madeja/gwt.js"></script>
        <iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
        <h1>Ejemplo1</h1>
        <p>Este es el ejemplo</p>

<!- Definimos una tabla con dos celdas a las que se llama slot1 (para el botón)
y slot2 (para la etiqueta).Estos son los contenedores donde ubicaremos los
controles de nuestra aplicación.-->

                  <table align=center>
                            <tr>
                                     <td id="slot1"></td>
                                     <td id="slot2"></td>
                            </tr>
                  </table>
         </body>
</html>

A continuación veremos un ejemplo un poco más complejo con interacción con el servidor.

En el ejemplo anterior todo se ejecuta en el lado cliente. Es más habitual aplicaciones web que manejan datos y ejecutan transacciones en el servidor.

A las operaciones en servidor se les llama “servicios”, pero no confundir con los servicios de la arquitectura SOA típicamente implementados con la tecnología Web Services.

Un servicio GWT es simplemente un servlet que recibe una petición http con una serie de parámetros y devuelve un resultado. En este caso todos los parámetros que recibe como el resultado son objetos serializados.

Otra diferencia importante es que el Servlet no devuelve una página HTML, sino que la respuesta es un documento XML con únicamente el objeto de respuesta serializado.

Ahora pasemos con el segundo ejemplo:

Siempre que creamos un servicio GWT crearemos dos interfaces y una clase.

En este ejemplo vamos a implementar un servicio de búsqueda de empleados. Dado un número de departamento nos devolverá los empleados de ese departamento.

El primer paso es poner un nombre al servicio: “SrvBusqueda”. Éste será el nombre de la primera interfaz necesaria que extenderá “com.google.gwt.user.client.rpc.RemoteService” y que declarará el método que realizará la operación de búsqueda. Este interfaz lo metemos en el paquete client.

Fichero: SrvBusqueda.java

package com.sp.gwt.client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface SrvBusqueda extends RemoteService {
         public Empleado[] buscarEmpleados (int nDpto);
}

En este ejemplo vamos a crear un Empleado que implementa isSerializable, (observe que los campos son de tipo String e int, con lo que cumple las reglas):

Empleado.java

package com.sp.gwt.client;
import com.google.gwt.user.client.rpc.IsSerializable;
public class Empleado implements IsSerializable {
         private String nombre = null;
         private String apellido = null;
         private int antiguedad = 0;
         public Empleado() {
                  super();
         }
         public Empleado(int antiguedad, String apellido, String nombre) {
                  super();
                  this.antiguedad = antiguedad;
                  this.apellido = apellido;
                  this.nombre = nombre;
  }
  public int getAntiguedad() { return antiguedad; }
  public void setAntiguedad(int antiguedad) { this.antiguedad = antiguedad; }
  public String getApellido() { return apellido; }
  public void setApellido(String apellido) { this.apellido = apellido; }
  public String getNombre() { return nombre; }
  public void setNombre(String nombre) { this.nombre = nombre; }
}

Ahora definimos la clase del lado del servidor que implemente dicha interfaz. Esta clase va a correr como un servlet dentro de un contenedor J2EE. Nuestra clase sólo se debe encargar de implementar el método buscarEmpleado() ya que del resto se encarga GWT.

SrvBusquedaImpl.java

package com.sp.gwt.server;
 import java.util.HashMap;
 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
 import com.sp.gwt.client.Empleado;
 import com.sp.gwt.client.SrvBusqueda;
public class SrvBusquedaImpl extends RemoteServiceServlet implements SrvBusqueda {
         static HashMap map = new HashMap();
         static {
                  map.put(new Integer(0), new Empleado[] {
                          new Empleado(2, "Manuel", "Rico"),
                          new Empleado(1, "Luis", "González"),
                          new Empleado(5, "Sonia", "Puentes"),
                  });
                  map.put(new Integer(1), new Empleado[] {
                          new Empleado(2, "Jorge", "de Andrés"),
                          new Empleado(1, "Óscar", "Rodríguez"),
                          new Empleado(3, "Jesús", "López"),
                  });

            map.put(new Integer(2), new Empleado[] {
                     new Empleado(6, "Natalia", "Ruiz"),
                     new Empleado(3, "Begoña", "Ferrer"),
                     new Empleado(2, "Antonio", "García"),
            });
            map.put(new Integer(3), new Empleado[] {
                     new Empleado(2, "Isabel", "Perez"),
                     new Empleado(8, "Luis", "Hernandez"),
                     new Empleado(5, "Francisco", "Soldado"),
            });
  }
  public Empleado[] buscarEmpleados(int nDepto) {
            Empleado[] lista=(Empleado[])map.get(new Integer(nDepto));
            if (null==lista) {
                     return new Empleado[]{};
            }
  return lista;
  }
}

Por último una clase del lado cliente que se va a utilizar para realizar la invocación de forma asíncrona desde el código cliente:

SrvBusquedaAsync.java

package com.sp.gwt.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface SrvBusquedaAsync {
         public void buscarEmpleados(int nDepto, AsyncCallback callback) ;
}

El nombre de esta interfaz debe ser idéntico al nombre de la interfaz principal del servicio añadiéndole el sufijo “Async”. Como vemos la firma del método “buscarEmpleados” es ligeramente distinta en la versión asíncrona , la transformación ha sido la siguiente:

  • Nombre del método el mismo
  • El tipo de retorno debe ser “void”
  • Los parámetros del método deben ser los mismos y en el mismo orden, pero hay que añadir al final un parámetro de tipo “AsynCallback”. Este objeto se encarga de recibir la respuesta de la invocación al servidor. En nuestro ejemplo devolverá un array de empleados.

Por último, veamos como invocar al servicio desde el cliente:

Cuando un usuario hace click en el botón de búsqueda se ejecutará el siguiente código:

Ejemplo2.java

package com.sp.gwt.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
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;
import com.google.gwt.user.client.ui.Widget;
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Ejemplo2 implements EntryPoint {
         private Grid tabla = null;
         /**
         * This is the entry point method.
         */
         public void onModuleLoad() {

final VerticalPanel panel = new VerticalPanel();
final TextBox txtDept = new TextBox();
panel.add(new Label("Número Departamento:"));
panel.add(txtDept);
final Button btnConsultar = new Button("Consultar");
btnConsultar.addClickListener(new ClickListener() {
         public void onClick(Widget sender) {
                   int nDepto = -1;
         try {
                   nDepto = Integer.parseInt(txtDept.getText());
         } catch (NumberFormatException e) {
                   mostrarError("Debe indicar un valor numérico como departamento");
                   txtDept.setText("");
                   return;
         }
//Creamos una instancia de la interface asincrona del servicio
SrvBusquedaAsync srvBusqueda = (SrvBusquedaAsync) GWT.create(SrvBusqueda.class);
//Indicamos la URI en la cual esta desplegado el servicio
ServiceDefTarget endpoint = (ServiceDefTarget) srvBusqueda;
endpoint.setServiceEntryPoint("/Ejemplo2/srvBusqueda");
//Creamos el objeto que gestionará el resultado de la invocación asíncrona
AsyncCallback callback = new AsyncCallback() {
         //La invocación al servicio ha sido correcta
         //Pinta el array de empleados con un Grid
         public void onSuccess(Object result) {
                   Empleado[] lista = (Empleado[]) result;
                   // eliminamos tabla con resultados anteriores
                   if (tabla != null) {
                             panel.remove(tabla);
                   }
                   tabla = new Grid(lista.length + 1, 3);
                   tabla.setWidth("450px");

                             tabla.setCellSpacing(0);
                             tabla.setCellPadding(2);
                             tabla.setStyleName("tabla");
                             // cabecera
                             tabla.setWidget(0, 0, new Label("Nombre"));
                             tabla.setWidget(0, 1, new Label("Apellido"));
                             tabla.setWidget(0, 2, new Label("Antiguedad"));
                             tabla.getRowFormatter().setStyleName(0,"tabla-filaCabecera");
                             // filas
                             for (int i = 0; i < lista.length; i++) {
                                        Empleado emp = lista[i];
                                        tabla.setWidget(i + 1, 0, new Label(emp.getNombre()));
                                        tabla.setWidget(i + 1, 1, new Label(emp.getApellido()));
                                        tabla.setWidget(i + 1, 2, new Label(""+ emp.getAntiguedad()));
                             }
                             // añadimos tabla
                             panel.add(tabla);
                   }
                   //La invocación al servicio ha fallado
                   public void onFailure(Throwable t) {
                             panel.add(new Label("Error: " + t.getMessage()));
                   }
          };
          //Invocación del servicio , como es una llamada asíncrona no bloquearemos la pantalla del usuario
          // durante la ejecución del servicio
          srvBusqueda.buscarEmpleados(nDepto, callback);
          }
  });
  panel.add(btnConsultar);
  panel.add(new Label("Resultados:"));
  RootPanel.get("panel1").add(panel);
}
private void mostrarError(String text) {
         final DialogBox popup = new DialogBox();
         popup.setText("Error");
         DockPanel dlgPanel = new DockPanel();
         dlgPanel.setSpacing(4);
         dlgPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
         dlgPanel.add(new Label(text), DockPanel.NORTH);
         dlgPanel.add(new Button("Cerrar",new ClickListener(){
                  public void onClick(Widget sender) {
                           popup.hide();
                  }}),DockPanel.SOUTH);
         popup.add(dlgPanel);
         popup.setPopupPosition(60, 60);
       popup.show();
    }
}