Construção de gadgets na plataforma EzWeb
Aluno:
Rafael Sato Suguiura
Orientador:
Flávio Soares Corrêa da Silva
Introdução

Morfeo é uma comunidade de código aberto européia engajada em definir padrões[1] e estimular a inovação e a colaboração em serviços web, provendo soluções para problemas em alguns cenários que vão desde usuários comuns a grandes corporações.[2] Iniciado em maio de 2007, um dos projetos ligados à comunidade pela Telefónica Investigación y Desarrollo (Telefónica I+D)[3] e sob a licença GNU Affero General Public License (GNU AGPL)[4] é a plataforma EzWeb.

A plataforma é um compositor em alto nível de mashups. Um mashup é uma composição não usual ou inovadora de conteúdo, geralmente de fontes diferentes, feita para interação humana.[5] Os dados são normalmente providos por serviços web, também considerado como back-end, e exibidos ao usuário em aplicações, também chamadas de front-end. Denominamos por gadget essa aplicação web, preferencialmente pequena, reutilizável e centradas no usuário.[6]

As idéias por trás do projeto trazem não apenas mais inovação e colaboração, mas abre espaço para destacar possíveis requisitos para que novos padrões e novas tecnologias possam solucionar problemas recorrentes das soluções atuais.

A plataforma EzWeb está sob desenvolvimento, mas as principais partes já estão disponíveis e funcionais, como o catálogo de gadgets, a área de vinculação (wiring) e a área de trabalho. Ela também possui alguns gadgets já implementados, como os de procura e tocador do YouTube, visualizador de fotos do Flikr, visualizador do Twitter, entre outros.

Os gadgets atualmente disponibilizados dificilmente interagem mais complexamente, com três ou mais gadgets funcionando colaborativamente para formar um mashup com uma finalidade bem definida. Um objetivo deste trabalho é justamente construir alguns gadgets simples e um mashup com uma complexidade maior.

Conceitos e tecnologias estudadas
EzWeb

O EzWeb é uma plataforma web implementada em Python, usando o arcabouço de desenvolvimento web Django no lado do servidor, e o arcabouço JavaScript de desenvolvimento de aplicativos web dinâmicas Prototype no lado do cliente.

A plataforma possui um catálogo de gadgets, onde pode-se adicionar ou remover gadgets, que podem ser ordenados a critério de nome, autor, popularidade, data de criação e distrbuidor, ou realizar busca pelas categorias. As informações com relação a um gadget catalogado na plataforma contém seu nome, o distribuidor responsável, sua popularidade, tags que o classificam, com uma breve descrição, opções para se obter gadgets que tenham afinidade pelo tipo de ligações disponíveis, e atalhos para versões anteriores, acesso ao template original, atualização do código HTML na plataforma, remoção do gadget do catálogo e adição de um gadget na área de trabalho.

Detalhes de um gadget

Gadgets podem se comunicar um com os outros quando estão vinculados. Para tanto, são criados vínculos direcionados entre os gadgets na área de vinculação, sendo possível o uso de uma filtragrem simples na mensagem transmitida.

Vinculação de gadgets

Por fim, é na área de trabalho que o usuário pode redimensionar e posicionar os gadgets em alguma de suas abas. Um usuário pode ter zero, uma ou várias áreas de trabalho, que podem ser criadas, removidas, renomeadas, travadas, publicadas ou compartilhadas. Cada área de trabalho pode conter uma ou mais abas. Quando uma área de trabalho é compartilhada, a plataforma disponibiliza ao usuário o endereço referente àquela área, que, neste modo, fica travada, possibilitando seu uso em outras páginas. A publicação é feita de forma a disponibilizar a área de trabalho desenvolvida no catálogo da plataforma.

Área de trabalho

Os gadgets na plataforma EzWeb podem ser qualquer aplicações web, normalmente baseados em uma arquitetura orientada a serviços (SOA).

SOA: Service-Oriented Architecture

Arquitetura de software é uma abstração da organização de um software, independente de tecnologia e implementação, evidenciando papéis, responsabilidades e relações tanto internas como externas. A arquitetura orientada a serviços é uma arquitetura de software onde grandes funcionalidades do aplicativo são obtidas através de serviços. A comunicação com os serviços é feita com troca de mensagens através de protocolos especificados em uma interface bem definida, normalmente recebendo o nome de API (Application Programming Interface).

A troca de mensagens também é independente de implementação, sendo que essas mensagens podem possuir qualquer tipo de dado. Para que essas mensagens possam ser manipuladas mais fácil e padronizadamente, alguns formatos foram criados, sendo XML e JSON dois deles.

XML: Extensible Markup Language

O XML é uma notação simples, flexível e legível aos humanos, criada para armazenar e transmitir dados, estruturados hierarquicamente. A especificação feita pela W3C também possui mecanismos de consulta (XQuery), navegação (XPath) e transformação (XSLT) de documentos XML.

A linguagem de consulta XML (XQuery) é especificada através de expressões de consulta, formadas principalmente por expressões FLWOR (acrônimo correspondente a For, Let, Where, Ordered by e Return), semelhantes ao SQL, provendo um recurso para extrair e interpretar os dados contidos em um documento XML. A linguagem de navegação XML (XPath) provê uma notação de endereçamento através dos nós da árvore de um documento XML. Finalmente, a linguagem de estilo extensível (XSL) é usada para se realizar transformações (XSLT) que reestruturam documentos XML de for a torná-los estilizados e apresentáveis a usuários.

