viernes, 24 de febrero de 2012

Compilando una aplicación GWT

Modo de Producción

Si ha completado con éxito las pruebas de la aplicación en modo de desarrollo, proceda a compilarla para generar el código JavaScript, genere un Web Archive (WAR) e instálelo en el servidor web  de su preferencia. La aplicación se ejecutará en modo de producción y será equivalente al modo de desarrollo. Es posible que encuentre algunas fallas que no se presentaron en modo de desarrollo, pero no es frecuente que esto suceda.

Ejecutar su aplicación en modo de producción permite probar la aplicación como si ya hubiese sido instalada en el servidor web final. Puede realizar pruebas desde diferentes navegadores apuntando al URL en donde reside su aplicación en el computador en donde instaló su servidor web de pruebas.

Desempeño de la aplicación (performance)

El modo de desarrollo de GWT utiliza un motor (engine) especial para ejecutar la aplicación como una mezcla de bytecode de Java y JavaScript, por esta razón la ejecución se notará más lenta a como se ejecuta en modo de producción. Aunque habrá ocasiones en las que complejos algoritmos escritos en Java se ejecutarán mucho más rápido en modo de desarrollo dado que el JVM supera a la mayoría de los motores de JavaScript.

Sin embargo, cuando la aplicación despliega grandes cantidades de datos en un número considerable de Widgets, podrá confirmar que el desempeño será mucho mejor cuando la aplicación haya sido instalada en un servidor web.

Desempeño de la aplicación

GWT ha sido diseñado para proveer soporte en múltiples navegadores, de tal manera que el promedio de los desarrolladores no deben preocuparse por cómo acondicionar la aplicación a cada navegador. Pero si crea nuevos Widgets o si utiliza librerías JavaScript de terceros, debe confirmar que estos componentes operan correctamente en cada navegador en donde se ejecutará la aplicación.

Apariencia en diferentes navegadores

Como los Widgets de GWT usan los componentes nativos DOM de cada navegador, la apariencia de la aplicación puede cambiar de un navegador a otro. Cuando utilice una hoja de estilos (stylesheet) verifique que este estilo funciona correctamente en cada navegador.

Compilador GWT

El compilador es el corazón de GWT, convierte código fuente Java en JavaScript. Soporta la gran mayoría del lenguaje Java. La librería de ejecución GWT (GWT runtime library) emula un subconjunto relevante de la librería de ejecución Java (Java runtime library). Cuando una clase de JRE o un método no es soportado, el compilador emitirá un error.

El compilador puede ser ejecutado desde la línea de comando del sistema operativo, pero en este caso continuaremos utilizando las bondades de Eclipse Helios.

Utilizaremos como ejemplo el proyecto creado en el blog Instalando Eclipse y GWT.

Para compilar una aplicación, simplemente abra Eclipse, seleccione el proyecto que va a compilar y desde la barra de comandos seleccione el icono de GWT y luego la opción GWT Compile Project:


El compilador mostrará las siguientes opciones de compilación:



Analicemos estas opciones:

Project

Confirme el nombre del proyecto que va a compilar.

Log Level

Define el  nivel de detalle de los mensajes que aparecerán en el log de la aplicación. Seleccione una de las siguientes: Error, Warn, Info, Trace, Debug, Spam, All.

Output Style

Define el estilo de presentación en el que será generado del código JavaScript. Obfuscated es el estilo que hace que el código JavaScript luzca como una sopa de letras, el código está comprimido y es muy complicado descifrarlo. Además, ayuda a proteger la propiedad intelectual de su aplicación y reduce el tamaño de los archivos JavaScript convirtiéndose en una ventaja cuando el código deba transportarse del servidor web al navegador del cliente. Pretty genera un código JavaScript mucho más claro y entendible. Detailed mejora la versión Pretty y produce más detalles del código.

Intente probar estos estilos de compilación como ejercicio de comparación del código JavaScript generado.

