cerrar-sesion editar-perfil marker video calendario monitor periodico fax rss twitter facebook google-plus linkedin alarma circulo-derecha abajo derecha izquierda mover-vertical candado usuario email lupa exito mapa email2 telefono etiqueta

400440305. Una caja de herramientas web de Google propia

Escrito por Redacción en Secciones
no hay comentarios Haz tu comentario
Imagen de logotipo de facebook Imagen de logotipo de Twitter Imagen de Logotipo de Google+ Imagen de logotipo de Linkedin

La mayoría de los desarrolladores crean aplicaciones Ajax usando varios lenguajes diferentes en dos o más niveles. En el lado del cliente, tenemos desde luego HTML, además de algo de lógica escrita en JavaScript para realizar tareas tales como validación del lado del cliente y manipulación del modelo de objeto de documentos (DOM, por sus siglas en inglés) HTML. En el lado del servidor, podemos tener partes escritas en PHP, Perl, Java u otros lenguajes.

Por desgracia, ligeras diferencias de JavaScript entre los navegadores, junto con importantes diferencias en DOM, han conspirado para hacer que la escritura de este tipo de aplicación sea más difícil. Las bibliotecas del tipo Dojo y Prototype contribuyen a limar las aristas más ásperas, pero importantes aplicaciones web dinámicas siguen siendo mucho más difíciles de escribir que las aplicaciones tradicionales de sobremesa a las que se supone están reemplazando.