Dois dialetos do XML bastante utilizados para propagação de informações são o ATOM e o RSS.

JSON: JavaScript Object Notation

Objetos em JavaScript são conciderados vetores associativos, onde o valor de cada mapeamento pode ser qualquer valor que uma variável pode receber, ou seja, booleano, número, cadeia de caracteres, arrays, objeto, função, null ou undefined. A sua criação pode ser feita chamando-se new antes de um construtor ou usando-se a notação literal de objetos, ou seja, uma lista de mapeamentos chave/valor, cercada por abre e fecha chaves.

O JSON é um subconjunto na notação literal de objetos, excluindo-se undefined e função como valores aceitos. Uma expressão em JSON pode ser transformado em objeto com uma chamada à função eval, em JavaScript.

Uma ramificação do JSON é o JSONP (JSON with Padding), onde um prefixo, usualmente o nome de uma função, é adicionado à requisição, que é avaliado assim que a transferência da requisição terminar.

Comet

Para que um servidor envie mensagens a um cliente, este precisa abrir um canal de comunicação com aquele. Através de uma conexão HTTP de longa duração, é possível este canal aberto, permitindo ao servidor realizar esta comunicação de uma forma bidirecional. Esta idéia é chamada de Comet, podendo também receber outros nomes, como AJAX push, HTTP server push, entre outros.

O Orbited é um roteador web e firewall com implementação Comet, permitindo conexões TCP, com suporte a alguns protocolos, como IRC (Internet Relay Chat, protocolo para um ambiente de chats), XMPP (Extensible Messaging and Presence Protocol, protocolo para troca de mensagens em XML) e STOMP (Streaming Text Orientated Messaging Protocol, protocolo com um formato interoperacional de comunicação).

JavaScript

Uma linguagem dinâmica é aquela que pode modificar seu comportamento em tempo de execução. O JavaScript, criado pela Netscape e posteriormente especificado pela Ecma Internacional, é uma linguagem dinâmica e interpretada com capacidades de orientação a objetos, herança baseada em protótipos e tipagem dinâmica, além da possibilidade do uso de funções anônimas e de fechamentos.

Apesar de poder ser utilizado em alguns outros contextos, a importância e popularidade do JavaScript vem justamente do seu uso para a atribuição de comportamento em elementos de um documento HTML, viabilizando a idéia de aplicativos web.

Implementação e resultados
Instalação do EzWeb

O EzWeb possui alguns pré-requisitos: um gerenciador de banco de dados (PostgreSQL, MySQL, SQLite e Oracle são suportados), Python 2.4 (ou mais recente) e o correspondente driver para o banco de dados, e Django 1.0 com PyXML 0.8 (ou mais recente). O ambiente de programação para este trabalho foi feita na distribuição Linux Gentoo, sendo que a configuração das ferramentas foi SQLite versão 3.6.18, Python versão 2.6.2-r1, Django versão 1.0.3 e PyXML versão 0.8.4-r2.

O projeto está armazenado em um servidor de controle de versões Subversion (SVN), no endereço do repositório logo abaixo. Para obtê-lo, é necessário um cliente SVN, sendo que o cliente usado no projeto foi o do Tigris.org (atualmente tornando-se um projeto da Apache Software Foundation). O comando utilizado foi o seguinte:

svn co https://svn.forge.morfeo-project.org/svn/ezwebplatform\
/ezweb_platform/src/trunk/
					

Obtido o projeto, foram realizadas apenas duas mudanças no arquivo de configuração settings.py: o valor de DATABASE_ENGINE foi mudado para "sqlite3" e o de DATABASE_NAME para o caminho do arquivo de banco de dados. Assim que a configuração foi feita, é necessário criar e preparar o arquivo do banco de dados, executando o seguinte comando, na raiz do projeto:

$ python manage.py syncdb
					

O comando prepara o esquema das tabelas utilizadas e pergunta ao usuário se este deseja criar um superusuário. Caso positivo, são perguntados o nome de usuário, e-mail, senha e confirmação da senha.

Com o banco de dados criado, é possível executar o projeto com o comando:

$ python manage.py runserver [endereço]:[porta]
					

, sendo [endereço] e [porta] o endereço e a porta da máquina onde se deseja acessar a plataforma, respectivamente.

Instalação do Jetrix

O Jetrix é um servidor TetriNet usado para testes. A versão instalada é 0.2.3 e o único pré-requisito é o JRE 1.5 ou mais recente. Para iniciar o serviço, basta executar, na raiz do Jetrix:

$ ./jetrix
					

Instalação do Orbited

Os pré-requisitos para a instalação do Orbited são o Python 2.5 (ou mais recente), a biblioteca em Python demjson e o Twisted. A versão utilizada, neste trabalho, do demjson é 1.4 e a do Twisted é 8.1.0.

O Orbited deve ser configurado em uma porta para escutar conexões vindos dos clientes, e para redirecionar as conexões da porta 31457, utilizado pelo servidor TetriNET. Conciderando que o servidor TetriNET esteja no mesmo IP, as modificações mais significantes no arquivo de configurações orbited.cfg são as seguintes:

[listen]
http://:8000

[access]
* -> 127.0.0.1:31457
					

Também é possível configurá-lo para hospedar arquivos, com a seguinte adição:

[static]
urlAlias=/path/to/a/directory
					

Para iniciá-lo, basta executar o seguinte, na raiz do projeto:

$ ./start.py
					

Implementando um gadget simples na plataforma EzWeb

A criação de um gadget é realizada através de um template, um arquivo XML contendo os meta-dados do gadget para a publicação no catálogo da plataforma, e o código da implementação do gadget, que pode se um documento HTML ou XHTML.

Template

O template é dividido em alguns blocos conceituais: descrição, variáveis de integração e outros elementos.

O bloco de descrição possui os seguintes campos, relacionados ao gadget: distribuidor (vendor), nome (name), versão atual (version), autor (author), endereço de email do autor (mail), uma breve descrição do gadget (description), endereço da imagem do gadget para exibição no catálogo (imageuri) e endereço para maiores informações sobre o gadget (wikiuri).

A descrição segue o seguinte formato:

<Catalog.ResourceDescription>
  <Vendor>IMEUSP</Vendor>
  <Name>Nome do Gadget</Name>
  <Version>1.0</Version>
  <Author>Rafael</Author>
  <Mail>rafael.suguiura@gmail.com</Mail>
  <Description>
    Este é um exemplo de uma breve descrição do gadget.
  </Description>
  <ImageURI>http://servidor/imagem.png</ImageURI>
  <WikiURI>http://servidor/wiki</WikiURI>
</Catalog.ResourceDescription>
						

O bloco de variáveis de integração é composto por quatro seções: preferências, propriedades de estado, vinculação e contexto.

Preferências podem ser mudadas através da interface oferecida pela plataforma. Cada preferência possui, obrigatoriamente: o nome da preferência (name), que será usado para referenciar a variável no gadget; o rótulo (label), que identificará a preferência na interface ao usuário; a descrição da preferência (description); e o tipo (type), que pode ser texto, número, booleano, senha ou lista. Caso a preferência seja do tipo lista, ela poderá conter um número qualquer de opções, sendo que cada opção deverá conter um nome e um valor associado. Por exemplo, posso limitar o acesso a servidores Tetrinet apenas aos que estiverem na lista:

<Platform.Preferences>
  <Preference
    name="nick"
    type="text"
    description="Apelido"
    label="Apelido"
  />
  <Preference
    name="host"
    type="list"
    description="Servidor"
    label="Endereço do servidor"
  >
    <Option name="Jetrix(localhost)" value="127.0.0.1:31457"/>
    <Option name="TetriNET.no" value="tetrinet.no:31457"/>
  </Preference>
</Platform.Preferences>
						

Já as propriedades de estado são variáveis em que a plataforma permite que valores do gadgets sejam persistidos para cada usuário. Cada propriedade de estado contém os atributos nome, tipo e rótulo, semelhantes aos da preferência, exceto pelo fato do único tipo aceito ser texto. Por exemplo, poderíamos armazenar o IP e a data do último acesso do usuário com o seguinte:

<Platform.StateProperties>
  <Property name="ip" type="text" label="IP do último acesso"/>
  <Property name="date" type="text" label="Data do último acesso"/>
</Platform.StateProperties>
						

As variáveis de vinculação abre canais de comunicação entre gadgets. Existem dois tipos de variáveis de vinculação, o slot, variável esta que recebe mensagens de events, e event, que as envia. Cada variável de vinculação possui os campos nome, tipo, rótulo e código de correspondência (friendcode). Assim como as propriedades de estado, o único tipo aceito é texto. O código de correspondência permite que variáveis de vinculação correspondentes possam ser encontrados mais facilmente através da identificação do código de correspondência das variáveis de vinculação dos outros gadgets. Podemos pegar como exemplo um gadget de chat que envia e recebe mensagens de texto:

<Platform.Wiring>
  <Slot name="income" type="text" label="Message" friendcode="msg"/>
  <Event name="outcome" type="text" label="Message" friendcode="msg"/>
</Platform.Wiring>
						

Um detalhe é que é possível vincular dois gadgets mesmo com códigos de correspondência diferentes.

As variáveis de contexto permitem obter informações sobre o ambiente, sendo ContextGadget a variável que disponibiliza informações sobre o próprio gadget e Context, a que disponibiliza informações externas, sobre a plataforma. Ambas as variáveis possuem tres atributos: nome, tipo e conceito (concept). Aqui, o tipo aceita apenas texto como valor. O conceito provê a semântica à variável, Atualmente, apenas altura (height) e largura (width) são oferecidas para o contexto do gadget, e nome de usuário (user_name) e idioma (language), para o contexto da plataforma. Exemplo:

<Platform.Context>
  <Context name="user" type="text" concept="user_name"/>
  <Context name="language" type="text" concept="language"/>
  <GadgetContext name="height" type="text" concept="height"/>
  <GadgetContext name="width" type="text" concept="width"/>
</Platform.Context>
						

Os outros elementos do template são o endereço do código, que possui um elemento, o XHTML, com apenas o atributo href, que é a referência ao código do gadget; e a renderização, que contém os atributos altura e largura do gadget. Exemplo:

<Platform.Link>
  <XHTML href="http://servidor/gadget.html" />