Entry Point Moules

GWT identificará el punto de entrada (entry point) de su proyecto. Sin embargo verifique que el que aparece en esta ventana de opciones es el mismo que se ha definido en el archivo descriptor.

Cuando haya identificado estas opciones, de click en Compile.

Observe los mensajes que aparecen en la vista Console de Eclipse:



Desde el explorador de proyectos de Eclipse, abra el proyecto ejemplo1, abra el directorio war y luego el directorio ejemplo1. Observe los archivos que se han generado allí como producto del proceso de compilación. El número de archivos HTML corresponde al número de permutaciones hechas por el compilador (ver vista Console de Eclipse).



Abra uno de estos archivos HTML para observar el código JavaScript generado. Compile de nuevo el proyecto cambiando una de las opciones de Output Style y revise el nuevo código JavaScript para que observe las diferencias. Cuando vaya a compilar la aplicación para ser instalada en un servidor web, es recomendable que genere el código en estilo Obfuscated para que los archivos sean más compactos y sean de difícil interpretación para quienes intenten copiar el código sin autorización.

Analicemos algunos de los archivos creados por el compilador GWT:

Ejemplo1.html

Es la página principal de la aplicación (host page) y la que los visitantes a su servidor web podrán ver primero. En esta página serán cargados el resto de los archivos de la aplicación. El archivo HTML debe contener una etiqueta <script> en donde se referencia el archivo de arranque (bootstrap):

<script type="text/javascript" language="javascript"
      src="ejemplo1/ejemplo1.nocache.js"></script>

Archivo de arranque (bootstrap) ejemplo1.nocache.js

Este archivo es responsable de seleccionar la correcta versión de su aplicación para ser cargada por el cliente dependiendo del navegador y los parámetros de ubicación (locale).

Archivos de la aplicación (.cache.html)

Es el conjunto de archivos generados más importantes. Representan una versión de su aplicación ajustada a un navegador específico. Estos archivos son seleccionados por el archivo de arranque (bootstrap) después que ha identificado el navegador desde el cual se está ejecutando la aplicación.

Archivo RPC (.gwt.rpc)

Este archivo es requerido si se está utilizando RPC en la aplicación. Soporta la interface de serialización para tipos de datos transferidos a través de RPC.

Recursos Públicos

Todos los recursos públicos tales como archivos de imágenes, estilos, o archivos XML pueden ubicarse en cualquier parte dentro del subdirectorio war

lunes, 20 de febrero de 2012

Depurando una aplicación GWT

Modos de ejecución

Hay dos modos de ejecución de una aplicación GWT. El primer modo se denomina Modo de Desarrollo (Development Mode), el cual se realiza utilizando las bondades de un IDE (Integrated Development Environment) o directamente desde la línea de comando de su sistema operativo. En este blog utilizaremos Eclipse Helios. En versiones iniciales de GWT, el modo de desarrollo se conocía como Modo Hospedado (hosted mode) y proporcionaba algunas herramientas adicionales que permitía probar la aplicación desde un navegador hecho exclusivamente para este propósito. En las versiones recientes de GWT las aplicaciones pueden ser probadas desde el navegador de su preferencia.

El segundo modo se denomina Modo de Producción (Production Mode) anteriormente llamado Modo Web (web mode). En este modo el código Java será compilado y traducido a JavaScript y la aplicación GWT se ejecutará de la misma manera como se ejecuta cuando ha sido instalada en un servidor web,

Depurando en Modo de Desarrollo

Una aplicación GWT puede ser ejecutada en modo de desarrollo desde un IDE. Los programas Java son compilados a bytecode de Java y los componentes son desplegados en un navegador a través de los mecanismos provistos por GWT. Por lo tanto, las facilidades de depuración (debugging) del IDE están disponibles para depurar tanto las aplicaciones cliente como servidor.

