CEIBO

Domingo 15/Junio/2008

Juego de Cartas Web 2.0 ¡En linea!

Archivado en: General — Hernan Galante @ 11:54 pm

Estas son algunos de los screenshots que hemos tomado del juego de cartas. Está en línea en este URL. Obviamente, esta en una fase de prueba y puede presentar alguna inestabilidad a corregir. A continuación presentamos algunos ScreenShots del mismo:

Carga del Juego de Cartas
Fig 1. Carga del juego de Cartas

Login del Juego de Cartas
Fig. 2 Login del Juego de Cartas

Registro de usuario
Fig. 3 Registro de nuevo usuario

Configuración del avatar
Fig. 4 Configuración del avatar

Configuración del pelo del avatar
Fig. 5 Configuración del pelo del avatar

Bienvenida al Juego
Fig. 6 Bienvenida al Juego

Jugando entre dos participantes
Fig. 7 Jugando entre dos participantes un juego de Solitario

Participante entrante al juego compartido saludando al oponente 
Fig. 8 Participante entrante al juego compartido saludando al oponente

Hasta aquí hemos presentado unas imágenes del juego que está en versión beta. Aún, por ejemplo, no se ha implementado la persistencia, por lo cual, la registración del juego está en memoria. En caso de reiniciar el servidor, las registraciones se perderían por el momento.

¡Espero que os guste!

Eligiendo la persistencia adecuada

Archivado en: General — Hernan Galante @ 11:53 pm

En casi todos los proyectos de software tradicional una de las primeras estructuras que se eligen es la base de datos. Se elige en que motor va a guardarse los datos, antes de saber de que datos hablamos, cantidad, volumen y si la solución adecuada es apropiada. Muchas herramientas de programación incluso, no permiten o no dan soporte prácticamente para trabajar con otra alternativa.
En los proyectos Smalltalk en general, la persistencia, es una de las últimas cosas que se plantean y estudian.

¿Porqué estudiar la persistencia a último momento?

Esta pregunta es interesante contestarla para quienes estén familiarizados con la acción inversa. Todos sabemos que en un proyecto orientado a objetos, el uso de una base de datos puede ser una tarea compleja. Para hacer una analogía, sería como pensar que cada vez que guardamos nuestro vehículo en nuestra cochera, de ante mano debemos desarmarlo hasta los tornillos para poder guardarlo. Y para volver a usarlo como tal, debemos rearmarlo nuevamente. Por lo que podemos deducir claramente que no es natural esta táctica. Alguien le puso un nombre en inglés a esto como “impedance mismatch”. Podría traducirse como “acople de impedancia”, pero a efectos de nuestro objetivo no tiene más significado de que estamos conectando dos tecnologías incompatibles. Para compatibilizarlas, generalmente se usan frameworks de persistencia, que no son otra cosa que “adaptadores”. Como en la electricidad, que usamos transformadores para pasar de 220 a 110v, aquí es lo mismo. Estos frameworks suelen tener su complejidad por supuesto.

En los proyectos de lenguajes tradicionales orientados a objetos, ya usan un estándar o estándares que la misma industria les recomienda, como Spring o Hibernate. Este ultimo resuelve exactamente esta incompatibilidad, para lo cual, la mayoría piensa que ha sido una buena elección y sin dudarlo solo acata elegir el motor de base de datos. La realidad, es que en la mayoría de los proyectos usan herramientas inapropiadas sin analizar sin más detalles si realmente la requieren o si con una solución más simple pudieran obtener una solución perfectamente adecuada. La pregunta que se harán muchos es ¿Que está mal al elegir un framework gigante como hibernate para guardar los datos? Bien, la respuesta es simple, si el sistema probablemente use miles de usuarios y miles de datos, la alternativa sería correcta, pero sería mejor post-poner el uso de la persistencia hasta que el modelo esté maduro. Recién allí, nos inclinamos a hacer persistir el modelo, ya maduro, en la base; optimizando y haciendo lo ajustes necesarios. Si esto lo hacemos mucho antes de lo necesario, traerá complicaciones, que se traducen en más tiempo y al final es dinero malgastado. Esto, debería ser así para cualquier proyecto, pero no, la industria en general opta por complicarse de antemano, tener que echarle mano a scripts SQL para migrar cuando el modelo “inmaduro” va cambiando drásticamente su forma o directamente para evadir esto empiezan a dejar residuos en la base de datos. Claro, hay que aclararlo, una base de datos es una entidad absolutamente pasiva, y ni siquiera sabe que datos son usados y que datos podrían ir a parar a la basura. Como los datos son pasivos, al contrario que los objetos que son entidades activas. Estos últimos pueden aplicar la capacidad de un “Garbage Collector” o recolector de basura, que puede decidir por si solo si ciertos objetos ya no están siendo usados, por lo tanto, pueden borrarse. Si imaginamos esto en una base de objetos, entonces, tenemos que las bases de objetos tienen información más confiable que una base de datos por simple naturaleza.
Muchas veces he visto, por ejemplo, que se usa un tremendo y complejo framework de persistencia para solo “persistir” unos 10 objetos en el modelo, lo que se traduce a unas pocas tablas. Y ni hablar que quizás ese sistema solo tenga unos pocos usuarios. Es decir, tranquilamente se puede optar por sistemas de persistencia más simples y menos complejos. ¿Y que soluciones nos traería algo así? Bueno, para seguir dando ejemplos para entender, hace uno tiempo vi como un producto en el mercado tenía esta “sobredimensión” y el producto competencia en el que trabajé solo mantenía la información que requería en un archivo de formato propio (que no era otra cosa que un sistema de persistencia basado en diccionarios, muy simple). A la hora de competir, este sistema nuevo no paga ningún licenciamiento y requería muchísimos menos requisitos para funcionar. El otro sistema requería instalar por separado el motor, y luego los clientes. Como se imaginarán, no solo a nivel técnico hablamos de menos complejidades, a nivel negocio, era más rentable aquel que tenía menos. O sea, menos es más muchas veces. Como moraleja, deberíamos asumir que no hay que intentar matar mosquitos a cañonazos, o mejor dicho, no intentemos solucionar todo a cañonazos. Aunque algunos políticos ese problema sistémico no lo han entendido, esperemos que la gente que desarrolla sistemas si lo entienda.

¿Qué soluciones serían alternativas a usar una Base de datos relacional?

Dependiendo de la magnitud del proyecto y las de exigencias de este, podemos ir desde persistir en archivos, en el image de Smalltalk, en esquemas de persistencia, usar frameworks de persistencia a Base de datos, o base de objetos.

¿Que soluciones son opciones para este proyecto?