</Platform.Link>
<Platform.Rendering width=“5" height="7" />
						

Implementação

A implementação do gadget na plataforma utiliza o JavaScript para a utilização das variáveis descritas no template. As variáveis são acessíveis através de uma biblioteca, também em JavaScript, fornecida pela plataforma, o EzWebAPI.

A API dispõe de dois métodos para tratamento das variáveis: o createRGadgetVariable, para criação de objetos para variáveis de leitura apenas e createRWGadgetVariable, para leitura e escrita. Os dois métodos tem o nome da variável como parâmetro. Porém, o método createRGadgetVariable recebe um segundo parâmetro que é uma função de tratamento. Essa função é chamada sempre que há uma mudança de valor da variável ao qual está associada. Quando isso acontece, ela é chamada com um parametro, o novo valor desta variável.

As variáveis de leitura apenas são o slot, as variáveis de preferência, e as de contexto. Já as variáveis de leitura e escrita são o event e as de propriedades de estado.

O objeto devolvido por esses métodos possuem o método get e, para as variáveis de escrita, o método set. Este possui um parâmetro, o novo valor da variável, enquanto aquele não possui parametros, mas devolve o valor da variável.

Assim, para as variáveis de propriedades de estado do exemplo da seção anterior, posso obter o valor do IP anterior e atribuir um novo valor da seguinte forma:

var ipVariable = EzWebAPI.createRWGadgetVariable("ip");
var oldIpValue = ipVariable.get();
var newIpValue = "127.0.0.1";
ipVariable.set(newIpValue);
						

Já um código para o tratamento da variável de contexto, também tomando o exemplo da seção anterior, é o seguinte:

var handler = function (username)
{
  alert("Olá, " + username + "!");
};
var userVariable = EzWebAPI.createRGadgetVariable("user", handler);
						

XMLHttpResquest

Um objeto XMLHttpResquest permite a comunicação do cliente com o servidor através das chamadas HTTP usando métodos post, get, put e delete. Porém, devido a questões de segurança, essas chamadas são restritas apenas ao mesmo domínio da página. Contudo, com o uso do serviço da plataforma EzWeb como intermediário, é possível contornar tal restrição utilizando respectivos métodos que a biblioteca também disponibiliza: send_post, send_get, send_put e send_delete.

jQuery

O jQuery é uma biblioteca JavaScript que oferece açúcares sintáticos para obter elementos DOM, tratamento de eventos, animação e AJAX. Com a biblioteca, é possível selecionar elementos DOM usando a sintaxe da linguagem CSS. A documentação mais detalhada pode ser encontrada no site do jQuery em http://docs.jquery.com/, mas uma breve descrição dos comandos mais utilizados vem a seguir:

$("div")
Seleciona todos os elementos do tipo "div".
$("div.box")
Seleciona todos os elementos do tipo "div" cuja classe é "box".
$("div #username")
Seleciona todos os elementos descendentes de algum elemento "div", cujo ID é "username".
$("div #username").css("background", "blue")
Para todos os elementos selecionados, muda o atributo "background" do CSS para "blue".
$("div #username").html("<input type='text' name='username'>")
Açúcar sintático para $("div #username").innerHTML(...).
Exemplo de implementação: TinyURL

O TinyURL oferece um serviço de redução de links, recebendo um endereço e devolvendo um código correspondente, único e determinístico.

Para facilitar a organização da implementação, o código JavaScript deste gadget foi dividido em três arquivos: ezweb.js, app.js e url.js. O ezweb.js é um açúcar sintático para a criação de variáveis do EzWeb, disponibilizando a função createGadgetVariable, cujos parâmetros são o nome da variável EzWeb e opcionalmente um método de tratamento (caso esse método seja dado, ele tenta criar uma variável de leitura apenas; caso contrário, ele tenta criar uma variável de leitura e escrita); o app.js faz todo o controle do aplicativo; e url.js faz o tratamento das variáveis do EzWeb:

url.js:

// Cria o namespace CONNECTOR, caso não exista.
var CONNECTOR = CONNECTOR || {};

// Instancia o objeto assim que todo o documento estiver pronto.
$(document).ready(function(){CONNECTOR.url = new CONNECTOR.Url();});

// Construtor.
CONNECTOR.Url = function()
{
  this.wire = EZWEB.createGadgetVariable("urlIn", this.handler);
  this.wire = EZWEB.createGadgetVariable("urlOut");
};

// Trata o URL recebido de algum outro gadget.
CONNECTOR.Url.prototype.handler = function(url)
{
  TINYURL.app.load(url);
};

// Envia o URL para outro gadget.
CONNECTOR.Url.prototype.send = function(url)
{
  this.wire.set(url);
}
						

app.js:

// Cria o namespace TINYURL, caso não exista.
var TINYURL = TINYURL || {};

// Instancia o objeto assim que todo o documento estiver pronto.
$(document).ready(function(){TINYURL.app = new TINYURL.App();});

// Construtor.
TINYURL.App = function()
{
  this.element = $("#tinyurl");
};

// Escreve o html no elemento.
TINYURL.App.prototype.html = function(html)
{
  this.element.html(html);
};