Como ya se explicó en el blog Ejecutando una aplicación GWT, para ejecutar su aplicación abra Eclipse, de click en el botón derecho del ratón y desde el menú de opciones seleccione Run As --> Web Application. Otra manera de ejecutar la aplicación es seleccionando el proyecto y desde el menú principal seleccione las opciones Run --> Run As --> Web Application. Copie el URL que aparece en la vista de tareas de Eclipse y cópielo en el navegador para probar la aplicación.

Este proceso lo realizará infinitas veces hasta que su aplicación este completada y suficientemente probada para ser puesta en producción.

Sin embargo, en ocasiones es necesario detener la aplicación en algún lugar determinado, en donde se está presentando un error o en donde la aplicación se comporta de manera distinta a lo esperado. Bien, aquí debemos depurar o en inglés debug. Desde Eclipse abra su proyecto, de click sobre el botón derecho del ratón, seleccione Debug As --> Web Application. La aplicación se ejecutará de manera similar a como si se hubiera ejecutado seleccionando Run As --> Web Application.

También puede iniciar la depuración desde el menú principal, Run --> Debug As --> Web Application, o simplemente dando click al ícono con figura de escarabajo o insecto (bug) de la barra de comandos de Eclipse.

Para detener la ejecución en un lugar específico, ubique la línea en donde va a detener la ejecución y en la barra izquierda del editor de doble click.




Una pequeña esfera aparecerá allí indicando el lugar en donde la ejecución se detendrá. Esto se conoce como un breakpoint o punto de ruptura.

Ejecute nuevamente la aplicación en modo depuración, copie el URL de la vista Development Mode de Eclipse y péguelo en el navegador para probar la aplicación. Eclipse mostrará un mensaje advirtiendo que la perspectiva de Eclipse cambiará para mostrar las vistas que despliegan información relacionada con la depuración de la aplicación:


Click en Yes.



La ejecución de la aplicación se detendrá en la línea en donde se definió el breakpoint.

Observe las vistas adicionales que Eclipse ofrece.

La vista Debug muestra la clase y el método en donde la aplicación se ha detenido.

La vista Variables muestra el estado de cada variable hasta ahora puestas en memoria. Aquí puede consultar el valor de cada una.

La vista con el código Java de la aplicación muestra la línea en donde se ha detenido.

La vista outline es una referencia para indicar la posición de la ruptura del programa dentro de todo el proyecto.

La vista Console, en la parte inferior de Eclipse, hace parte de las vistas de tareas. Aquí puede ver salidas o mensajes que el programador ha puesto directamente dentro del programa. Por ejemplo, la salida del método System.out.println o los mensajes enviados utilizando la utilidad GWT.log.

Para continuar con la ejecución utilice las opciones disponibles para debugging que Eclipse ofrece. Vaya al menú principal, seleccione Run y una de las opciones disponibles:



Puede continuar la ejecución del programa línea por línea pulsando F5, o si ha puesto varios breakpoints dentro de su programa, pulse F8 para que la ejecución continúe y se detenga en el próximo breakpoint.

Para retornar a la perspectiva del ambiente de desarrollo de Java de Eclipse, vaya a la parte superior derecha de Eclipse y de click sobre el ícono Java:



Refrescando el Modo de Desarrollo

Puede realizar cambios en el código de la aplicación y reiniciar la ejecución. No es necesario que termine o detenga completamente la ejecución, puede simplemente refrescar el navegador para que el nuevo código cargue y se ejecute.

Si ha modificado aplicaciones del servidor, es conveniente que reinicie el servidor Jetty que viene integrado a Eclipse. Simplemente de un click sobre el ícono de flechas amarillas de la vista Development Mode:


Mensajes de Depuración con GWT.log

GWT provee una utilidad para generar mensajes desde su programa a la vista Development Mode de Eclipse. Haciendo llamados al método GWT.log() podrá generar mensajes de depuración que le indicarán el sitio y el estado de su aplicación.