Dentro del marco de investigación para lo que necesitamos, van a desde sistemas de base de objetos como Magma o Goods, a un framework de persistencia sobre Base de datos.

Las solución que se elija debe contemplar:

  • Múltiples usuarios
  • Las 4 leyes básicas de persistencia: ACID (Atomicity, Consistency, Isolation, Durability) o en castellano, Atomicidad (ante cualquier eventualidad ninguna acción queda a medias), Consistencia (Es decir, que cada operación que se realice sobre la información asegura que siempre quedará integra), Aislamiento (Una operación no afectará a otras operaciones) y Durabilidad (es decir, que la información se guardará y permanecerá en el tiempo)
  • Pool de Sesiones, generalmente en un proyecto web, donde existen múltiples clientes no vamos a abrir una conexión por cada conexión web que se realice. El tema principal es que no siempre estamos persistiendo y podrían quedar sesiones abierta contra la base sin demasiado sentido más que malgastar los recursos computacionales preciados. Es por ello que se piensa en un pool de conexiones habilitadas para realizar las operaciones, y ciertos planes de contingencia.
  • Loqueo optimista, es de preferencia para un sitio web. El loqueo optimista asume que siempre hay conflictos y traza su política es base a esto. En el pesimista, pretende estar solo, y si va a haber conflicto debes loquear el objeto antes de usarlo.

Resumen

Se estudiarán varias alternativas de persistencia para el proyecto, la que mejor se adecue será la opción final a usar. Por lo pronto, por cada opción haremos una entrada en el blog para recordar los puntos positivos, los puntos negativos y los puntos interesantes de la cada opción.

El avance de la configuración de avatares en el juego de barajas 3D

Archivado en: Diseño — Hernan Galante @ 11:28 pm

Estos son algunas de las capturas de pantalla para la configuración de avatares en el juego de barajas 3D.

Estos son algunas de las capturas de pantalla para la configuración de avatares en el jeugo de barajas 3D.
Fig 1. Elección de gafas para el avatar

Registro de un nuevo usuario
Fig 2. Registro de un nuevo usuario

Configuración de las cejas del avatar
Fig 3. Configuración de las cejas del avatar

Configuración de la nariz del avatar
Fig 4. Configuración de la nariz del avatar

Estaremos publicando más capturas de pantalla a medida que vaya avanzando las distintas herramientas del juego.

Domingo 27/Abril/2008

¿Como empezar con SWT?

Archivado en: General, Programación — Hernan Galante @ 7:49 pm

Introducción

Una de las principales tareas a realizar cada vez que comenzamos con un nuevo framework o herramienta es saber rápidamente algunos detalles de como manejarnos. Ejemplo de esto son entender la arquitectura básica, saber como realizar las tareas básicas (arrancar, suspender, o detener el proceso) y como obtener las actualizaciones. Mínimamente con estos tres conceptos claros sobre una herramienta podemos usarla y explotarla satisfactoriamente. En este artículo pretendemos dar estos tres conceptos al lector.

Arquitectura del SWT

Smalltalk Web Toolkit es un framework para la construcción de aplicaciones web. Sus principales diferencias con respecto a otros frameworks es su arquitectura basada en Comet y un ambiente Smalltalk cliente hecho en JavaScript a través de un traductor de código Smalltalk-JavaScript. Estas dos diferencias hacen que las aplicaciones web rompan la desincronización del protocolo HTTP (gracias a Comet) pudiendo el server enviar contenido a sus clientes conectados, y gracias al traductor, todo el JavaScript necesario se escribe en Smalltalk sin tener que manipular en un proyecto varios lenguajes y tecnologías, pudiendo el desarrollador enfocarse más en el núcleo de su problema y no tanto en el entorno de como resolverlo.

Tareas Básicas

Algunas de las tareas básicas que requerimos conocer para hacer uso del framework son las siguientes:

1) Como arrancar el ambiente y el servicio
2) Como monitorear el servicio
3) Un “Hola Mundo”

Arrancando Squeak (Linux)

Squeak es un Smalltalk multiplataforma, más allá del ejemplo que citaremos aquí puede correr en muchos otros operativos.

Running Squeak
Fig. 1 - Corriendo el ambiente

Una vez dentro del ambiente, debemos arrancar el servicio. Para ejecutar una expresión Smalltalk la seleccionamos (de manera que todo el texto quede pintado) y luego podemos ejecutarlo con la combinación de teclas ALT+d ó ALT+p.

Arrancando SWT

La manera más fácil de saber si el framework está corriendo es apuntar nuestro navegador a su dirección default: http://127.0.0.1:2222. Si nos muestra la página (Fig. 2) con todas las aplicaciones disponibles, entonces el framework está corriendo.

Presentation web page
Fig. 2 - Página principal de SWT con todas las aplicaciones

En caso de que no esté corriendo, presentamos una serie de expresiones útiles a ser evaluadas en un Workspace de Smalltalk.
Estas expresiones nos permiten parar, arrancar o resetear el servicio.

SWTApplicationRunner start.
SWTApplicationRunner stop.
SWTApplicationRunner reset.
SWTApplicationRunner cleanUp.

¿En que casos debemos hacer uso del reset?
En caso de que se esté produciendo algún error inesperado grave, el #reset para el framework, mata la instancia actual del servicio y lo arranca de nuevo.

¿Cuál es la diferencia con el #cleanUp y el #reset?
El #cleanUp para el servicio, y es un proceso más profundo, hace una limpieza de las instancias de todos los aplicativos y del traductor de Smalltalk-JavaScript. Aunque no vuelve a arrancarlo explícitamente al servicio. Este método es usado cuando queremos hacer alguna actualización o mantenimiento.

Monitoreando el Servicio

El framework loguea actualmente todos sus pasos importantes, la principal salida es el Transcript de Smalltalk. Como vemos en la figura a continuación, en este Transcript nos muestra que se ha “salvado” la imagen del ambiente, y que luego hemos arrancado el servicio con el #start. Allí nos muestra de donde está tomando los recursos (imágenes, sonidos, etc) y en donde está atendiendo el servicio.

SWTApplicationRunner start
Fig. 3 - Arrancando SWT

También podemos ver el log en la consola de Linux, como en la pantalla que continua

Linux console log
Fig. 4 - Log en la consola de Linux

El clásico “Hola Mundo”

No es el objetivo de este artículo como programar sobre SWT, pero explicaremos un simple “Hola Mundo” que nos puede servir como base para comenzar a entender al framework.
La arquitectura del framework para construir aplicaciones se base en una parte cliente (la que correrá sobre el navegador) y la parte servidora (la que correrá sobre el servidor web y será la encargada de manipular a los clientes y proveerlos de la información, eventos y actualizaciones). Las clases en cuestión son: SWTClientApplication y SWTServerApplication. Para crear un nuevo aplicativo solo necesitaremos crear una subclase para el cliente y otra para el server. Tomaremos como ejemplo al aplicativo de “Ping/Pong” el cual es una especie de “Hola Mundo”.