// Envia uma mensagem para o send_get e, caso seja executado com sucesso,
// chame o método tryGet. Caso contrário, chame o método this.catchGet.
TINYURL.App.prototype.load = function(url)
{
  var requestURL = "http://tinyurl.com/api-create.php?url=" + url;
  this.html("<p>Loading...</p>");
  EzWebAPI.send_get(requestURL, this, this.tryGet, this.catchGet);
};

TINYURL.App.prototype.tryGet = function(res)
{
  var url = res.responseText;
  var html = '<a href="javascript:CONNECTOR.url.send(\'" + url + "\');">';
  html += url;
  html += '</a>';
  this.html(html);
};

TINYURL.App.prototype.catchGet = function(res)
{
  this.html("Error: could not get the url!");
};
						

Note que o método load se utiliza da intermediação do serviço da plataforma para realizar uma requisição em outro domínio, o do TinyURL. A resposta é dada em um texto simples e sem formatação.

index.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <link type="text/css" rel="stylesheet"
      href="/files/tinyurl/style.css">

    <!-- libraries -->
    <script type="text/javascript"
      src="/files/EzWebAPI.js">
    </script>
    <script type="text/javascript"
      src="/files/jquery-1.3.2.min.js">
    </script>

    <!-- utilities -->
    <script type="text/javascript"
      src="/files/ezweb.js">
    </script>
    <!-- application -->
    <script type="text/javascript"
      src="/files/tinyurl/app.js">
    </script>
    <!-- connectors -->
    <script type="text/javascript"
      src="/files/tinyurl/connector/url.js">
    </script>
  </head>

  <body>
    <div id="tinyurl"></div>
  </body>
</html>
						

template.xml:

<Template schemaLocation="http://morfeo-project.org/2007/Template">
  <Catalog.ResourceDescription>
    <Name>TinyURL</Name>
    <Version>1.1</Version>
    <Author>Rafael</Author>
    <Mail>rafael.suguiura@gmail.com</Mail>
    <Vendor>IMEUSP</Vendor>
    <Description>A TinyURL generator</Description>
    <ImageURI>/files/tinyurl/image.png</ImageURI>
    <WikiURI>http://www.ime.usp.br/</WikiURI>
  </Catalog.ResourceDescription>

  <Platform.Wiring>
    <Slot name="urlIn" type="text" label="url" friendcode="url" />
    <Event name="urlOut" type="text" label="url" friendcode="url" />
  </Platform.Wiring>

  <Platform.Link>
    <XHTML href="/files/tinyurl/index.html" />
  </Platform.Link>
  <Platform.Rendering width="3" height="3" />
</Template>
						

Para adicionar o gadget ao catálogo da plataforma, é preciso clicar na opção "Development Options", na aba "Add Gagets". O endereço do template deve ser colocado na entrada de texto de "Template URL" e, em seguida, adicionado ao catálogo ao se clicar em "Create resource".

Lista de Vídeos relacionados do YouTube

O gadget de lista de vídeos relacionados do YouTube segue a mesma estrutura do gadget de links reduzidos do TinyURL. Devido à complexidade do conjunto de dados providos pelo serviço do YouTube, esses dados vem estruturados, tanto em dialetos do XML, como ATOM ou RSS, como JSON ou JSONP.

A especificação da estrutura dos dados está especificado em http://code.google.com/apis/gdata/docs/json.html, sendo que o formato do pedido dado em http://code.google.com/apis/youtube/2.0/reference.html#Related_videos_feed.

YouTube Related Videos List
Transformador XSL

O gadget transformador XSL recebe o endereço de um arquivo XML e um correspondente transformador XSL, exibindo o resultado no corpo do gadget. O gadget utiliza uma implementação de XSL-T em javascript através do arcabouço AJAXSLT.

TetriNET

O TetriNET é uma modificação multi-jogador do jogo Tetris, permitindo até 6 jogadores simultaneamente, criado em 1997. O jogo possui, além da mecânica do Tetris, blocos especiais que adicionam comportamento ao campo do jogador alvo. Este projeto se baseou na versão 1.13 do jogo original, através do projeto de código aberto GTetrinet (versão 0.7.11), implementado em C usando o arcabouço GTK.

GTetrinet
Organização
O jogo foi dividido em componentes, sendo que cada componente, representada por um gadget, responde a uma funcionalidade específica do jogo.
Orbited
Gadget para a camada de comunicação com o servidor Orbited, disponibilizando as mensagens recebidas para outros gadgets.
Tetrinet
Gadget que interpreta e distribui as mensagens recebidas. Este gadget também armazena informações pertinentes ao jogo como um todo, como o nome, o time e o campo de cada usuário.
TetrisEngine
Implementação da mecânica do jogo.
TetrisInterface
Interface para a interação com o usuário. Cabe a este gadget interceptar os comandos de jogo dados pelo usuário, dados pelo teclado.
TetrisFields
Exibe os campos dos jogadores.
Logger
Exibe eventos de texto.
Sender
Envia mensagens para a sala de bate-papo.
List
Exibe uma lista de itens.
Protocolo do Tetrinet e mecânica de jogo

A comunicação é feita através do protocolo TCP. Os comandos utilizados na comunicação deste projeto são os seguintes:

noconnecting
Mensagem dada pelo servidor, caso a conexão do cliente não possa ser estabelecida.
playernum
Assim que o cliente conecta ao servidor, o cliente recebe um número entre 1 e 6 para a identificação do jogador.
playerjoin
Sinaliza a entrada de um jogador.
playerleave
Sinaliza a saída de um jogador.
disconnect
Envia a mensagem ao servidor, avisando que o cliente está desconectando.
pline
Comando para o envio e recebimento de mensagens dos usuários na sala de bate-papo.
plineact
Semelhante ao pline, mas ao invés de mensagens, o texto é exibido no formato de ações.
startgame
Inicia ou termina um jogo de acordo com o parâmetro utilizado.
pause
Pausa ou continua o jogo, caso este estiver pausado.
f
Envia ou recebe o conteúdo de um campo.
sb
Envia ou recebe um bloco especial.

Assim que o canal de comunicação é aberta, a conversa é iniciada enviando um código inicial, resultado de uma função hash que usa como parâmetros o IP do cliente e a concatenação que identifica a versão do cliente com o apelido do jogador. Este código não possui um comando associado e é enviado na mesma forma que foi gerado. Porém, um jogador não pode conectar no servidor caso já exista um outro jogador já conectado com o mesmo apelido que ele escolheu. Caso isto ocorra, o jogador que não conseguir conectar é notificado através da mensagem dada pelo comando noconnecting.

Caso o cliente consiga conectar com sucesso, o cliente recebe o número de identificação através do comando playernum. Se o jogador possuir o menor número de identificação, este obtém a responsabilidade de iniciar, pausar ou parar um jogo. Porém, se ele possuir esta responsabilidade e um outro jogador conectar ao servidor, sendo notificado através do playerjoin, e obter um número de identificação menor, então estas operações passam a ser responsabilidades deste novo jogador. O oposto também ocorre, quando um jogador fica com o menor número de identificação quando outro jogador, que mantinha o menor número de identificação, sair, sendo esta operação notificada pelo comando playerleave.

Durante todo o momento em que o jogador permanecer conectado, ele pode enviar e receber mensagens e realizar e notificar ações na sala de bate-papo, através dos comandos pline e plineact, respectivamente.

Com um jogo iniciado, através de startgame, cada cliente envia o estado do seu campo usando o comando f. O parâmetro de f pode ter duas formas: uma cadeia de caracteres sendo que cada caracter representa um bloco da serialização simples de um campo; ou a diferença do campo anterior com o campo atual, contendo os códigos e as posições dos blocos que foram modificados.

O envio de um bloco especial pode ser feito a qualquer momento, enquanto o jogador ainda estiver em jogo e possuir blocos especiais na fila, com o comando sb. O bloco é ativado quando o jogador pressionar o número correspondente ao jogador alvo. Cada bloco especial é descrito a seguir:

a
Adiciona uma linha ao jogador alvo. Esta linha é preenchida de blocos normais, com a exceção de 1, 2 ou 3 posições, que são deixados vazios (blocos vazios), e é adicionada na parte de baixo do campo, descolando todas as linhas já existentes para cima. Caso a linha do topo possuir algum bloco, o jogador perde o jogo.
c
Em oposição ao bloco especial "a", este bloco especial remove a linha de baixo e desloca todas as linhas uma posição abaixo.
n
Remove todos os blocos do campo, transformando-os em blocos vazios.
r
Remove até 10 blocos, em posições aleatórias, do campo.
s
Troca de campo com outro jogador.
b
Transforma todos os blocos especiais do campo alvo em blocos normais.
g
Aplica o efeito de gravidade. Move todos os blocos do campo uma posição abaixo, caso esta posição estiver vazia, até que não haja um bloco com uma posição vazia abaixo dele.
q
Para cada linha, desloca a linha no sentido horizontal, circularmente, em uma a três posições.
o
Para cada bloco especial "o" que estiver no campo alvo, desloca os blocos adjacentes a ele para posições aleatórias no campo.

O jogo de um jogador termina na condição do bloco especial "a" ou quando não for possível movimentar um bloco a partir de sua posição inicial. Quando todos os jogadores oponentes perderem, o jogador ou a equipe que permanecer é declarado ganhador da partida.

Interface do usuário

A implementação da interface do usuário para cada gadget foi feita buscando-se exibir apenas as informações relevantes ao usuário. Todo o tratamento de elementos no documento foi feito utilizando o arcabouço jQuery e da linguagem de estilos CSS. A seguir, segue uma descrição sobre a implementação de cada gadget:

Orbited
As únicas ações permitidas ao usuário, neste gadget, são as ações de conectar e desconectar, em botões que se alternam. Porém, para tanto, é preciso escolher e salvar previamente em qual servidor ele deseja se conectar no menu de preferências do gadget. Além dos botões, são exibidos mensagens de alerta e estado da conexão.
Tetrinet
Este gadget possui campos para preenchimento de apelido e equipe. O campo apelido deve ser preenchido antes que a conexão do Orbited seja efetuada. Assim que a conexão seja feita, o campo apelido é bloqueado e, caso o jogador seja responsável pelo controle de jogo, o botão start é exibido e, quando estiver em jogo, este botão é ocultado e os botões pause e stop são exibidos, sendo que pause é alternado com unpause quando o jogo for pausado e vice-versa.
TetrisEngine
Exibe o estado do jogo e os tetrominos atual e próximo.
TetrisInterface
Exibe o campo de tetris do jogador. Também é este gadget que recebe os eventos do teclado.
TetrisFields
Exibe o campo de tetris de todos os jogadores.
Logger
Apenas exibe mensagens de outros gadgets, com a adição da data e do horário do recebimento.
Sender
Possui apenas um campo de entrada de texto, sendo que este é enviado assim que o enter é pressionado.
List
Exibe duas lista, uma lista de jogadores conectados e outra lista de blocos especiais disponíveis.
Comunicação entre gadgets