Por ejemplo inserte un par de líneas con llamados a GWT.log:

      public void onModuleLoad() {
            GWT.log("Comenzando la ejecucion de la aplicacion...", null);
            final Button sendButton = new Button("Enviar");
            final TextBox nameField = new TextBox();
            nameField.setText("Usuario GWT");
            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
            GWT.log("Obteniendo elementos de la pagina web", null);
            RootPanel.get("nameFieldContainer").add(nameField);
            RootPanel.get("sendButtonContainer").add(sendButton);
            RootPanel.get("errorLabelContainer").add(errorLabel);

 Salve la aplicación, refresque el navegador y observe los mensajes que aparecen en la vista Development Mode de Eclipse:


Los mensajes enviados desde GWT.log se mezclan son los mensajes generados por GWT. A medida que la aplicación se vuelva más compleja, inserte en el mensaje la ubicación en donde éste se genera, por ejemplo:

GWT.log("Ejemplo1:onModuleLoad():Comenzando la ejecucion de la aplicacion...", null);

De ese modo podrá identificar sus propios mensajes y rastrear fácilmente el flujo de la aplicación.

También puede utilizar la salida estándar más popular de Java: System.out.println. Como ejercicio inserte una línea con algún mensaje que facilite la depuración y observe la salida del mensaje en la vista Console.

viernes, 3 de febrero de 2012

Estructura de un Proyecto GWT

Prerequisitos

Antes de entrar a detallar la composición de un proyecto GWT, es conveniente saber el significado de módulo.

Módulo (Module)

Un módulo GWT es simplemente una encapsulación de funcionalidad. El concepto comparte algún parecido a un paquete Java (Java package) pero no es la misma cosa. Se nombran del mismo modo separando los nombres de los subdirectorios o subcarpetas con punto. Por ejemplo, la mayoría de los módulos estándar de GWT están subordinados a com.google.gwt. 


Modulo
Contenido
com.google.gwt.user.User
Núcleo de la funcionalidad de GWT; requerido en cada proyecto
com.google.gwt.http.HTTP
Librería de comunicaciones HTTP de bajo nivel
com.google.gwt.i18n.I18N
Soporte para internacionalización
com.google.gwt.json.JSON
Creación e interpretación de estructuras JSON
com.google.gwt.junit.JUnit
Framework para pruebas e integración JUnit
com.google.gwt.xml.XML
Creación e interpretación de documentos XML

Un módulo es definido por un archivo descriptor XML terminado con la extensión .gwt.xml. El nombre de este archivo determina el nombre del módulo. En nuestro ejemplo, creamos un proyecto llamado ejemplo1. Internamente GWT crea el descriptor src/com/gwt/ejemplo1/Ejemplo1.gwt.xml, creando a su vez el módulo com.gwt.ejemplo1. El contenido del archivo .gwt.xml especifica una lista precisa de las clases Java y otros recursos que son incluidas en el módulo GWT.

En otras palabras, un módulo GWT agrupa todas las propiedades de configuración que su proyecto necesita, entre ellas podemos destacar las siguientes:

·         Lista de módulos heredados. Por ejemplo, com.google.gwt.user.User debe estar definido en cada módulo, por ser el núcleo de GWT.
·         El nombre de la clase Java que se utilizará como punto de entrada (entry point). Esta es la clase que se instanciará al comienzo, invocando el método EntryPoint.onModuleLoad(), cuando el módulo sea cargado.
·         Ubicación de los subpaquetes fuentes a ser compilados y traducidos a JavaScript.
·         Ubicación de los subpaquetes públicos a ser compilados y traducidos a Javscript. Aquí debe incluirse el URL completo de la ubicación de estos subpaquetes.
·         Además, puede agregar propiedades adicionales para la compilación y traducción de los fuentes en Javascript.


Estructura de un Proyecto GWT

Tomando como referencia el proyecto ejemplo1 creado en el blog anterior, observamos que hay cinco grandes elementos definidos allí. Los dos primeros corresponden a carpetas de programas fuentes, los dos siguientes son contenedores de librerías y el último elemento corresponde a la carpeta que incluirá la aplicación web cuando esté lista para ser puesta en producción.

Cuando creamos este proyecto, en el asistente seleccionamos la opción Sample Code (código ejemplo), por esta razón, el proyecto contiene archivos adicionales a los que inicialmente teníamos previstos. El asistente ha creado aplicaciones tanto para el lado del cliente como del servidor. Más adelante revisaremos esta funcionalidad basada en RPC. Por ahora revisemos la estructura creada por el asistente:

Paquetes para código fuente:
Paquete
Propósito
com.gwt.ejemplo1
Paquete raíz del proyecto. Contiene el archivo descriptor XML:Ejemplo1.gwt.xml.
com.gwt.ejemplo1.client
Archivos fuentes y subpaquetes del lado del cliente: Ejemplo1.java, GreetingService.java y GreetingServiceAsync.java
com.gwt.ejemplo1.server
Archivos fuentes y subpaquetes del lado del servidor: GreetingServiceImpl.java
com.gwt.ejemplo1.shared
Recursos que pueden ser compartidos tanto del lado del cliente como del servidor

Paquete para aplicaciones de prueba:
Paquete
Propósito
com.gwt.ejemplo1
Paquete vacío en el cual podrá crear aplicaciones para probar sus aplicaciones del proyecto.

Librerías del SDK (Software Development Kit) de GWT
Librería
Propósito
gwt-user.jar
Contiene la gran mayoría de fuentes Java que componen GWT. Incluye  las clases que generalmente utilizamos en nuestro propio código. Por ejemplo todas las clases de widgets (componentes gráficos), animación, manejo de eventos, etc.
gwt-dev.jar
Contiene clases que soportan la ejecución del proyecto en modo de desarrollo (development mode)
validation-api-1.0.0.GA-sources.jar
Contiene los fuentes Java de un sistema de validación para la integración entre cliente y servidor
validation-api-1.0.0.GA.jar
Contiene las clases Java de un sistema de validación para la integración entre cliente y servidor

Librerías del sistema JRE (Java Runtime Environment)
Librería
Propósito
resources.jar
Clases JRE de propósito general para la ejecución de clases Java
rt.jar
Runtime clases Java
jsse.jar
Clases para seguridad de sockets (Java Secure Socket Extension)
jce.jar
Clases para codificación (Java Cryptography Extension)
charsets.jar
Clases para conversión de caracteres
dnsns.jar
Clases para representar direcciones IP.
dns_sd.jar
Clases para DNS auto descubrimiento (DNS Self Discovery)
localedata.jar
Clases para localización, tales como formatos de fechas, números, moneda, zona horaria, etc.
sunjce_provider.jar
Clases para codificación (Java Cryptography APIs)

Web Archive (war)
Archivo
Propósito
war/WEB-INF/lib/gwt-servlet.jar
Provee en el lado de el servidor las clases requeridas para implementar los mecanismos de GWT RPC (Remote Procedure Call)
war/WEB-INF/web.xml
Archivo de configuración de Servlets
war/Ejemplo1.css
Archivo de definición de estilos. (Cascading Style Sheets)
war/Ejemplo1.html
Archivo HTML en el cual la aplicación GWT será cargada.


Archivos del Proyecto GWT

Ejemplo1.gwt.xml

Abra este archivo en Eclipse y revise su contenido. Como ya vimos, este es el archivo descriptor, un documento XML que contiene propiedades especificas para este proyecto. Hereda paquetes GWT como com.google.gwt.user.User:

<inherits name='com.google.gwt.user.User' />

Define también las clases que se utilizarán para definir el tema de composición en CSS (Cascading Style Sheets). El asistente deja disponible la clase:

<inherits name='com.google.gwt.user.theme.clean.Clean' />

Como ejercicio puede volver esta linea un comentario y habiliar alguna de last res opciones adicionales que contiene este archivo descriptor:

    <!-- <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'/> -->

El punto de entrada (entry point), indica la clase Java que se instanciará cuando se ejecute el proyecto:

    <!-- Specify the app entry point class. -->
    <entry-point class='com.gwt.ejemplo1.client.Ejemplo1' />

El archivo descriptor también especifica la ubicación de los archivos fuentes de Java que se compilarán y se traducirán en Javascript:

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

¿Por qué no se incluye aquí los archivos Fuentes para el servidor? La respuesta es porque las aplicaciones del servidor se ejecutan como clases de Java y no como Javascript.



Ejemplo1.java

Este es el archivo principal de su proyecto. Aquí se alojarán los componentes que se desplegarán en la página web.

Contiene el método onModuleLoad() el cual es el primer método a ejecutarse cuando se instancia esta clase. Desde este punto comienza a tener vida su aplicación.


GreetingService.java

Esta interface hace parte de la implementación RPC que hará posible el diálogo entre el cliente y el servidor. Extiende RemoteService de GWT y define la lista de los métodos RPC que tendrán una implementación en el servidor.

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
      String greetServer(String name) throws IllegalArgumentException;
}