Ping-Pong
Fig. 5 - El aplicativo Ping/Pong

El código del Ping/Pong es bastante simple, la idea detrás del aplicativo es que el cliente muestre una página muy simple, y al cliquear en el botón se envíe un mensaje #ping al servidor, y este le conteste al cliente, con un mensaje #pong.

Existe otro articulo llamado Mini aplicaciones sobre Smalltalk Web Toolkit (SWT) que abarca a este ejemplo de “Hola Mundo” en profundidad.

Actualizando SWT

¿Como mantener actualizado el código en SWT? Para responder esta pregunta, vamos a explicar como un proyecto en Squeak, en general, también se actualiza y mantiene. Existe un servicio, que es un repositorio de código para Squeak llamado SqueakSource.

Squeak Sourcepage
Fig. 6 - SqueakSource

En este sitio hay docenas de proyectos open source para la comunidad. SWT es un proyecto más publicado de esta manera. El sitio oficial dentro de SqueakSource es http://www.squeaksource.com/SWT.html. La mejor forma de mantenerse informado es apuntar nuestro lector de RSS favorito a http://www.squeaksource.com/SWT/feed.rss. Cada nueva versión que se publique será publicada de forma automática. Para actualizar nuestro ambiente Squeak a esta nueva versión usaremos una herramienta llamada Monticello. (Fig. 7)

Actualizando con Monticello 1
Fig. 7 - Creando un nuevo paquete en Monticello

¿Como actualizar usando Monticello?
Monticello se abre desde el menú principal de Squeak (dando click sobre el escritorio de Squeak se despliega un menú). En el menú, elegir las opciones “Open” y luego “Monticello browser”.

Menu para abrir Monticello
Fig. 8 - Secuencia para abrir Monticello

Una vez que tenemos abierto el Monticello, debemos crear un nuevo paquete (Package), nos pedirá el nombre, al cual nombraremos como SWT o como nos sea útil. Luego, que tenemos el nuevo paquete, le vamos a indicar donde está el repositorio, dando click en el botón que dice “+Repository”. Elegimos la opción HTTP, e ingresamos la dirección en el cuadro http://www.squeaksource.com/SWT.

Actualizando Monticello 2
Fig. 9 - Después de crear el paquete, creamos el repositorio, y seleccionamos el HTTP

Una vez creado el repositorio, lo seleccionamos y presionamos el botón “Open”. Esto hará que se conecté al repositorio, y nos abra otra ventana donde nos mostrará las versiones disponibles para cargar desde el repositorio en nuestro ambiente.

Actualizando Monticello 3
Fig. 10 - El repositorio mostrando los distintos frameworks y sus versiones para ese proyecto

Para actualizar nuestra versión simplemente elegimos la versión, y luego apretamos el botón “Load” (cargar).
Cuando esta operación termine nuestro ambiente estará con la versión que hemos seleccionado. Si una versión es dependiente de otra versión, nos preguntará si también lo deseamos cargar.

Resumen

En este artículo hemos visto como arrancar el ambiente, como actualizarlo y como hacer los mantenimientos básicos.

¿De donde bajar Smalltalk Web Toolkit?

Archivado en: General, Programación — Hernan Galante @ 7:49 pm

¿De donde se puede bajar la versión?

Se ha publicado una versión del framework actual en la siguiente dirección:

http://smalltalk.consultar.com/varios/SWT-full.zip

¿Que contiene el archivo Zip?

El Zip contiene los archivos necesarios para correr el ambiente para SWT en las plataformas de Linux y Windows.

Contiene los siguientes directorios:

  • Files: Contiene las bibliotecas javascript para SWT
  • Packages-cache: Es utilizado por la herramienta de paquetes de Squeak
  • Resources: Son todos los recursos (imágenes, sonidos, etc.) que usan las distintas aplicaciones sobre SWT
  • Sm: Es utilizado por la herramienta de paquetes de Squeak

Contiene los siguientes archivos:

  • Archivos independientes de la plataforma:
    • Squeak3.8.1-6747full.38.changes: Es el archivo de cambios del ambiente
    • Squeak3.8.1-6747full.38.image: Es el archivo imagen de Squeak.
    • SqueakV3.sources: Es el archivo que contiene los fuentes de Squeak.
    • Splash.bmp: Es la imagen visual que se ve al arrancar el ambiente.
  • Archivos exclusivos para Linux:
    • Squeak-3.9-8.i686-pc-linux-gnu.tar.gz: Contiene la máquina virtual para instalar en Linux
  • Archivos exclusivos para Windows:
    • SqueakFFIPrims.dll: Librería para primitivas exclusivas para Windows
    • Squeak.ini: Configuración de la máquina virtual sobre Windows
    • Squeak.exe: Ejecutable para Windows

¿Cómo lo corro desde Linux?

En un Linux, recordamos que esta versión ha sido probada en Ubuntu 7.10, instalar la máquina virtual que se encuentra en el archivo Zip, Squeak-3.9-8.i686-pc-linux-gnu.tar.gz. Dentro de este archivo encontrarán las instrucciones para llevar a cabo la instalación de la máquina virtual sobre Linux.

¿Cómo lo corro en Windows?

En Windows correr el archivo Squeak.exe y este nos abrirá el archivo .image que encuentre dentro del mismo directorio.

En Windows encontraremos un error, dado que esta versión está siendo desarrollada para Linux.  Para ello hay que desactivar (simplemente comentando el código) en

Alogger>>logMessages:
....
   "Try to log to stdout, using OSProcess"
   "Smalltalk at: #OSProcess ifPresent: [:osProcessClass |
    osProcessClass thisOSProcess stdOut
     nextPutAll: msg;
     nextPut: Character lf.
   ]."
....

¿Otras plataformas?

Dado que Squeak es un ambiente Smalltalk multiplataforma, podemos encontrar en su sitio oficial muchas máquinas virtuales para correr la imagen (que no depende de la plataforma ni del sistema operativo). Con solo seguir las instrucciones de como instalar para una plataforma en especial para Squeak, también lo estamos haciendo para SWT. Sólo deberemos descomprimir la imagen (archivo extensión .image) y correrlo con el ejecutable o binario de nuestra plataforma y SWT estará corriendo.

¿Sobre que Sistemas operativos ha sido probada esta distribución?

La versión está preparada para Linux. Pero también ha sido probada sobre Windows. Ver en las preguntas anteriores los detalles de como instalar.