La caja de herramientas Google Web Toolkit (code.google.com/webtoolkit) es una plataforma Open Source de uso libre creada por Google para hacer que Ajax sea más fácil. En el presente artículo, vamos a presentar GWTFlow, un visualizador de fotos de mezcla que nos permite navegar por cualquier álbum de fotos Flickr. La IU se inspiró en el visualizador de álbumes Cover Flow de Apple (

Listado número 2

GWTFlow

Modo alojado frente a modo web

Mientras desarrollamos y depuramos la aplicación estaremos utilizando GWT en modo alojado. No obstante, cuando estemos en producción, la aplicación estará funcionando en modo web. Podemos pensar en el modo alojado como ruedas de entrenamiento para nuestro programa GWT. Es un entorno híbrido exclusivo para GWT que nos permite ejecutar y depurar el auténtico código Java, mientras seguimos dentro de un navegador.

La forma más sencilla de lanzar el modo alojado es ejecutar el fichero script creado por applicationCreator. En el ejemplo, hemos denominado “GWTFlow” al proyecto así que el script para ejecutar el modo alojado se denomina “GWTFlow-shell.” Esto hace aparecer el shell de desarrollo GWT, que a continuación inicia el programa en modo alojado dentro de un navegador web insertado.

O, al usar IDE para iniciar el shell, podemos establecer puntos críticos, examinar variables, y adentrarse en la aplicación en un solo paso igual que cualquier otro programa Java. Un buen plug-in (como el Diseñador GWT para Eclipse) puede facilitar esta tarea, además de ofrecer ventajas extra como la creación de interfaz de usuario WYSIWYG.

Después de haber depurado y comprobado las unidades del código, el paso siguiente es compilarlo en una forma que pueda ser ejecutada dentro de un navegador normal empleando para ello un script GWTFlow-compile o equivalente. El compilador GWT traduce el código del lado del cliente a JavaScript. Y a continuación combina nuestro código con una versión JavaScript de la API GWT en un gran fichero JavaScript, que cargamos en la página HTML anfitrión.

En realidad, crea varias versiones específicas para distintos navegadores y lenguajes. Por defecto, el código compilado de JavaScript es oscuro y está comprimido para hacer que cargue y funcione lo más rápido posible para los usuarios. No obstante, en el caso de que encontremos un fallo técnico que no pueda ser rastreado en modo alojado, podemos decirle a GWT que cree un JavaScript legible para los humanos que podemos depurar en modo web mediante una herramienta como FireBug ( www.ddj.com/development-tools/196802787).

Diseño de la Interfaz de Usuario

La IU de la aplicación muestra consiste en dos widgets (elementos IU) y un controlador principal. El primer widget, AlbumWidget, les permite a los usuarios seleccionar un servicio de imágenes, introducir su nombre de usuario, y seleccionar un álbum de fotos; véase las figuras 1 y 2. El segundo widget, ImageFlowWidget, muestra las fotos y permite la navegación a través del álbum.

El principal programa (GWTFlow.java) controla los dos widgets y mantiene el estado de la aplicación. Todos los widgets son añadidos y eliminados de forma dinámica del elemento de mantenimiento de sitio <div> que pusimos en la página HTML anfitrión.

AlbumWidget se construye usando un número de widgets más sencillos suministrados por GWT, como Button, Image, Label, RadioButton, y TextBox, que están ordenados en VerticalPanels y HorizontalPanels. (Para una mayor documentación sobre esto y otros temas, véase la referencia al final del presente artículo.)

La ventaja de usar los widgets y paneles que ofrece la caja de herramientas es que funcionan de la misma manera en todos los navegadores. Un ejemplo muy bueno es el selector desplegable para elegir la foto de la figura 2, que sería difícil de implementar en HTML tradicional, pero que en GWT es una sencilla tabla de Rejilla que se encuentra dentro de un ScrollPanel.

Lo que no quiere decir que todos los problemas entre navegadores van a desaparecer – nosotros experimentamos algunas peculiaridades con Internet Explorer y Safari – pero son bastante menos si los comparamos con el desarrollo tradicional Ajax.

Los usuarios pueden seleccionar un servicio de fotos y nombre de usuario.

Figura número 2

El Listado de álbumes se extrae del servidor y se muestra en una rejilla desplegable.

ImageFlowWidget extiende AbsolutePanel, lo que permite una posición y superposición absoluta de los widgets. Los widgets de imagen se sitúan en este panel y se escalan para simular perspectiva. La imagen principal siempre es la más grande y está situada en el centro de la ventana. Otras fotos se apilan debajo y su tamaño es cada vez más pequeño según se alejan del centro.

Cuando los navegadores muestran elementos colocados de forma absoluta, superponen los elementos que se añadieron después sobre los primeros. Así que necesitamos añadir imágenes del exterior (usando AbsolutePanel.add()), con la imagen principal al final.
Las posiciones de imagen, no obstante, se calculan desde dentro hacia fuera para evitar que las imágenes más pequeñas queden totalmente ocultas. El listado número 3 presenta el algoritmo para gestionarlo. Empezando por la imagen del centro, calcula primero el tamaño y la posición, recursa a la imagen vecina, invoca AbsolutePanel.add() y por último retorna al invocador.

Listado número 3

private void calcImagePosition(int imageIdx, int()() whlt, int offsetWidth,

int offsetHeight, boolean addToPanel, boolean animateAdd)

if (imageIdx < 0 || imageIdx >= images.length)

return; // Stopping recursion once we reach the first or last image

// Calculating image's width/height based on its distance from center.

int distFromCenter = Math.abs(selIdx - imageIdx);

int maxWidth = (int)((offsetWidth*.6)/(distFromCenter+1));

int maxHeight = (int)((offsetHeight*.6)/(distFromCenter+1));

int() wh = scaleImage(dtos(imageIdx).width, dtos (imageIdx).height,

maxWidth, maxHeight);

int width = wh(0);

int height = wh(1);

// Calculating image's top position so it's always centered on viewport

int top = (offsetHeight / 2) - (height / 2);

// Calculating image's left position so 45% of its width pokes out

int left;

if (imageIdx < selIdx)

int xDiff = (int)(width*.45);

left = whlt(imageIdx+1)(LEFT) - xDiff;

else if (imageIdx > selIdx)

int xDiff = (int)(width*.55);

left = whltimageIdx-1](LEFT) + whlt[imageIdx-1](WIDTH) - xDiff;

else // centering middle image

left = (getOffsetWidth() / 2) - (width / 2);

whlt(imageIdx) = new int() width, height, left, top ;

// Recursive calls to calc positions for images on the left and/or right

if (imageIdx <= selIdx)

calcImagePosition(imageIdx-1, whlt, offsetWidth, offsetHeight,

addToPanel, animateAdd);

if (imageIdx >= selIdx)