À parte da implementação do gadget responsável pelo tratamento da comunicação entre outros gadgets na plataforma foi dado o nome de conector. Um conector realiza o envio e o tratamento das mensagens recebidas com relação a apenas um dos gadgets com que o gadget se comunica.

Abaixo estão as descrições dos dados enviados pelos gadgets, por pares que trocam informações bidirecionalmente:

Orbited ↔ Tetrinet
Mensagens do protocolo usado pelo Tetrinet.
Tetrinet ↔ Partyline
Troca de mensagens de texto simples.
Tetrinet ↔ TetrisEngine
Ações de comando da mecânica do jogo, como início e fim de jogo, atualizações de campo e blocos especiais.
TetrisEngine ↔ TetrisInterface
Atualizações de campo e comandos do jogo.
Algumas comunicações unidirecionais são as seguintes:
Tetrinet → PlayerList
Lista de nome dos jogadores.
Tetrinet → TetrisField
Serialização do estado de um campo.
TetrisEngine → SpecialList
Lista de blocos especiais.
Conclusões

A tecnologia de comunição em tempo real oferecido pelo Orbited tornou possível a elaboração de um cliente Tetrinet, na forma de um mashup com um grau de complexidade maior, tanto com relação à interação (comunicação) entre os gadgets envolvidos, como a ferramentas e as técnicas utilizadas para o seu desenvolvimento.

Apesar da maior complexidade do mashup, que, como exercício acadêmico, não seguiu à risca toda a ideologia da plataforma, como se utilizar de serviços web, é possível dividir um gadget no blocos conceituais de exibição, obtenção de dados e comunicação com outros gadgets, facilitando a organização do código na criação de gadgets para serviços web. Uma ilustração desta divisão é feita a seguir:

Cada uma dessas divisões pode ser considerada uma componente do gadget que se comunicam internamente, cada um obtendo e repasando informações conforme estes lhe são atribuídos. Ressaltando essa conectividade e ampliando o escopo da organização, temos o seguinte diagrama:

Uma maior complexidade se deve ao tratamento dos dados, à forma de exibição e interação do usuário com a interface do gadget, e à influencia das mensagens de outros gadgets no aplicativo.

O fato do JavaScript ser uma linguagem interpretada e possuir uma tipagem dinâmica trouxe um grau de complexidade maior ao desenvolvimento do mashup, quanto à sua depuração. Uma ferramenta bastante utilizada para a verificação do código deste projeto foi o JSLint. O verificador, implementado em JavaScript, alerta sobre diversos erros de sintaxe, apontando também diversas práticas que possam levar a erros em JavaScript. Usar a engine JavaScript SpiderMonkey, implementada em C, tornou a verificação mais rápida do que a verificação realizada no navegador ou no Rhino, outra engine JavaScript, implementada em Java.

Referências
  1. Morfeo PROJECT (link)
  2. Lizcano, David. et al. The Morfeo Open Source Community: Building Technologies of the Future Web through Open Innovation (link)
  3. EzWeb | Telefónica Investigación y Desarrollo (link)
  4. GNU AFFERO GENERAL PUBLIC LICENSE (link)
  5. Mashups: The new breed of Web app (link)
  6. Ureña, Marcos. EzWeb Platform, A web 2.0 approach (link)
  7. Stevens, Michael. Service-Oriented Architecture Introduction, Part 1 (link)
  8. Russell, Alex. Comet: Low Latency Data for the Browser (link)
  9. Flanagan, David. JavaScript: The Definitive Guide, 5th Edition
  10. Crockford, Douglas. The Little JavaScripter (link)
Recursos
  1. Extensible Markup Language (XML) (link)
  2. Extensible Stylesheet Language (XSL) Version 1.1 (link)
  3. XML Path Language (XPath) Version 1.0 (link)
  4. XQuery 1.0: An XML Query Language (link)
  5. The Atom Syndication Format (link)
  6. RSS 2.0 Specification (link)
  7. Introducing JSON (link)
  8. Orbited - Networking for the Web (link)
  9. Standard ECMA-262 ECMAScript Language Specification (link)
  10. jQuery (link)
  11. Document Object Model (DOM) (link)
  12. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification (link)
  13. TinyURL.com (link)
  14. YouTube (link)
  15. AJAXSLT (link)
  16. GTetrinet (link)
  17. JSLint, The JavaScript Code Quality Tool (link)
  18. SpiderMonkey (JavaScript-C) Engine (link)
  19. Rhino: JavaScript for Java (link)
  20. XMLHttpRequest (link)
  21. Servidor de demonstração do EzWeb (link)
  22. Jetrix TetriNET Server (link)
Experiências no projeto