Miércoles 19/Marzo/2008

Ejemplo: Un examen en línea con Smalltalk Web Toolkit (SWT)

Archivado en: Programación — Hernan Galante @ 4:08 pm

Introducción

En este framework, basado en la arquitectura Comet, tenemos dos clases principales para hacer un aplicativo, SWTClientApplication y SWTServerApplication. Para comenzar vamos a realizar un pequeño ejemplo sobre lo que sería una aplicación de Exámenes en línea. Donde se muestra una pregunta a la vez, y varias posibles soluciones. Al final de contestar las preguntas da el puntaje obtenido. Este tutorial se dividirá en dos partes, en la primer parte haremos este aplicativo con un modelo en el servidor más inactivo y el cliente web con más mucha más actividad y funcionalidad. En la segunda parte, haremos uso del MVC distribuido que ofrece el SWT, donde mostraremos como mejorar considerablemente la cantidad de mensajes y la forma ineficiente con respecto a la primer parte.

Ejemplo: Exámenes en línea

El modelo

Para comenzar vamos a desarrollar un modelo simple del aplicativo. Un examen se compone de una pregunta y múltiples respuestas, donde cada respuesta puede ser la más acertada para responder o simplemente es incorrecta. Por estándar vamos a tener cinco respuestas por cada pregunta, y cada respuesta tiene un valor. Para hacer los cálculos más simples, vamos a poner un rango de puntuación entre 0 y 10 puntos.

La respuesta es un objeto simple que tiene la respuesta que contiene con su puntaje asociado, y una pregunta es un objeto con una pregunta y una colección de respuestas.

Para ello, vamos a crear un workspace con las expresiones que queremos que funcionen:

| question answers |

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘Object’ score: 0);

add: (SWTAnswerModel answer: ‘Collection’ score: 0);

add: (SWTAnswerModel answer: ‘Set’ score: 10);

add: (SWTAnswerModel answer: ‘Bag’ score: 0);

add: (SWTAnswerModel answer: ‘SWTModel’ score: 0);

yourself.

question := SWTQuestionModel question: ‘¿De quién hereda Dictionary?’ answers: answers.

Como vemos en workspace anterior ya tenemos un pequeño borrador de como sería nuestro modelo. Ahora, cada vez que un usuario responde vamos a agregarle que la pregunta sepa la respuesta que eligió el usuario, para ello, agregamos una variable de instancia que nos permita recordar que respondió a esa pregunta. La variable la vamos a denominar answerChoosed.

| question answers |

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘Object’ score: 0);

add: (SWTAnswerModel answer: ‘Collection’ score: 0);

add: (SWTAnswerModel answer: ‘Set’ score: 10);

add: (SWTAnswerModel answer: ‘Bag’ score: 0);

add: (SWTAnswerModel answer: ‘SWTModel’ score: 0);

yourself.

question := SWTQuestionModel question: ‘¿De quien hereda Dictionary?’ answers: answers.

question answerChoosed: (answers at: 3).

Si el usuario no sabe contestar la pregunta, pondremos una respuesta por defecto, que valdrá cero puntos, y es No sabe y/o No contesta. Esto lo vamos a hacer en el getter de #answerChoosed

SWTQuestionModel>>answerChoosed

” Returns the answer choosed by the user to the receiver.”

answerChoosed isNil ifTrue: [ self answerChoosed: SWTAnswerModel notAnswered ].

^answerChoosed

Ahora bien, en nuestro modelo ya tenemos preguntas, posibles respuestas y la respuesta que se elige. Esto funciona para solo una pregunta, pero un examen, consta de muchas preguntas, y dado, que generalmente una certificación, tiene al menos unas 40 preguntas, vamos a modelar nuestro objeto examen. Este objeto tiene una colección de preguntas, y sabe calcular el puntaje final. Vamos a denominar SWTExamModel.

Para calcular el puntaje final lo hacemos así:

En el examen

SWTExamModel>>score

” Returns the score of the receiver.”

^self questions inject: 0 into: [ :finalScore :question | question score + finalScore ]

En la pregunta

SWTQuestionModel>>score

” Returns the score of the receiver.”

^self answerChoosed score

Hasta aquí, ya tenemos un modelo funcional, tenemos un examen, que se compone de preguntas, a su vez, las preguntas tiene posibles respuestas, y el usuario por cada pregunta elige su respuesta. El objeto respuesta sabe que puntaje tiene. Entonces el examen solo delega en sus preguntas saber los puntajes obtenidos, y estas a su vez, usan de colaborador a nuestras respuestas.

Nuestro examen aún le falta algo más, si ya respondí una pregunta, tengo que esperar la siguiente, así que vamos a decirle al examen, que nos de una pregunta más, para hacerlo más interesante aún, que sea al azar, y lógicamente, como es azar, no quiero responder más de una vez una pregunta, por lo tanto, el examen deberá quitar las que ya se respondieron. Para ello, agregamos este comportamiento a examen. Vamos a tener variables de instancia a questions, que son las preguntas totales, y otra colección con las preguntas ya usadas, questionsAnswered.

SWTExamModel>>questionsNotAnswered

” Returns the collection of questions not answered yet of the receiver.”

| newQuestions |

newQuestions := self questions copy.

newQuestions removeAll: self questionsAnswered.

^newQuestions

Obtener una nueva pregunta:

SWTExamModel>>newQuestion

” Returns a new question for the exam.”

| newQuestion randomIndex maximumInteger |

randomIndex := Random seed: 2345678901.

[ maximumInteger := self questionsNotAnswered size.

maximumInteger = 0 ifTrue: [ ^nil ].

newQuestion := self questionsNotAnswered at: (randomIndex nextInt: maximumInteger).

self questionsAnswered includes: newQuestion] whileTrue: [].

self currentQuestion: newQuestion.

self questionsAnswered add: self currentQuestion.

^self currentQuestion

Para probar lo que hemos hecho hasta el momento, vamos a hacer un workspace donde tengamos un examen con 3 preguntas y las contestaremos. Por ultimo, evaluaremos el puntaje final.

| exam questions answers questionToAnswer |

questions := OrderedCollection new.

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘Object’ score: 0);

add: (SWTAnswerModel answer: ‘Collection’ score: 0);

add: (SWTAnswerModel answer: ‘Set’ score: 10);

add: (SWTAnswerModel answer: ‘Bag’ score: 0);

add: (SWTAnswerModel answer: ‘SWTModel’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘¿De quien hereda Dictionary?’ answers: answers).

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘un objeto’ score: 0);

add: (SWTAnswerModel answer: ‘una clase’ score: 0);