calcImagePosition(imageIdx+1, whlt, offsetWidth, offsetHeight,

addToPanel, animateAdd);

// Adding images to the panel. This happens on the initial load and on

// window resize events. If the user is just clicking between images,

// they are already on the panel so we don't need to add them.

if (addToPanel)

images(imageIdx).setWidth(width + "px");

images(imageIdx).setHeight(height + "px");

// The first time we load, we'll use the Scriptaculous grow effect

// for any images that are in the viewport.

if (animateAdd && inViewport(left, images(imageIdx).getWidth()))

images(imageIdx).setVisible(false);

images(imageIdx).addLoadListener(new LoadListener()

public void onLoad(Widget sender)

Effect.grow(sender, new EffectOption()

new EffectOption("duration", LOAD_DURATION));

public void onError(Widget sender)

showErrorMessage();

);

// Last added are on top, so we add from the outside in.

this.add(images(imageIdx), left, top);

Animación

GWT no ofrece actualmente una animación o biblioteca de efectos incorporada (aunque los desarrolladores están trabajando en ello para un próximo lanzamiento. En lugar de eso, necesitamos invocar a una biblioteca JavaScript como Script.aculo.us (script.aculo.us), YUI (developer.yahoo.com/yui), o Rico (openrico.org).

Para GWTFlow, hemos elegido la clase Effect de la Biblioteca de Widgets GWT Open Source. Al usar la Interfaz Nativa JavaScript de GWT (JSNI), envuelve la biblioteca de efectos Script.aculo.us, proporcionando así animación para efectos de movimiento, escalado y difuminado.

Cuando los usuarios navegan a una nueva imagen, GWTFlow vuelve a calcular las nuevas imágenes y tamaños, invoca Effect.move() y Effect.scale() (proporcionados por la Biblioteca de Widgets GWT), y deja que Script.aculo.us ejercite su magia. El listado número 4 presenta el método invocado para animar el movimiento de imágenes.

//Listado número 4

private void animateMove(Widget widget, int left, int top, double dur)

Effect.move(widget, new EffectOption() new EffectOption("mode", "absolute"),

new EffectOption("x", left), new EffectOption("y", top),

new EffectOption("duration", dur) );

Obtención de datos desde Flickr

Cuando los usuarios introducen un nombre de usuario y pinchan en el botón de “continuar”, necesitamos extraer el listado de imágenes y álbumes desde el servidor. Flickr ofrece acceso a sus datos mediante una API de servicios web amplia ([http://www.flickr.com/services/api). Hemos creado un servicio proxy para suministrar estos datos mediante la funcionalidad Remote Procedure Call (RPC) de GWT (Figura 3).

Figura 3

ImageService actúa como proxy entre el cliente y Flickr.

Los servicios RPC en GWT se extienden de la API Servlet de JAVA, con rellamadas incorporadas definidas para hacer todo asíncrono. Los objetos devueltos son POJOs (Plain Old Java Objects) serializables, que utilizamos para almacenar metadatos de imágenes y álbumes.

Las auténticas invocaciones a Flickr se hacen en ImageService.java utilizando Flickrj, una biblioteca Open Source de Javaque envuelve la API basada en REST de Flickr (flickrj.sourceforge.net ). El listado número 5 muestra el código para buscar usuarios, obtener una lista de sus conjuntos de fotos, y transformar el listado en una matriz de objetos ligeros para la transferencia de datos de álbumes.

Listado número 5

public AlbumDTO() getFlickrAlbums(String username) throws IOException,

SAXException, FlickrException

Flickr flickr = FlickrUtil.getInstance(); // Access Flickr using API key

PeopleInterface people = flickr.getPeopleInterface();

User user = people.findByUsername(username);

PhotosetsInterface photoSets = flickr.getPhotosetsInterface();

Collection sets = photoSets.getList(user.getId()).getPhotosets();

AlbumDTO() albums = new AlbumDTO(sets.size());

Iterator iter = sets.iterator();

for (int i = 0; i < albums.length; i++)

Photoset set = (Photoset) iter.next();

albums(i) = new AlbumDTO(); // Custom POJO w/Album metadata

albums(i).id = set.getId();

albums(i).name = set.getTitle();

albums(i).description = set.getDescription();

albums(i).imageCount = set.getPhotoCount();

albums(i).smallSquareUrl = set.getPrimaryPhoto().getSmallSquareUrl();

return albums;

Como en cualquier aplicación Ajax, la capacidad de respuesta del lado del cliente es asunto fundamental. Un servicio RPC nos permite minimizar los datos enviados por cable y usar la capacidad de procesado del servidor para extraer información de imágenes. También permite una API claramente definida que pueda ser ampliada para soportar otros proveedores de imágenes, como los Picasa Web Albums de Google.

No obstante, los servicios RPC normalmente requieren un motor servlet como Tomcat o Jboss, lo que añade complejidad al desarrollo y limita el número de proveedores de alojamiento. Una alternativa que tuvimos en mente fue JSON (JavaScript Object Notation), un formato de intercambio de datos con soporte para solicitudes de servicios web JavaScript nativos.

Las alimentaciones de datos JSON están soportadas por una variedad de proveedores, entre los que se incluye Flickr y algunos servicios Google (aunque no Picasa). Al final, descartamos JSON, y nos decantamos por RPC por su rendimiento, facilidad de depurado y de mantenimiento del código.

Encajar y limpiar

Soporte para el historial del navegador ha sido siempre problemático en las aplicaciones web, especialmente en el mundo Ajax (“por favor usen mi flecha especial anterior, no la grande en la que se pincha en todos los demás sitios”). Afortunadamente, GWT permite una integración fácil con el historial del navegador. Según van navegando los usuarios por sus dibujos, GWTFlow empuja las entradas en la pila del historial del navegador.

Al implementar HistoryListener en el controlador GWTFlow.java, la aplicación recibe notificación de los eventos del historial. Ello les permite a los usuarios navegar por la aplicación como por un sitio web tradicional: Al apretar el botón de atrás se muestra la imagen anterior o la pantalla de diálogo, no el sitio web anterior.

Como la URL cambia en la barra del navegador, un buen efecto secundario es que el soporte de marcado de páginas es gratis. Los usuarios que retornan al sitio verán exactamente el mismo estado de la aplicación que cuando lo marcaron con marcapáginas. La figura 4 es la aplicación completada.

Figura 4

Se pueden ver unas cuantas imágenes antes y después de la actual. Podemos pinchar en cualquier imagen para moverla o apretar el botón de Retroceso del navegador para volver a la última imagen seleccionada.

Conclusión

JavaScript es el nuevo lenguaje de Ensamblado. La caja de herramientas web de Google nos permite crear programas Ajax en Java y compilarlos en un JavaScript para un navegador específico, ocultando la mayoría de las peculiaridades del navegador que complican de forma innecesaria el desarrollo Ajax.

Al usar GWT podemos crear unas aplicaciones muy interactivas que funcionan en todos los navegadores más importantes sin necesidad de plug-ins. Lo que es más importante, podemos hacerlo con un lenguaje portátil, orientado al objeto y unas herramientas maduras que ya conocemos.

Referencias

Hay una demostración en vivo de GWTFlow y su código fuente en: www.adamhoughton.com/GWTFlow. Aquí tenemos unos cuantos recursos para aprender más cosas sobre GWT:
– La página de inicio de GWT se encuentra en: code.google.com/webtoolkit.
– El blog del equipo GWT está disponible en: googlewebtoolkit.blogspot.com.
– El Foro GWT se encuentra en: groups.google.com/group/Google-Web-Toolkit.
– La Biblioteca de Widgets GWT se encuentra en: gwt-widget.sourceforge.net.
– El libro de Ed Google Web Toolkit: Taking the Pain Out of Ajax está disponible en: pragmaticprogrammer.com/titles/ebgwt.
– El libro de Robert Hanson y de Adam Tacy “ GWT in Action” se encuentra disponible en (www.manning.com/hanson)->http://www.manning.com/hanson].
– El Diseñador GWT está en: www.instantiations.com/gwtdesigner.

DDJ

Etiquetas

Noticias relacionadas

Comentarios

No hay comentarios.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Debes haber iniciado sesión para comentar una noticia.