O projeto começou com a proposta do Flávio em estudar a plataforma, quando, após implementar alguns gadgets iniciais, surgir a idéia da implementação do TetriNET. As primeiras implementações eram extremamente demoradas, sendo que o teste para verificar uma mudança pequena chegava a demorar um minuto(!), um tempo enorme quando se está acostumado a compilações praticamente instantâneas. Esse problema foi superado ao utilizar usa organização que dependa o menos possível da plataforma, enviando os códigos JavaScript para arquivos externos e usando a opção do Firefox de atualizar apenas um determinado frame.

Apesar de ter começado com bastante antecedência, o projeto começou a tomar alguma forma no final do primeiro semestre do ano, quando a implementação do mashup foi iniciada. Antes disso, procurei por serviços web que possam ser interessantes, entre eles os serviços oferecidos pelo Wikipedia, pelo AIM e pelo Bovespa, todos com oferecimento de algum tipo de informação, sendo que a não implementação delas foram as mais frustantes. Houve um motivo para cada um dos gadgets: em meio ao desenvolvimento do gadget do Wikipedia, o servidor de demonstração do EzWeb recebeu a submissão de um gadget seguindo a mesma idéia; já o serviço de mensagens instantâneas do AIM utiliza um código de reprodução de gadgets próprio, um ambiente complexo e encapsulado onde não consegui uma documentação para melhor explorá-lo (com este gadget já havia a pretenção em fazer algum tipo de comunicação em tempo real); e finalmente, o gadget do Bovespa foi feito procurando por alguma forma de se obter alguma informação da bolsa, sendo que, na época, não havia um oferecimento oficial dessas informações (o serviço era oferecido, mas não havia menção a ele no site da Bovespa). Mais tarde, ao dar os toque finais aos gadgets, este passara a não mais funcionar, já que a Bovespa havia reformulado a estrutura do seu site e, portanto, o gadget foi abandonado mesmo depois de estar pronto.

Este projeto exigiu um esforço grande no que diz respeito à busca e à quantidade de informações. Utilizar tecnologias e padrões requer, além de aprender sobre elas, aprender ou ter pelo menos alguma noção sobre as tecnologias e padrões relacionadas a elas.

Utilizar as férias de inverno para o projeto deu um enorme impulso no andamento do trabalho, mas, em compensação, toda a energia que normalmente seria recuperada nesse período não foi obtido, além de ter o esforço extra do trabalho efetuado. Dependendo da situação, essa energia pode fazer falta em algum momento.

O ideal seria disponibilizar este trabalho no servidor do Projeto Morfeo, que já possui diversos outros gadgets catalogados. Porém, devido à restrição de domínio do XMLHttpRequest, a biblioteda do Orbited não consegue acessar o ser servidor. Houve uma tentativa frustrada de se utilizar um iframe, com um documento com a biblioteca do Obited no domínio do servidor, e fazer uma comunicação entre os frames, mas sem sucesso. Para a viabilização da disponibilização, seriam necessárias as instalações tanto do servidor do Orbited como o da plataforma EzWeb no mesmo domínio, ou então implementar modificações na plataforma e na biblioteca, adaptando-a à plataforma.

Apesar de tudo, o projeto teve foi desafiadora pela complexidade dada pela junção de uso de ferramentas não tão complexas, mas que trazem semânticas que precisam ser organizadas e trabalhadas.

Disciplinas relevantes
Estrutura de dados

Estruturas simples de dados foram utilizadas para a implementação, como pilhas e filas.

Laboratório de Programação I

O conhecimento sobre algumas ferramentas utilizadas, e a experiência adquirida nesta disciplina contribuíram para a busca de alternativas que auxiliaram no projeto.

Conceitos Fundamentais de Linguagens de Programação

A disciplina permitiu distinguir algumas características do JavaScript, inclusive no que diz respeito a funções anônimas, escopos e fechamentos.

Engenharia de Software

Estruturar, programar e documentar de modo congruente e claro, levando em conta não apenas os requisitos funcionais, foram as influências desta disciplina no projeto.

Observações

Algumas disciplinas que poderiam ter contribuído para o projeto, mas que não foram cursadas foram a Programação Orientada a Objetos, uma vez que suas técnicas poderiam ser utilizadas na programação em JavaScript, e, em um grau bem maior, Sistemas de Middleware, que cobre muitos tópicos relacionados ao projeto.

Próximos Passo

Os próximos passos a serem tomados para a continuidade do projeto seria o estudo de outras tecnologias e outros padrões, como o BOSH (Bidirectional-streams Over Synchronous HTTP), XMPP (Extensible Messaging and Presence Protocol), Message Brokers, WSDL, entre outros.

A cultura de gadgets tem um grande potencial com a vinda da versão 5 da especificação do HTML. Apesar da web ser o maior propulsor, outras interfaces, como os celulares e as TVs digitais também poderiam se utilizar dessa idéia.

Além do EzWeb, existem diversos outros ambientes baseados em gadgets, como o iGoogle, o site da BBC e a área de trabalho do Windows. Porém, os gadgets desses ambiente não influenciam ou pouco influenciam outros gadgets. Uma nova plataforma a ser lançada pela Google tras um ambiente fortemente baseado em gadgets, em rede de contatos e em comunicação em tempo real, ambiente este que poder ser estudado e nomeado de Wave.

Existe outro projeto da Google para ambientação virtual em 3D para navegadores, programado em JavaScript, entitulado O3D