add: (SWTAnswerModel answer: ‘una variable global’ score: 10);

add: (SWTAnswerModel answer: ‘El nombre del producto’ score: 0);

add: (SWTAnswerModel answer: ‘una nueva distro de Linux’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘Que es Smalltalk?’ answers: answers).

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘la clase del 3′ score: 0);

add: (SWTAnswerModel answer: ‘la clase Class’ score: 0);

add: (SWTAnswerModel answer: ‘Integer class’ score: 10);

add: (SWTAnswerModel answer: ‘un error’ score: 0);

add: (SWTAnswerModel answer: ‘nil’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘que devuelve 3 class class?’ answers: answers).

exam := SWTExamModel questions: questions.

questionToAnswer := exam newQuestion.

questionToAnswer answerChoosed: (questionToAnswer answers at: 1).

questionToAnswer := exam newQuestion.

questionToAnswer answerChoosed: (questionToAnswer answers at: 3).

questionToAnswer := exam newQuestion.

questionToAnswer answerChoosed: (questionToAnswer answers at: 3).

exam score

El resultado obtenido nos debería devolver 20 puntos. Pues la primer pregunta la contestamos incorrectamente, y las dos subsecuentes correctamente.

La interfaz web con SWT sin MVC distribuido

La interfaz de nuestro examen, será bien simple también, solo tenemos que mostrar nuestra pregunta, y las posibles respuestas para que las pueda elegir el usuario. La forma de elegir será a través de un botón por ahora. Cada vez que responde una pregunta, tenemos que continuar a la siguiente, hasta que termine y mostrar el puntaje final obtenido. Para lograr esto, vamos a modelar nuestra página a través de una clase que hereda de SWTClientApplication. La vamos a denominar SWTClientExamApplication, y desde el servidor vamos a tener a su controlador, llamado SWTServerExamApplication.

En el cliente, vamos a tener la pregunta como modelo, y en el server al examen.

SWTServerExamApplication>>exam

” Returns the exam of the receiver.”

exam isNil ifTrue: [ self initializeExam ].

^exam

SWTServerExamApplication>>initializeExam

” Initialize the exam.”

| questions answers |

questions := OrderedCollection new.

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘Object’ score: 0);

add: (SWTAnswerModel answer: ‘Collection’ score: 0);

add: (SWTAnswerModel answer: ‘Set’ score: 10);

add: (SWTAnswerModel answer: ‘Bag’ score: 0);

add: (SWTAnswerModel answer: ‘SWTModel’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘De quien hereda Dictionary?’ answers: answers).

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘un objeto’ score: 0);

add: (SWTAnswerModel answer: ‘una clase’ score: 0);

add: (SWTAnswerModel answer: ‘una variable global’ score: 10);

add: (SWTAnswerModel answer: ‘El nombre del producto’ score: 0);

add: (SWTAnswerModel answer: ‘una nueva distro de Linux’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘Que es Smalltalk?’ answers: answers).

answers := OrderedCollection new.

answers

add: (SWTAnswerModel answer: ‘la clase del 3′ score: 0);

add: (SWTAnswerModel answer: ‘la clase Class’ score: 0);

add: (SWTAnswerModel answer: ‘Integer class’ score: 10);

add: (SWTAnswerModel answer: ‘un error’ score: 0);

add: (SWTAnswerModel answer: ‘nil’ score: 0);

yourself.

questions add: (SWTQuestionModel question: ‘que devuelve 3 class class?’ answers: answers).

self exam: (SWTExamModel questions: questions).

SWTServerExamApplication>>newQuestion

” Returns a new question of the receiver.”

^self exam newQuestion.

Una parte muy importante, dado que el cliente, es un mini-Smalltalk, pues todo lo que estamos escribiendo en nuestra clase cliente, a la hora de funcionar, esto se traduce a Javascript. El framework posee un traductor de Smalltalk a Javascript bastante complejo, y como Smalltalk y Javascript son asimétricos, es decir, no todo el potencial del Smalltalk puede ser traducido a funcionalidad en Javascript, debemos tenerlo en cuenta a la hora de poner comportamiento en el cliente.

Todas las clases de nuestro modelo que sean usadas en el cliente, debemos enumerarlas en un mensaje de clase #jsClassesToInclude. Para que el traductor, genere estas clases del modelo en nuestro mini-Smalltalk en Javascript. Para nuestro ejemplo, vamos a hacer uso de las preguntas y las respuestas, por consiguiente, redefinimos este mensaje:

SWTClientExamApplication class>>jsClassesToInclude

^ {SWTQuestionModel. SWTAnswerModel }

Ahora en el cliente, haremos nuestra vista

SWTClientExamApplication>>newQuestion

” Returns the a new question of the receiver and updates the questions panel of the receiver.”

self isolatedAsynchronousRPCMethods:

[ self question: self serverSide newQuestion.

self updateQuestionsPanel ]

Ahora, lo que haremos son los widgets de la vista, esto se hace redefiniendo un método #initializeWidgets.

SWTClientExamApplication>>initializeWidgets

” Initialize the widgets of the receiver.”

| root |

root := self rootWidget.

root

addWidget: (questionsPanel := SWTPanel new).

En este método hemos definido una variable de instancia que guardara un SWTPanel, que es quien contendrá las preguntas, y a medida que el usuario las contesta, entonces, usaremos este panel para actualizar los datos en el navegador.

SWTClientExamApplication>>updateQuestionsPanel

” Update the questions panel of the receiver.”

questionsPanel clearWidgets.

self question isNil

ifTrue:

[ ^questionsPanel

addWidget: (SWTHeader contents: 'Puntaje final: ' , self finalScore)].

questionsPanel