GreetingsServiceAsync.java

Esta es una interface asincrónica del servicio creado en GreetingService y es invocada desde el lado del cliente.

public interface GreetingServiceAsync {
      void greetServer(String input, AsyncCallback<String> callback)
                  throws IllegalArgumentException;
}

Observe que esta interface contiene un método con el mismo nombre dado en GreetingService.java. La diferencia radica en los parámetros dados. El parámetro de tipo AsyncCallback nos ayudará a implementar el servicio bajo las características de AJAX. Se hace el llamado al servicio y la ejecución de la aplicación no se detiene a esperar una respuesta. La ejecución continúa y el resultado se procesa tan pronto como llegue de regreso del servidor. Por esta razón se denomina un servicio asincrónico.


GreetingServiceImpl.java

Esta clase define el servicio RPC en si. Extiende RemoteServiceServlet e implementa la interface asociada que define los servicios.  Observe que la implementación del servicio no se hace sobre la versión asincrónica de la interface:

.
.              
public String greetServer(String input) throws IllegalArgumentException {
.
.

¿Cómo determinar esto? Bueno, observe los parámetros de los métodos. La implementación del método greetServer(String input) corresponde al método definido en la interface GreetingService.java.

En realidad esta clase es un Java Servlet, que no extiende la típica clase HTTPServlet que se encarga de entablar un diálogo cliente-servidor utilizando el protocolo HTTP, sino que extiende la clase GWT RemoteServiceServlet, que realiza una serialización automática de los datos transmitidos entre el cliente y el servidor e invoca el método correspondiente en la implementación de este servicio.

Cabe destacar que esta clase residirá en el lado del cliente.


FieldVerifier.java

Esta clase hace parte del paquete com.gwt.ejemplo1.shared. Es una clase que puede ser compartida entre el cliente y el servidor. Normalmente aquí se crean clases que se utilizarán como herramientas o utilitarios para soportar el proceso general del proyecto. Rutinas de validación, rutinas para realizar cálculos, para manipular cadenas de caracteres, etc., son  implementadas aquí.


Ejemplo1.css

Define  los estilos utilizados para personalizar los componentes de la página web. Aquí puede definir  estilos propios  dando rienda suelta a su creatividad si tiene buenos conocimientos de CSS.


Ejemplo1.html

Esta es la página principal del proyecto. Es la página que se invoca cuando se ejecuta su aplicación.  Ya hemos visto como modificar este archivo  en el blog anterior Ejecutando una Aplicación GWT.


Autor de El Efecto Margarita