addWidget: (SWTText

contents: ‘Pregunta: ‘ , (self question perform: #question));

addHorizontalRule.

(self question perform: #answers) do:

[:answer |

questionsPanel addWidget: (SWTButton caption: (answer perform: #answer)

onClick: [:event | self answerChoosed: answer])]

Un detalle que debemos notar de este #updateQuestionsPanel, es que si la pregunta es nula, es decir, ya no tenemos más preguntas para mostrar, entonces mostramos el puntaje final obtenido del usuario.

Para ello definimos el mensaje:

SWTClientExamApplication>>finalScore

” Returns the final score of the receiver.”

^self serverSide score

A la hora que se conecta el cliente con el server, vamos a hacer que este se inicialize con la primer pregunta para que la muestre, para engancharnos de este evento, redefiniremos un mensaje que nos provee el framework, el #justConnected. De esta manera nos aseguramos que solo la pregunta será nula, cuando el examen haya finalizado, dado que cuando se conecta por primera vez el cliente, se inicializará con la primer pregunta del examen.

SWTClientExamApplication>>justConnected

” On just connected the receiver.”

super justConnected.

self newQuestion.


Lo que hemos hecho es decirle, una vez que te conectás con el servidor, envíame una pregunta, e inicializamos el MainPanel, que es nuestro panel donde mostramos las preguntas.

¡Muy bien! Ahora ya tenemos nuestro examen listo ¡Es hora de probarlo!

Screenshot tutorial pregunta

Y la pantalla final del puntaje:

Screenshot puntaje final non MVC

Resumen

Este ejemplo es muy improductivo e ineficiente, porque, como se puede observar en la ultima imagen, usa demasiados mensajes al servidor, y no usa el MVC distribuido que nos proporciona el framework. En nuestra segunda sección, haremos que este mismo ejemplo, sea hecho con el MVC distribuido, mejorando considerablemente la cantidad de mensajes que usan el servidor a través de eventos.

¡La cantidad de peticiones que realizó fueron 30! En la siguiente sección vamos a explorar y refactorizar ciertos mensajes haciendo uso no solo del MVC distribuido sino también de un modelo en el servidor más activo que en la primer parte.

La interfaz web con SWT con MVC distribuido

Una vez que sabemos como podemos hacerlo funcionar, ahora, vamos a hacerlo funcionar bien.

Vamos a usar el mismo modelo, con algunas modificaciones, pero usando el Model-View-Controller distribuido que provee el framework, el cual, está optimizado para Internet, dado que un mal uso del servidor, con muchos usuarios, sería muy caótico, además de desaprovechar el framework.

Creando nuevas clases

Para empezar vamos a redefinir todo la parte web en otras clases. Las vamos a denominar SWTClientMVCExamApplication y SWTServerMVCExamApplication a las nuevas vistas con MVC.

SWTClientApplication subclass: #SWTClientMVCExamApplication

instanceVariableNames: ‘exam questionsPanel’

classVariableNames:

poolDictionaries:

category: ‘TutorialSWT-SWT’

Y el servidor

SWTServerApplication subclass: #SWTServerMVCExamApplication

instanceVariableNames: ‘exam’

classVariableNames:

poolDictionaries:

category: ‘TutorialSWT-SWT’

Modificando el modelo

A nuestro modelo anterior, tenemos que agregarle la parte escencial del MVC, que es que nos avise cuando un evento se produce en él. Las dos únicas situaciones importante en el modelo, que son de interés para nuestra vista, son cuando se gestiona una nueva pregunta (y esto es porque el usuario ya respondió la anterior o porque comienza el examen) y cuando se termina el examen. Estas son las dos situaciones donde necesitamos que nos avise el modelo, y a las cuales, la vista se suscribirá para tomar acción en ellas.

Para ello modificamos el modelo haciendo que la pregunta actual que está siendo mostrada por el sistema al usuario la guardemos en una variable de instancia del examen, cosa que antes no hacíamos, entonces nuestra clase de examen quedaría de esta manera:

SWTModel subclass: #SWTExamModel

instanceVariableNames: ‘questions questionsAnswered currentQuestion’

classVariableNames:

poolDictionaries:

category: ‘TutorialSWT-Core’

y los mensajes que modificaremos serán #newQuestion y

SWTExamModel>>newQuestion

” Returns a new question for the exam.”

| newQuestion randomIndex maximumInteger |

randomIndex := Random seed: 2345678901.

[ maximumInteger := self questionsNotAnswered size.

maximumInteger = 0 ifTrue: [ self triggerEvent: #examFinished. ^nil ].

newQuestion := self questionsNotAnswered at: (randomIndex nextInt: maximumInteger).

self questionsAnswered includes: newQuestion] whileTrue: [].

self currentQuestion: newQuestion.

self questionsAnswered add: self currentQuestion.

self triggerEvent: #newQuestion.

^self currentQuestion


Como se puede observar en el código del método, lo que hemos agregado es el uso de la variable de instancia #currentQuestion a través de sus mensajes de acceso, y hemos puesto los eventos, el primero denominado #examFinished, que se dispara cuando ya terminaron las preguntas, y el otro #newQuestion, que se dispara cuando hay una nueva pregunta disponible.

Vamos a agregar el mensaje al examen #answerChoosed:, donde se la pasa la respuesta seleccionada y genera una nueva pregunta.

SWTExamModel>>answerChoosed: anAnswer

self currentQuestion answerChoosed: anAnswer.

self newQuestion.


Se puede apreciar que ya en este nuevo modelo, levemente modificado, un circuito, donde una vez que se contesta una pregunta, se inicia otra, si se termino, avisa, y si está comenzando, con solo llamar a generar una nueva pregunta damos comienzo al examen. Con este pequeño flujo de trabajo, vamos a rediseñar nuestro Servidor y nuestro Cliente para bajar las 30 peticiones que hace el cliente al servidor.

La vista con MVC

Esta nueva vista, al momento que se conecta con el servidor, le pedirá su modelo (un exámen), registrará los eventos y luego dará comienzo al examen.

SWTClientMVCExamApplication>>justConnected

” On just connected the receiver.”

super justConnected.

self exam: self serverSide exam.

self registerEvents.

self serverSide startExam


La suscripción a los eventos del modelo

SWTClientMVCExamApplication>>registerEvents

” Register the events with the model of the receiver.”

self exam

when: #examFinished send: #showFinalScore to: self;

when: #newQuestion send: #showQuestion to: self.


Y en el lado de la clase, vamos a decirle al framework que solo vamos a pasar el examen hacia la vista como modelo.

SWTClientMVCExamApplication class>>jsClassesToInclude

^ {SWTExamModel}

En este método, cuando se produce un evento u otro, llama a dos mensajes distintos dentro de la vista: #showFinalScore y #showQuestion.

Si terminó el examen, entonces se ejecuta:

SWTClientMVCExamApplication>>showFinalScore

” Shows the final score in the questions panel of the receiver.”

self isolatedAsynchronousRPCMethods:

[ questionsPanel

clearWidgets;

addWidget: (SWTHeader contents: 'Puntaje final: ' , self serverSide score printString) ]

En este método, estamos haciendo que esta operación del cliente sea ejecutada en modo batch de una sola vez contra el servidor. Esto es unas de las características que brinda el framework para reducir el tráfico de datos.

Cada vez que hay una nueva pregunta se ejecuta:

SWTClientMVCExamApplication>>showQuestion

” Shows the questions panel of the receiver.”

questionsPanel clearWidgets.

questionsPanel

addWidget: (SWTText contents: ‘Pregunta: ‘ , (self serverSide currentQuestionString));

addHorizontalRule.

(self serverSide currentQuestionAnswersString) inlineDo:

[:answerString |

questionsPanel addWidget: ((SWTButton caption: answerString)

onClick: [:event | self serverSide answerChoosed: event source caption ])]

En esta método, lo que está realizando es que cada vez que se ejecuta, pide al servidor la pregunta, las posibles respuestas y arma la web.

Armando el servidor con su respectivo examen

En el servidor, vamos a definir #startExam, que lo unico que hará es decirle al modelo que comienze el examen por medio de la generación de una nueva pregunta

SWTServerMVCExamApplication>>startExam

” Start the current exam.”

self exam newQuestion

Los dos siguientes mensajes retornan los textos necesarios para la pregunta y sus posibles respuestas

SWTServerMVCExamApplication>>currentQuestionString

” Returns the current question strings.”

^self exam currentQuestion question

El cliente enviará al servidor el siguiente mensaje cuando la respuesta se haya seleccionado:

SWTServerMVCExamApplication>>answerChoosed: anAnswerString

” Set the answer choosed from the button caption clicked.”

self exam

answerChoosed: (self exam currentQuestion answers detect: [ :answer | answer answer = anAnswerString ])

¡Muy bien! Ahora ya tenemos nuestro nuevo examen listo ¡Es hora de probarlo!

Screenshot puntaje final MVC

Como podemos analizar de ver en la imagen anterior, la cantidad de pedidos al servidor se vieron reducidos en un 60%, lo que es un gran ahorro de tráfico para cualquier tipo de aplicativo.

Resumen

Como hemos visto a través de este ejemplo, el framework permite hacer aplicativos web en forma muy sencilla, sin ningún uso otras tecnologias más que Smalltalk y usando objetos. Y como se puede comprobar, el uso de un MVC distribuido es eficaz y nos permite tener muchas más ventajas, como multiples vista (N cantidad de navegadores sobre un mismo modelo), optimización de tráfico de datos a través de la red y una actualización sin necesidad de que el cliente lo tenga que peticionar al servidor.

Miércoles 5/Marzo/2008

Diseño de baraja en 3D

Archivado en: Diseño, General — Diego Gomez Deck @ 11:00 am

Ya tenemos bastante avanzado el diseño de una de la barajas que incluiremos en el juego.

cartas3d.png

Pueden descargar los PNGs desde forjamari. Más información en http://igosoftware.wordpress.com/

Domingo 20/Enero/2008

Mini aplicaciones sobre Smalltalk Web Toolkit (SWT)

Archivado en: Programación — Hernan Galante @ 2:24 am

Introducción

En este framework, basado en la arquitectura Comet y con un mini-Smalltalk en los navegadores sobre Javascript, tenemos dos clases principales para hacer un aplicativo, SWTClientApplication y SWTServerApplication. La primera es la clase que modela la parte cliente, que corre en el navegador y sobre Javascript, y de la cual heredará nuestra clase que será la responsable de presentar la interfaz al usuario; la segunda, es la clase en el servidor, que corre en Smalltalk, y de la cual se heredará para darle comportamiento al aplicativo controlando al cliente o los clientes. El framework también nos provee de un esquema de Model-View-Controller distribuido. Vamos a realizar dos simples ejemplos para mostrar el uso de este framework.

Ejemplos de uso

Vamos a hacer dos aplicaciones muy sencillas, la primera es un ejemplo de como usar el framework en una aplicación donde el servidor y cliente solo se comunican en forma básica, y en la segunda, es una adaptación de la primera pero usando algunas funcionalidades más.

Ping/Pong

La idea detrás de este aplicativo es que el cliente envíe un “ping” al servidor, y este le responda con un “pong”. Es muy simple y vamos a explorar las cualidades más básicas del framework al escribir esta aplicación.

Creando nuestras clases

Para comenzar vamos a crear nuestra clase cliente, heredando de SWTClientApplication y a la cual vamos a denominar SWTPingPongClientApplication.

Para el cliente:

SWTClientApplication subclass: #SWTPingPongClientApplication

instanceVariableNames:

classVariableNames:

poolDictionaries:

category: ‘SWT-Examples’

Para el server:

SWTServerApplication subclass: #SWTPingPongServerApplication

instanceVariableNames:

classVariableNames:

poolDictionaries:

category: ‘SWT-Examples’

Dándole un nombre al aplicativo

Con las clases definidas, vamos a darle un nombre a nuestro aplicativo, esto lo hacemos redefiniendo un mensaje de clase en la parte server a través de #applicationName, nuestro aplicativo se llamará “Ping/Pong”.
El principal propósito de esto, es que el framework nos presenta una lista de aplicativos a ejecutar por defecto en el navegador, si este lo apuntamos a la dirección por defecto http://127.0.0.1:2222, y el título que usa para hacer la presentación de cada aplicativo, es este mensaje.

SWTPingPongClientApplication class>>applicationName

^ ‘Ping Pong’

Poniendo los controles web

Como mencionamos anteriormente, la parte cliente es la responsable de la presentación en el navegador, por lo tanto, vamos a crear los elementos necesarios. Para realizar esto, tenemos toda una jerarquía de Widgets o controles web, que se clasifican a partir de SWTWidget.
El framework nos provee de ciertos mensajes que debemos definir, unos de estos es #initializeWidgets. En este mensaje se define la construcción de la página web, armando los controles que irán, como se componen y que eventos y propiedades tienen. Para nuestro caso, lo que queremos que vea el usuario es un titulo con el nombre de nuestro aplicativo y vamos a colocar un botón donde el usuario envia el “Ping” al servidor.

SWTPingPongClientApplication>>initializeWidgets

“Initialize the receiver’s widgets”

| root |

root := self rootWidget.

root addWidget: (SWTHeader level: 2 contents: self class applicationName).

root addWidget: (SWTButton caption: ’server ping’ onClick: [:event | self serverSide ping]).

Como podemos apreciar en el método anterior, lo hacemos es crear un control raíz, o root widget, y a partir de este armamos nuestra página. En este caso, hemos agregado primero un título de nivel 2, o como se lo conoce en HTML, un tag H2 con el nombre de nuestra aplicación usando el método más arriba definido. Por último, se agregó un botón con la leyenda “server ping”, y que, al ser clickeado envia al servidor el mensaje #ping.

Implementando el ping en el servidor

Una vez hecha la parte cliente, vamos a implementar el mensaje #ping, que estamos enviando desde el navedor al presionar el botón. Desde el cliente, cuando enviamos #serverSide, nos retorna un objeto remoto a nuestra aplicación del lado del servidor. Es por ello, que vamos a implementar el comportamiento del “ping” en el server.

SWTPingPongServerApplication>>ping

Transcript show: ‘ping!’; cr.

self clientSide pong.

Lo que hemos definido en el servidor, es una vez que recibimos el #ping, escribimos el mensaje en el Transcript de Smalltalk (es una ventana de salida de mensajes) y luego, le devolvemos un “pong” al cliente.
Como podemos apreciar, para enviar mensajes hacia un lado u otro usamos un mensaje, para obtener la parte cliente desde el servidor es #clientSide, y para obtener la parte del servidor desde el cliente es #serverSide. De forma tan simple, podemos enviar comunicación para un lado o para el otro a través del canal establecido por la arquitectura de Comet. Recordemos que el HTML es un protocolo asimétrico, es decir, solo la comunicación la establece el cliente, y el servidor se limita solo a contestar las peticiones. En la arquitectura comet que usa este framework, esa diferencia no existe, ya que la comunicación entre el cliente y el servidor no se corta. En HTML una vez que el servidor haya cumplido con las peticiones del cliente la comunicación se corta. En Comet el servidor también puede enviar información al cliente sin que este último la haya tenido que solicitar. Esto es muy útil en aplicativos como sitios de remate, salas de conversación o chat, sitios de la bolsa de valores, y para cualquier aplicativo web donde la información cambie en el servidor y los clientes no tengan que hacer las peticiones para mantenerse informados, sino que sean informados en el instante en que se producen los eventos en el servidor.

Implementando el pong en el cliente

Ahora, por último, nos falta implementar el mensaje #pong en el cliente, y lo que vamos a hacer, es que cuando lo reciba muestre un mensaje al usuario con la expresión “Pong!”

SWTPingPongClientApplication>>pong

self inform: ‘pong!’

Probando el Ping/Pong

Para hacerlo, tenemos dos maneras, la primera es apuntando a nuestro navegador a la dirección: http://127.0.0.1:2222.
Allí nos presenta un listado de aplicativos que podemos usar, el nuestro, aparecerá listado con el nombre que le indicamos en el applicationName.
La otra forma, es directamente apuntando al aplicativo, en este caso: http://127.0.0.1:2222/SWTPingPongClientApplication.
Listo, ya estamos preparados para probar nuestro aplicativo. A continuación presentamos un screenshot del mismo.

Screenshot del ping/pong funcionando

Resumen del Ping/Pong

Hemos visto que se debe heredar de dos clases fundamentales del framework y que estas nos proveen unos mensajes que redefinimos para implementar nuestro comportamiento, esto en el cliente es el #applicationName y el #initializeWidgets.
En solo estos dos mensajes más un comportamiento básico de dos mensajes ping/pong hemos armado nuestro primer aplicativo. Como se vió también en este ejemplo, el framework nos da soporte para tener controles (SWTWidgets) y de comportamiento básico en la web, como lo es mostrar un mensaje (#inform:).

Echo Request / Echo Reply

Este aplicativo es muy parecido al ejemplo anterior, pero con la diferencia, que un echo envia un objeto como parámetro al server y este lo único que hace es reponderlo nuevamente. Es como un ping/pong, pero ahora, con una pelota.
Para realizarlo, vamos a repetir la misma secuencia que con el ejemplo anterior, pero esta vez, enviando un mensaje al servidor y este nos lo va a devolver.

Para el cliente:

SWTClientApplication subclass: #SWTEchoClientApplication

instanceVariableNames:

classVariableNames:

poolDictionaries:

category: ‘SWT-Examples’

Para el server:

SWTServerApplication subclass: #SWTEchoServerApplication

instanceVariableNames:

classVariableNames:

poolDictionaries:

category: ‘SWT-Examples’

Y le vamos a definir el nombre del aplicativo:

SWTEchoClientApplication class>>applicationName

^‘Echo!’

Poniendo los controles web

Vamos crear un titulo, un lugar donde poner un texto y al presionar el enter, enviará el texto al servidor.

initializeWidgets

“Initialize the receiver’s widgets”

| root input |

root := self rootWidget.

input := SWTInputText contents: .

input

onKeyPress: [:event | event keyCode = 13

ifTrue: [self serverSide echoMessage: event source contents]].

root

addWidget: (SWTHeader level: 2 contents: self class applicationName);

addWidget: (SWTText contents: ‘Ingrese un mensaje y presione enter para enviarlo al servidor: ‘);

addWidget: input

Lo que hemos hecho en este mensaje, es utilizar las propiedades que nos brinda el SWTInputText, al presionar una tecla, y si esta tecla es un enter (codificado como 13), se envia un mensaje al server (#echoMessage:), con un argumento, este no es más que el contenido del control que generó el evento. En este caso, ese contenido es el texto que ingresamos.

Ahora, vamos a definir, nuestro #echoMessage: en el servidor, que lo que hace, no es otra cosa que devolverlo al cliente de la siguiente manera:

SWTEchoServerApplication>>echoMessage: aMessage

self clientSide echoMessage: aMessage

En el cliente, ahora necesitamos implementar nuestro mensaje #echoMessage:, que no hará otra cosa más que mostrar un cartel en el navegador con el mensaje.

SWTEchoClientApplication>>echoMessage: aMessage

self inform: aMessage

Probando el Echo

Para hacerlo, como sabemos, hay dos maneras, pero vamos a usar la forma directa: http://127.0.0.1:2222/SWTEchoClientApplication.

Y el resultado es:

Screenshot Echo Application

Como podemos apreciar, enviamos un mensaje, le dimos enter, y el cartel nos muestra que escribimos.

Resumen del Echo

En este aplicativo, hemos aplicado lo mismo que para el Ping/Pong, pero con la diferencia que usamos un nuevo control, y sus eventos para generar un ping/pong pero con un mensaje que nosotros indicamos.

Conclusiones

Estos dos mini-aplicativos que presentamos no tenían otra intención que hacer un pequeño uso del framework SWT.
Las aplicaciones que se pueden lograr en esta plataforma son mucho más complejas y ricas. La idea que hay detrás es abstraerse, por medio del framework, de la cantidad de complicaciones que genera un aplicativo web y enfocarse en la resolución adecuada de nuestro problema. Para ello SWT nos provee del lado cliente un mini-Smalltalk hecho sobre Javascript, hay comunicación constante entre servidor y cliente a través de la arquitectura de Comet, hay un framework de Model-View-Controller distribuido que nos permite hacer aplicaciones más desacopladas y optimizadas para funcionamiento sobre la red, y una capa de controles web, que podemos expandir hacia donde necesitemos. Como se puede apreciar, es mucho trabajo el que realiza el framework en aras de conseguir una abstracción adecuada para desarrollar aplicaciones más complejas sobre la web.