SlideShare uma empresa Scribd logo
1 de 51
Baixar para ler offline
Eduardo Cereto Carvalho




Rich Internet Applications com clientes offline
               utilizando Gears




               Itatiba - São Paulo - Brasil
                     Junho de 2009
Eduardo Cereto Carvalho




Rich Internet Applications com clientes offline
               utilizando Gears

                          Monografia, apresentada à disciplina Trabalho
                          de Conclusão de Curso II do curso de Engenha-
                          ria da Computação da Universidade São Fran-
                          cisco, sob a orientação do Prof. Rodrigo Cha-
                          vez M. do Prado, como exigência parcial para
                          conclusão do curso de graduação.




                        Orientador:
              Rodrigo Chavez M. do Prado




        G RADUAÇÃO EM E NGENHARIA DA C OMPUTAÇÃO
               U NIVERSIDADE S ÃO F RANCISCO




                 Itatiba - São Paulo - Brasil
                       Junho de 2009
i




                                         Sumário


Lista de Figuras                                                                                p. iii


Resumo                                                                                          p. iv


Abstract                                                                                         p. v


1 INTRODUÇÃO                                                                                     p. 1

   1.1     Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 3

           1.1.1   Objetivos Específicos . . . . . . . . . . . . . . . . . . . . . . . . . .      p. 3


2 ASPECTOS TEÓRICOS                                                                              p. 4

   2.1     Evolução das Aplicações Web . . . . . . . . . . . . . . . . . . . . . . . . .         p. 4

           2.1.1   Páginas Estáticas . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 4

           2.1.2   Páginas com Conteúdo Multimídia . . . . . . . . . . . . . . . . . . .         p. 4

           2.1.3   Aplicações Ricas da Internet . . . . . . . . . . . . . . . . . . . . . .      p. 5

           2.1.4   Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 5

           2.1.5   HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .       p. 6

   2.2     Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    p. 7

           2.2.1   Ajax e DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .        p. 7

   2.3     Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 9

           2.3.1   Módulos do Gears . . . . . . . . . . . . . . . . . . . . . . . . . . .       p. 10

           2.3.2   Arquitetura de Sistemas Baseados em Gears . . . . . . . . . . . . . .        p. 10


3 METODOLOGIA                                                                                   p. 14
ii


   3.1   Aplicação de anotações . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    p. 14

   3.2   Aplicação em Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 14

         3.2.1   Estrutura Básica de Sistemas Django . . . . . . . . . . . . . . . . .       p. 15

         3.2.2   Implementando Ajax . . . . . . . . . . . . . . . . . . . . . . . . . .      p. 17

   3.3   Implementação do Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . .      p. 19

         3.3.1   Implementação Modal ou Amodal . . . . . . . . . . . . . . . . . . .         p. 20

         3.3.2   Conteúdo Estático . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 20

         3.3.3   Identificando Estado Online/Offline . . . . . . . . . . . . . . . . . .       p. 22

         3.3.4   Camada de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . .       p. 23

         3.3.5   Sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   p. 24


4 CONCLUSÃO                                                                                  p. 28

   4.1   Análise da Arquitetura Proposta . . . . . . . . . . . . . . . . . . . . . . . .     p. 28

   4.2   Contribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   p. 28

   4.3   Dificuldades Encontradas . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 28

   4.4   Propostas de Extensão . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 29


Referências Bibliográficas                                                                    p. 30


Apêndice A -- Aplicação em Django utilizando Gears                                           p. 31

   A.1 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   p. 31

   A.2 Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    p. 33

         A.2.1 Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      p. 34

         A.2.2 Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     p. 36
iii




                         Lista de Figuras

1   Arquitetura tradicional de aplicações Web . . . . . . . . . . . . . . . . . . .       p. 11

2   Diagrama de sequência tradicional para aplicações Web . . . . . . . . . . . .         p. 11

3   Arquitetura proposta pelo Gears . . . . . . . . . . . . . . . . . . . . . . . .       p. 12

4   Diagrama de sequência para aplicações Web baseadas em Gears . . . . . . .             p. 13

5   Confirmação para permitir que a aplicação use o Gears para guardar dados . .           p. 19

6   Tela listando todas as notas. . . . . . . . . . . . . . . . . . . . . . . . . . . .   p. 31

7   Tela mostrando uma determinada nota. . . . . . . . . . . . . . . . . . . . . .        p. 32
iv




                                     Resumo

    “Aplicações Ricas da Internet” é o nome dado às aplicações Web que fazem uso pesado de
Javascript para implementar uma interface dinâmica provendo uma experiência similar a das
aplicações desktop convencionais.
    Este trabalho mostra um pouco da história das aplicações Web, e especula sobre o futuro,
fazendo um estudo de tecnologias emergentes como o Gears que trazem novas possibilidades a
essa plataforma.
v




                                      Abstract

    “Rich Internet Applications” is the name for the Web applications that make heavy use
of Javascript to implement dynamic interfaces providing a user experience similar to a regular
Desktop Application.
    This work shows the history of Web applications, and discusses about the future of the Web
as an application platform. Also it explores emerging technologies such as Gears that bring new
features to this platform.
1




1        INTRODUÇÃO



    Nos últimos anos pudemos vivenciar a popularização de hardware e Internet em todo o
mundo. É comum hoje em dia o indivíduo ter um computador desktop em casa, um notebook
para o trabalho e mais aquele computador da namorada que ele usa nos finais de semana. Seus
arquivos acabam espalhados em diversos computadores e pen drives. Alguém distraído pode
facilmente se perder em meio às diferentes versões de arquivos que vão sendo criadas ao longo
do tempo. Agora imagine fazer backup de tudo isso de uma maneira organizada. Pode-se pensar
em muitas soluções para estes problemas, dentre elas: criar um servidor FTP em um servidor
pago para centralizar tudo, usar um pen drive para ter mobilidade e manter backups nos diversos
computadores ou ainda criar um elegante sistema de versões mantendo repositórios distintos que
iriam sendo mesclados usando uma ferramenta de controle de versões como o GIT. Cada uma
dessas soluções tem um problema, seja ele um ponto único de falha, um custo monetário mensal
ou um grau de complexidade elevado. Mas com certeza nenhuma delas é uma solução trivial o
suficiente para ser amplamente utilizada pelo usuário final.

    A computação nas nuvens [Miller 2008] surge para resolver este problema. Esse novo
conceito de computação propõe que todos os dados e, às vezes, até mesmo as aplicações fiquem
na Internet. As empresas como o Google começam a oferecer muitos Giga Bytes grátis para
que o usuário possa guardar seus e-mails no Gmail ou documentos no GoogleDocs. Esses são
dois exemplos onde tanto os dados quanto a aplicação estão nas nuvens, ou seja, nos servidores
do Google. Tudo é facilmente acessível de um navegador, onde quer que o usuário esteja. É
fácil, é confiável, é seguro e é muito funcional.

    Com a disseminação da computação nas nuvens o computador pessoal deixou de rodar as
aplicações e guardar os dados passando a ser apenas uma janela para a Internet. Na prática só
se precisa de um Sistema Operacional (SO) e um navegador para ter acesso a um mundo de
aplicações como editores de imagem, planilhas eletrônicas, editores de texto, e-mail, etc. As
aplicações desktop ficaram um tanto ameaçadas porque é improvável que elas consigam ofere-
cer em curto prazo as vantagens da computação nas nuvens. Porém as aplicações na Internet
2


têm a desvantagem de estar atreladas ao navegador e por isso ter certas limitações. Volta-se
a era dos terminais burros e mainframes, com os dados e aplicações centralizadas na Internet
e os computadores fazendo o papel dos terminais burros. Os computadores de hoje são muito
superiores, em termos de recursos, aos terminais burros de antigamente, porém esses recursos
são muito mal utilizados nas aplicações Web. A falta de acesso direto ao SO não permite que
as aplicações acessem o sistema de arquivos ou façam algum processamento mais complexo
em paralelo. Todas estas aplicações estão presas ao protocolo HTTP que é simples e sem es-
tado [Tanenbaum e Steen 2007] além de linguagens script para processamento client side muito
lentas se comparado a uma biblioteca nativa. Caso o usuário esteja em um local sem Internet
todos os seus documentos estão inacessíveis e seu computador passa a ser um peso de papel.

    Além disso a questão da usabilidade é importante já que as interfaces das aplicações Web
são diferentes das interfaces de programas desktop equivalentes, o usuário pode sentir difi-
culdade em se acostumar ao novo ambiente, o que pode gerar uma queda de produtividade
expressiva [Krug 2005].

    Algumas iniciativas vêm sendo tomadas para integrar as aplicações Web ao desktop a fim de
eliminar ou reduzir estas desvantagens das aplicações Web. Algumas empresas lançaram seus
produtos em caráter experimental usando suas próprias abordagens para o problema. A Adobe
criou o AIR que permite criar aplicações Web em Flash e ActionScript que rodam como se fos-
sem aplicações nativas, se aproveitando de recursos como aceleração 3D enquanto o Google,
com o seu Gears, teve uma abordagem diferente privilegiando a possibilidade de guardar arqui-
vos no lado do cliente e fazer processamento Javascript em paralelo.

    A integração tem um papel tanto de usabilidade, trazendo transparência no acesso à apli-
cação Web, quanto em termos de funções, já que as aplicações desktop não estão presas ao
navegador especificamente. Por isso tem mais liberdade de acesso aos recursos da máquina.
3


1.1    Objetivos

    O objetivo deste documento é fazer uma análise da evolução das aplicações Web e como o
Gears pode resolver limitações desta plataforma, introduzindo funcionalidades novas.


1.1.1 Objetivos Específicos

   • Usar o Gears para contornar limitações das aplicações Web.

   • Mostrar como o uso de um framework forte facilita a criação de aplicações mais ricas.

   • Estudar os problemas mais comuns na implementação do Gears.
4




2         ASPECTOS TEÓRICOS



2.1     Evolução das Aplicações Web

    De maneira geral a evolução das aplicações Web pode ser definida em 3 fases distin-
tas [Taivalsaari e Ingalls 2008].


    • Páginas "clássicas", apenas com texto e imagens estáticas.

    • Páginas multimídia, com animações e conteúdo multimídia com o uso de plugins.

    • Rich Internet Applications ou Aplicações Ricas da Internet.


2.1.1 Páginas Estáticas

    Nos primórdios a Web era usada para manter arquivos HTML estáticos que possuíam links
entre eles. Era como um livro gigantesco, no qual o usuário tinha a opção de pular direto para a
seção que mais lhe interessava com facilidade.

    Este modelo foi se modernizando e as páginas começaram a se tornar dinâmicas. Lingua-
gens simples eram usadas para gerar as páginas antes estáticas. Lentamente foram surgindo
linguagens e frameworks focados na Web e a arquitetura dos sites foi se tornando cada vez mais
complexa.


2.1.2 Páginas com Conteúdo Multimídia

    Mesmo com as páginas sendo geradas dinamicamente a interface do usuário ainda era está-
tica. O usuário clicava num link e isso acarretava num recarregamento da página. Com o tempo
foi surgindo a necessidade de adicionar dinamismo a interface do usuário.

    Os Java applets e o Flash deram essa possibilidade ao desenvolvedor. Os sites podiam ser
melhor customizados. Animações, som e vídeo abriam um novo leque de possibilidades para
5


os webdesigners.

    Este modelo exigia que o usuário instalasse um plugin proprietário no navegador, caso con-
trário este não conseguiria acessar o conteúdo. Porém não era mais preciso lidar com problemas
de incompatibilidade entre os navegadores, visto que todos usavam o mesmo plugin.

    Essa metodologia trouxe novos problemas. O conteúdo em Flash, não era indexado pelos
mecanismos de busca, o que logo se tornou um grande problema a medida que os mecanismos
de busca se estabeleceram como a principal porta de entrada para a Web.

    Além disso uma falta de padronização de interface trouxe dificuldades de usabilidade e
acessibilidade. Cada desenvolvedor criava interfaces ricas diferenciadas e que o usuário não
reconhecia de imediato [Krug 2005].


2.1.3 Aplicações Ricas da Internet

    As Aplicações Ricas da Internet começaram a fazer uso mais intensivo das linguagens e
frameworks modernos. Além disso houve o aparecimento do Ajax.

    Ajax (Asynchronous Javascript and XML) é um conjunto de técnicas para alterar o conteúdo
de uma página Web depois dela ter sido carregada. Na prática ela permite que apenas uma parte
da página seja atualizada ao invés de fazer um novo carregamento. Por ser assíncrona essa
técnica permite que o usuário interaja com a página enquanto as informações são carregadas.
Esta funcionalidade existe nos navegadores desde o ano 2000, mas o termo Ajax surgiu apenas
em 2005 quando a tecnologia foi popularizada.

    O Ajax trouxe um dinamismo novo às antigas páginas estáticas melhorando a experiên-
cia do usuário drasticamente e permitindo aos desenvolvedores reinventar a Web como uma
plataforma para o desenvolvimento de aplicações.

    O Flash deixou de ser a melhor opção para gerar interfaces ricas. E foi lentamente, sendo
rebaixada para a categoria de mídia player para sites. Sites como o Youtube usam o Flash
apenas para exibir vídeos e áudio, enquanto que o Ajax predomina na interface.


2.1.4 Gears

    As aplicações Web ficam centralizadas na nuvem. Isso significa que todos os códigos,
arquivos e dados ficam em servidores e não na máquina cliente, que serve apenas como uma
janela para enxergar essas aplicações.
6


       Antes da aparição do Gears não existia uma maneira de guardar estes dados e arquivos. Os
cookies podem guardar apenas uma quantidade limitada de dados, e são geralmente usados para
manter sessões de usuários, provendo uma funcionalidade não inclusa no HTTP. Não existe uma
maneira de guardar dados relacionais como os que são guardados nos bancos de dados do lado
do servidor.

       Com o Gears o desenvolvedor tem uma nova opção. Pode armazenar dados no computador
do usuário em um banco de dados local implementado dentro do navegador na forma de uma
extensão.

       Isso cria um novo precedente no desenvolvimento de aplicações Web. Pode-se criar aplica-
ções Web seguras que nunca enviam os dados para a nuvem, ou acelerar aplicações existentes
trazendo os dados todos para o lado do cliente. Bem como tornar aplicações antes apenas aces-
síveis através da Internet completamente offline.

       Aplicações Web contruídas desta forma podem deixar de ser do tipo thin-client/fat-server e
passar a ser fat-client/thin-server. Exatamente como aplicações desktop tradicionais.


2.1.5 HTML5

       A nova especificação do HTML, prevista para ser finalizada em 2010, inclui algumas funci-
onalidades análogas as providas pelo Gears. Como será uma funcionalidade padrão do navega-
dor pode-se antecipar que será utilizada por muitos desenvolvedores a medida que os usuários
começam a utilizar os navegadores que implementam o HTML5.

       Além de contar com a funcionalidade de guardar dados localmente o HTML provê tags
multimídia para exibir videos ou sons, e uma API Javascript para controlar essas funcionalida-
des.

       O Objetivo do HTML5 é introduzir funcionalidades antes providas apenas por extensões e
que provaram ser importantes para a construção de aplicações mais ricas baseadas na Web.

       O Gears provê hoje a habilidade de escrever aplicações que usam as algumas funcionali-
dades do HTML5 antes que este seja liberado. O Google anunciou recentemente uma camada
de abstração que permite o uso tanto do Gears como do HTML5, caso este esteja disponível,
através da mesma interface [Google 2009].
7


2.2     Javascript

    O Javascript é um dialeto da especificação ECMAScript e é hoje a linguagem mais utilizada
para fazer programação client side. Por ser a única linguagem amplamente implementada por
todos os grandes navegadores, ela não tem muita concorrência.

    A programação client side foi por muito tempo chamada de DHTML ou Dynamic HTML,
pois a maior utilidade para o Javascript era adicionar dinamismo ao HTML. Este dinamismo, era
geralmente uma questão visual e não interferia em nada com o funcionamento das aplicações.
Uma das funcionalidade mais utilizada era para prover validação a formulários.

    Com a popularização do Ajax o Javascript tornou-se parte integrante das aplicações. Uma
vez que a lógica das aplicações começou a ser escrita no lado do cliente a linguagem precisou
evoluir para suprir as necessidades dos desenvolvedores.

    Hoje o Javascript é uma linguagem poderosa orientada a objetos e que faz uso extensivo de
eventos para capturar a interação do usuário com a página. É importante que o desenvolvedor
tenha um bom domínio dessas funcionalidades na hora de implementar grandes aplicações,
criando bibliotecas reutilizáveis e simples de manter [Keith 2005].


2.2.1 Ajax e DOM

    O DOM ou Document Object Model, é uma representação em árvore da estrutura HTML
de uma página Web. O DOM permite interações como consulta, adição, remoção ou alterações
dos nós desta árvore. O Javascript possui uma interface para uso do DOM permitindo alteração
dinâmica [Keith 2005].

    O uso em conjunto do DOM e do Ajax é o que permite o carregamento de informação
adicionais dentro de uma página sem recarregar todo o conteúdo novamente.

    Cada navegador implementa o Javascript em cima das especificação ECMAScript. Porém
as vezes há diferenças entre as implementações. Essas diferenças entre os navegadores sempre
foram uma dor de cabeça para os desenvolvedores. A medida que as aplicações crescem, e o
código Javascript cresce fica mais difícil encontrar bugs e essa diferença entre os navegadores
não ajuda em nada os desenvolvedores.

    Existem bibliotecas Javascript que padronizam a interface de comandos Ajax e para inte-
ração com o DOM. Essas bibliotecas resolvem problemas como incompatibilidades com nave-
gadores e deixa tempo para o programador lidar com seus próprios bugs. Dentre as bibliotecas
8


mais utilizadas estão o jQuery, Prototype e Dojo.

    As Aplicações Ricas de Internet geralmente fazem uso constante do DOM e Ajax, e por
este motivo é comum o uso de alguma destas bibliotecas.
9


2.3    Gears

    O Gears é um projeto de código livre que possibilita a construção de aplicações Web mais
poderosas e integradas ao desktop, as chamadas Rich Internet Applications.

    O Gears foi idealizado pelo Google e lançado em maio de 2007 [Gears API 2008], atual-
mente está em sua versão 0.5.22.0 e é desenvolvido por funcionários do Google e membros
voluntários de uma comunidade de desenvolvedores que se formou ao redor do projeto.

    O uso mais comum para Gears é fazer com que aplicações Web, ou pelo menos parte delas,
fiquem acessíveis mesmo que não haja acesso a Internet [Kilani 2007], ou para acelerar o fun-
cionamento da aplicação para que ela fique o mais parecido possível com o funcionamento de
uma aplicação desktop.

    Atualmente as plataformas suportadas são: Windows XP/Vista, Windows Mobile, Mac,
Android e Linux. O Gears é implementado como um extensão para os navegadores Firefox,
Internet Explorer, Safari ou Chrome. O seu trabalho é fazer uma ponte entre a aplicação Web e
o SO, fornecendo os recursos do SO para a aplicação através de uma API em Javascript.

    Entre os sistemas que já se beneficiam do Google Gears estão diversas aplicações do Google,
MySpace, Zoho, Remember the Milk [Kilani 2007], entre outras.
10


2.3.1 Módulos do Gears

    O Gears é um sistema modular e a idéia é que no futuro mais e mais módulos sejam adicio-
nados permitindo flexibilidade enquanto mantém o core do Gears bem leve. Dentre os módulos
atualmente disponíveis estão:


Database Provê um banco de dados local no cliente para guardar dados e recuperá-los, pos-
      sibilitando que esses dados possam ser utilizados mesmo sem que haja conexão com a
      Internet. No Gears esta camada faz uso do SQLite, um banco de dados open source
      pequeno mas com muitas funcionalidades.

Desktop Fornece acesso ao desktop como por exemplo a possibilidade de criar ícones na má-
      quina cliente facilitando o acesso a aplicação Web e tornando-a mais próxima de aplica-
      ções locais.

Geolocation Permite que a aplicação Web acesse dispositivos da máquina cliente que infor-
      mam a localização do usuário como um módulo GPS. Esse recurso é utilizado por exem-
      plo em uma aplicação de mapas rodando em um celular para poder localizar a posição
      exata em que o usuário se encontra em um mapa.

LocalServer Permite que requisições HTTP que normalmente seriam enviadas pela Internet
      para um servidor remoto, sejam respondidas pela mesma máquina cliente num servidor
      local. Este recurso acelera o funcionamento de uma aplicação Web e inclusive permite
      que uma certa aplicação funcione sem acesso a Internet, e conseqüentemente ao seu ser-
      vidor. Dentro do LocalServer existem ResourceStores que são utilizados para guardar
      conteúdo estático.

WorkerPool Fornece recursos para fazer processamento Javascript em paralelo para evitar que
      um script complexo interrompa a fluidez da aplicação.


2.3.2 Arquitetura de Sistemas Baseados em Gears

    Como regra geral as aplicações Web são aplicações distribuídas do tipo fat server/thin cli-
ent [Tanenbaum e Steen 2007], uma vez que o cliente ou browser é responsável apenas por
renderizar a interface de usuário como mostra a Figura 1. Neste modelo cada vez que o usuário
realiza qualquer interação com a aplicação é feita uma requisição ao servidor e este retorna uma
página HTML que representa um snapshot do sistema como ilustrado na Figura 2.
11




      Figura 1: Arquitetura tradicional de aplicações Web




Figura 2: Diagrama de sequência tradicional para aplicações Web
12




                          Figura 3: Arquitetura proposta pelo Gears

    O Gears propõe uma arquitetura diferente [Gears API 2008]. Através dos módulos Local-
Server e Database, descritos na seção 2.3.1, o Gears tem o poder de prover páginas localmente
sem precisar contactar o servidor. Isso agiliza as chamadas e possibilita o uso das aplicações
mesmo sem uma conexão a Internet. Nessa arquitetura as requisições passam primeiramente
por um data switch que irá identificar se os dados devem ser requisitados para o servidor remoto
ou para o servidor local. Caso a requisição vá para o servidor remoto o data switch encaminha
a requisição para a camada de dados remotos, que por sua vez implementa a API para recuperar
os dados remotamente. Caso a requisição seja encaminhada para a camada de dados local, os
dados serão recuperados do banco de dados interno do Gears. Existe ainda uma camada op-
cional de sincronização responsável por sincronizar os dados do banco de dados local com os
dados do servidor remoto, essa sincronização normalmente é feita por um Worker Pool sendo
assim executado em segundo plano. Esta arquitetura está ilustrada na Figura 3.

    Na arquitetura do Gears nem sempre as requisições precisam passar pelo servidor, vide
Figura 4. Isto torna o processo todo bem mais rápido já que não depende da conexão com a In-
ternet. O próprio Gears trata de encaminhar as requisições que não podem ser feitas localmente
e sincronizar os dados remotos com os dados locais.
13




Figura 4: Diagrama de sequência para aplicações Web baseadas em Gears
14




3        METODOLOGIA


    Este capítulo mostra os passos principais no desenvolvimento de uma aplicação de anota-
ções em Django que faz uso do Gears.



3.1     Aplicação de anotações

    A aplicação que foi desenvolvida é uma aplicação simples usada como base para imple-
mentar o Gears utilizando o Django como framework do lado do servidor.

    Dentre as características da aplicação podemos citar:


    • Criação de anotações com título e conteúdo.

    • Possibilidade de visualizar as anotações mesmo sem acesso a Internet.

    • Possibilidade de criar anotações mesmo sem acesso a Internet.

    • Sincronização de anotações enquanto a aplicação está online, para enviar ao servidor as
      anotações criadas em modo offline.



3.2     Aplicação em Django

    O Django é um framework de código livre de alto nível que encoraja o desenvolvimento
rápido de aplicações Web com design limpo e pragmático utilizando a linguagem Python. A
linguagem Python por sua vez tem como principais características a rápida prototipação e o fato
de ter uma biblioteca básica muito completa.

    O framework Django se baseia no design pattern MVC (Model View Controller) que pro-
põe uma divisão clara entre as camadas de modelo, visão e controle (representação de dados,
interface com usuário e lógica de negócio, respectivamente) da aplicação. Esta divisão facilita
15


a manutenção dos sistemas e a independência das camadas entre si e torna fácil a reestruturação
completa de uma dessas camadas com poucas ou nenhuma modificação nas outras camadas.

    Os sistemas em Django são geralmente divididos em diversas aplicações Django. Cada
aplicação implementa uma ferramenta específica e estas são “plugáveis” no sistema como um
todo. Elas podem interagir entre si mas há uma separação clara de código. Este modelo mais
uma vez facilita a manutenção dos sistemas e estimula o reaproveitamento de código de maneira
muito prática.


3.2.1 Estrutura Básica de Sistemas Django

    Esta seção visa exemplificar a estrutura geral de uma aplicação Django e como os diferentes
aplicativos são organizados e reutilizados. Bem como os pontos importantes para criar aplica-
ções em Ajax com Django. Este trabalho não pretende documentar todos os passos envolvidos
no desenvolvimento de aplicações Django. Uma análise mais detalhada pode ser encontrada na
bibliografia [Holovaty e Kaplan-Moss 2008] ou na home page do projeto Django 1 .

    Após usar o comando python django-admin.py startproject project, o Django cria
uma pasta “project” com a seguinte estrutura.


project/
|-- __init__.py
|-- manage.py
|-- settings.py
‘-- urls.py


    O arquivo settings.py possui configurações diversas como informações do banco de da-
dos, diretórios com templates, aplicações Django instaladas, entre outros. O arquivo urls.py
possui o mapeamento de urls para “views”, em outras palavras indica qual função irá ser execu-
tada quando cada url for acessada. Já o arquivo manage.py disponibiliza uma extensa coleção
de scripts que gerenciam e automatizam a administração do sistema, pode-se usá-lo para criar
  1 http://www.djangoproject.com/
16


uma nova aplicação Django.


$ python manage.py startapp notes
$ ls
project/
|-- __init__.py
|-- notes
|      |-- __init__.py
|      |-- models.py
|      ‘-- views.py
|-- manage.py
|-- settings.py
‘-- urls.py


    Neste momento é criada uma pasta “notes” que irá agrupar os arquivos referentes a este
aplicativo e nele já existem os arquivos models.py e views.py que devem ser reescritos para
conter a descrição dos dados e lógica de negócio. O código utilizado neste documento pode ser
encontrado no Apêndice A.

    Após escrever estas duas camadas o aplicativo pode ser “plugado” alterando a seguinte
sessão no arquivo settings.py.


INSTALLED_APPS = (
       ’django.contrib.auth’,
       ’django.contrib.contenttypes’,
       ’django.contrib.sessions’,
       ’django.contrib.sites’,
       ’project.notes’,
)


    Desta forma o aplicativo “notes” é plugado no sistema. É perceptível que o Django já vem
com alguns aplicativos habilitados por padrão como por exemplo o “django.contrib.auth” que é
responsável por gerenciar usuários do sistema. Uma vez que a maioria dos sistemas Web tem
usuários, é natural que o Django já venha com esta aplicação, seguindo o modelo all under the
hood do Python. Claro que esta aplicação pode ser desligada facilmente desabilitando o suporte
a usuários e permissões.
17


    Após plugar a aplicação, pode-se invocar o comando python manage.py syncdb para
que o Django crie no banco de dados as tabelas que refletem os modelos definidos no arquivo
models.py.

    O Django provê uma interface orientada a objeto para acesso aos dados através da camada
de modelos. Desse modo não é preciso lidar com queries SQL, o que facilita o desenvolvimento
e cria uma independência do DBMS 2 .


3.2.2 Implementando Ajax

    Uma boa prática no desenvolvimento de aplicações com Ajax, é se certificar de que a aplica-
ção continuará funcionando corretamente mesmo sem o Javascript [Keith 2005]. Uma estratégia
para atingir este objetivo é seguir os seguintes passos:


   1. Construa uma aplicação sem Javascript utilizando links e formulários em HTML puro e
      crie a lógia no servidor para responder a estas requisições.

   2. Depois adicione Javascript para interceptar essas chamadas e submissões de formulário
      realizando-as por Ajax e atualizando apenas parte da página.


    Desta forma é fácil criar aplicações Ajax que são compatíveis com navegadores sem Javas-
cript, ou que continuem funcionando caso haja algum erro de Javascript.

    A lógica em Javascript usada para interceptar as requisições na aplicação anotações, pode
ser encontrada no conteúdo do arquivo notes.js, na página 42 do apêndice A.2.2.

    Após implementar a lógica para interceptar essas requisições em Javascript é importante
certificar-se que o servidor não irá responder da mesma forma as requisições simples e as re-
quisições em Ajax.

    Felizmente o Django provê uma maneira simples de identificar a origem da requisição
através da função request.is_ajax() dentro de uma “view”. Isso é possível graças ao jQuery
que insere um cabeçalho a mais na requisição HTTP facilitando sua identificação.

    No caso de a requisição ser feita via Ajax, a “view” não precisa retornar a página completa,
apenas os dados que serão inseridos dentro da página. Estes dados podem ser retornados como
HTML, texto puro, XML ou Json. O Json tem a vantagem de ser um formato compatível com
um objeto Javascript e devido a isso o trabalho de extrair os dados se torna mais simples.
  2 Data   Base Management System: Sistema gerenciador de bancos de dados
18


    Neste exemplo utilizamos o Django para listar todas as notas, gerar Json caso a requisição
seja feita via Ajax e renderizar a página completa caso seja uma requisição normal.


def note_list(request):
     n = Note.objects.all()
     form = NoteForm()
     if request.is_ajax():
          response = HttpResponse(mimetype="application/json")
          json_serializer = serializers.get_serializer("json")()
          json_serializer.serialize(n, ensure_ascii=False, stream=response)
          return response
     else:
          return render_to_response(’notes/note_list.html’,
               { ’object_list’ : n,’form’ : form},
               context_instance=RequestContext(request))
19


3.3     Implementação do Gears

    O Gears é flexível e a maneira como o desenvolvedor vai implementa-lo depende das ne-
cessidades da aplicação e da dificuldade de implementação. O desenvolvedor deve ponderar a
quantidade de trabalho a ser realizado e o benefício para o usuário final. Na maioria das vezes
não faz sentido fazer com que toda aplicação esteja disponível offline [Gears FAQ 2008].

    A medida que se acrescentam funcionalidades offline se torna necessário um mecanismo de
sincronização. Este provavelmente é o momento mais complexo e sujeito a erros na implemen-
tação do Gears.

    Para inicializar o Gears sempre se deve usar o arquivo gears_init.js que o Google dis-
ponibiliza. Este script torna disponível a variável global google dentro do Javascript caso o
Gears esteja instalado. Com isso podemos redirecionar o usuário para uma página de instalação
caso o Gears não esteja instalado.


if (!window.google || !google.gears)
{
       location.href = ’http://gears.google.com/?action=install&’ +
       ’message=Baixe o Google Gears para Continuar’ +
       ’&return=http://localhost/notes’;
}


    Uma vez que o Gears esteja instalado é exibido para o usuário um diálogo de segurança
como o ilustrado na figura 5.




      Figura 5: Confirmação para permitir que a aplicação use o Gears para guardar dados
20


3.3.1 Implementação Modal ou Amodal

    A primeira decisão a ser tomada é como o Gears será habilitado e o usuário irá interagir
com ele. As opções são as seguintes [Kilani 2007]:


   1. Modal: O usuário deve clicar em um botão na interface que troca para o modo offline e de
      volta para o modo online. O Google Reader e o Remember the Milk, são dois exemplos
      de aplicação que utilizam este sistema.

   2. Amodal: O sistema entra em modo offline automaticamente caso a Internet não esteja
      acessível. Este é o modelo de implementação usado no Gmail.


    O modelo Modal é geralmente mais simples de implementar e dependendo da aplicação
pode ser o modelo ideal. A aplicação de anotações poderia ser implementada utilizando este
modelo, porém decidiu-se utilizar o modelo Amodal para fins de pesquisa.


3.3.2 Conteúdo Estático

    Tornar o conteúdo estático offline é uma operação relativamente simples no Gears. Por este
motivo este geralmente é o primeiro passo tomado pelos desenvolvedores. Além disso este é
um dos recursos que mais aceleram o funcionamento da aplicação para o usuário final. Como
todos os recursos estão alocados localmente a aplicação não precisa acessar a Internet, ou então
acessa a Internet com muito menos frequência, e a velocidade se aproxima da velocidade de
uma aplicação desktop.

    Este recurso usa o módulo LocalServer do Gears. Este módulo possui 3 classes, dessas
iremos abordar apenas 2 necessárias para capturar e prover os recursos estáticos em um site: A
classe LocalServer e a classe ManagedResourceStore.

    Com essas duas classes pode-se fazer o cache de arquivos estáticos como páginas HTML,
código Javascript, documentos CSS, imagens, etc.
21


    Primeiro deve-se escrever um arquivo manifest.json com os arquivos que deverão ser
baixados. Exemplo de arquivo manifest.json:


{
     "betaManifestVersion": 1,
     "version": "v1",
     "entries": [
          { "url": "/notes/"},
          { "url": "/media/notes/gears_init.js"},
          { "url": "/media/notes/jquery.js"},
          { "url": "/media/notes/notes.js"},
          { "url": "/media/notes/django_gears.js"},
          { "url": "/media/notes/datalayer.js"},
          { "url": "/media/notes/style.css"},
          { "url": "/media/notes/gears_icons.png"}
     ]
}


    O Gears fica fazendo requisições repetidamente pelo arquivo manifest.json, essas geral-
mente são retornadas com o código HTTP 304 (“Not Modified”). Porém caso o arquivo seja
modificado ele recebe a nova versão. Caso um dos arquivos seja atualizado basta atualizar o pa-
râmetro version do manifest para que as atualizações sejam buscadas. Caso contrário o Gears
irá sempre prover a versão local carregada anteriormente.

    Esse mecanismo funciona analogamente ao mecanismo de cache do HTTP, com a diferença
que ele não precisa checar as modificações para cada arquivo, o Gears apenas checa pelas
modificações no arquivo manifest.json.

    Inicie o localserver em todas as páginas para ter certeza que sempre tem o ultimo
manifest.json.


localServer = google.gears.factory.create("beta.localserver");
          store = localServer.createManagedStore(’mystore’);
          store.manifestUrl = ’http://localhost/media/notes/manifest.json’;
          store.checkForUpdate();
22


3.3.3 Identificando Estado Online/Offline

    Caso o Gears seja implementado usando a forma Amodal, precisa-se descobrir o status da
aplicação. O Gears não possui uma interface simples para verificar se a aplicação está online
ou offline, porém é fácil implementar em Javascript uma rotina que faça esta verificação.

    Segue uma rotina que faz este procedimento:


var request = google.gears.factory.create(’beta.httprequest’);
var online = false;
function pingSuccess() {
     if(request.responseText.indexOf("ok") >= 0){
          online = true;
     } else {
          online = false;
     }
}
function isServerAvailable() {
     var resource_to_test = "/media/notes/gears_test.txt";
     var TIME_BETWEEN_PINGS = 3*1000;
     var PING_TIMEOUT_SECONDS = 1*1000;
     //parâmetro randômico para não receber arquivo em cache.
     resource_to_test += "?q=" + Math.floor(Math.random() * 100000);
     request.open(’GET’, resource_to_test);
     window.setTimeout("pingSuccess()",PING_TIMEOUT_SECONDS);
     request.send();
     window.setTimeout("isServerAvailable()",TIME_BETWEEN_PINGS);
}
isServerAvailable();


    Esta rotina basicamente busca um arquivo no servidor a cada 3 segundos. Este arquivo deve
existir dentro do servidor como um arquivo texto puro com o conteúdo “ok”. Dependendo da
resposta da requisição a rotina marca a variável online para refletir o estado da aplicação.

    Pode ser importante ou não saber o estado da aplicação, dependendo da forma de sincroni-
zação que será utilizada.

    No exemplo incluído nesta monografia a aplicação faz uso desta rotina para informar ao
23


usuário o estado atual, e para desativar a sincronização dos dados com o servidor.


3.3.4 Camada de Dados

      A maioria das aplicações Web não possuem uma camada de dados bem definida. Isso
porque como a fonte de dados era apenas uma não fazia sentido criar esta abstração. Nestes
casos a implementação é mais complicada pois toda a aplicação deve ser reescrita para usar a
nova camada de dados.

      A camada de dados é uma interface em Javascript para acesso aos dados da aplicação.
É importante a construção desta camada, pois uma vez que implementa-se o Gears os dados
poderão vir de duas origens distintas. O servidor ou banco de dados local.

      Aplicações tradicionais fazem uma requisição ao servidor pedindo por um determinado
conjunto de dados. Dependendo da aplicação e implementação, esses dados podem vir em dife-
rentes formatos: texto puro, HTML, XML, Json, etc. Depois que esses dados são recuperados
a página é atualizada para mostrar os dados.

      Porém uma vez que implementamos o Gears os dados que são recuperados do banco de
dados local vêm dentro de um Gears ResultSet (classe do módulo Database). Portanto tem-
se um retorno diferente dependendo da origem dos dados.

      A camada de dados dentro de uma aplicação Web deve ser construída para normalizar os
dados que são passados para a aplicação. A seguir é apresentado como a aplicação de anotações
usa a camada de dados para fazer requisição de dados.


var dl = new datalayer;
dl.getNote(7,function(){
      //mostra o titulo da Nota com id 7 em uma caixa de diálogo
      alert(this.fields.title);
});


      A classe datalayer irá verificar a existência do Gears. Caso este esteja instalado ela irá
buscar a nota no banco do Gears caso não esteja instalado, o DataLayer irá fazer uma requisição
Ajax ao servidor.
24


     Exemplo de implementação de Camada de Dados:


function datalayer(){};
//Seleciona uma ou todas as notas do Gears ou da Web caso este não esteja disp.
datalayer.prototype.getNotes = function(id,callback){
     try{
            var sql = ’SELECT * FROM notes_note ’,
                json_r = [];
            if(id>=0){
                sql += ’WHERE id = ’+id+’;’
            }
            //Já retorna um Json igual ao retornado pelo Django
            json_r = dg.queryToObject(sql);
            return cb(json_r);
     }catch(e){
            if(id>=0)
                return $.getJSON(’/notes/’+id+’/’,cb);
            return $.getJSON(’/notes/’,cb);
     }
};


     Percebe-se que independente de usar ou não o Gears o retorno é sempre um objeto Json
com os dados requisitados. Esta é a abstração desejada nesta implementação.

     O conteúdo dinâmico das páginas deve ser armazenado dentro do banco de dados local
utilizando a interface Javascript do módulo Database do Gears. Pode-se interagir com o banco
de dados através de queries SQL, da mesma maneira com que se interage com um banco de
dados no servidor. Porém com tudo sendo executado do lado do cliente.


3.3.5 Sincronização

     A sincronização dos dados locais com os dados remotos é um dos pontos mais difíceis
na implementação do Gears. O desenvolvedor mais uma vez precisa ponderar que nível de
sincronização faz sentido dentro da sua aplicação.

     O Gears não vem com nenhuma funcionalidade que implemente a sincronização automati-
camente. Ao invés disso o desenvolvedor deve criar um mecanismo de sincronização.
25


    A seguir são apresentadas algumas estratégias de sincronização por ordem de complexidade
e comentários sobre a implementação de cada uma delas.


Apenas Leitura Offline

    Neste modo baixa-se todo conteúdo, ou parte dele para o cliente. A partir daí sempre
que necessário, pode-se ler o conteúdo localmente, o que acelera muito o funcionamento da
aplicação. Quando alguma modificação é feita no servidor, descarta-se todo conteúdo local e
“baixa” o novo conteúdo.

    Este é o modo mais fácil de usar o Gears para acelerar o acesso das aplicações aos dados e
permite que as aplicações sejam utilizadas offline apenas para leitura.

    A rede social MySpace utiliza esta estratégia com Gears para acelerar as buscas no site.
Todos os contatos são baixados para a máquina do usuário, e as buscas por Amigos são reali-
zadas localmente. Além de livrar o servidor da carga que existe por trás de uma busca do tipo
full-text-search, acelera a interface.


Leitura e Escrita Offline

    Com uma aplicação implementando o modo somente leitura com o Gears, pode-se passar
para o próximo passo. Gravar as modificação localmente.

    Ao invés de enviar as alterações para o servidor, fazer estas alterações diretamente no banco
de dados local, tornando desnecessário carregar todos os dados novamente a cada alteração de
registros.

    Assim a aplicação fica disponível offline tanto para leitura como para edição, porém como
as modificações não são feitas no servidor perde-se uma das grandes vantagens das aplicações
nas nuvens que é a vantagem de poder acessar a aplicação de qualquer localidade. Deste modo
os dados vão estar sempre no cliente, e caso se mude de navegador se perde os dados.

    O fato de os dados nunca irem para o servidor pode ser uma vantagem. Desta maneira é
possível a criação de sistemas em que os dados são apenas locais, introduzindo um nível de
segurança novo em aplicações Web. Pode-se imaginar, por exemplo, uma aplicação de controle
financeiro desenvolvida dessa maneira. A atualização do código da aplicação ainda pode ser
feita de modo remoto, porém toda a lógica e dados ficam na máquina do usuário e nunca são
enviadas para a Internet.
26


Sincronização Mono-usuário

    Esta é uma estratégia para implementar a sincronização online e offline, utilizando a pre-
missa de que um usuário nunca poderá estar logado mais de uma vez no sistema.

    Num primeiro momento baixamos todos os dados do servidor localmente. Depois sempre
que uma gravação for efetuada nos dados locais ela será marcada com uma flag para que seja
enviada para o servidor assim que possível.

    Uma rotina é executada periodicamente que verifica se existem modificações na base local
para que sejam enviadas para o servidor. Assim que a modificação é enviada para o servidor
marca-se a informação como enviada.

    É interessante criar uma coluna de chave primária no banco de dados local, independente
da coluna de chave primária do servidor, para evitar problemas de conflito. Pode-se usar o
mesmo esquema do banco de dados do servidor dentro do Gears porém adicionando a coluna
id_server para manter uma referência ao “id” real do registro.


Sincronização Multi-usuário

    Esta seria a estratégia mais completa, porém a mais complexa de ser implementada.

    Além de gravar as modificações feitas na base local e no servidor, precisa-se consultar o
servidor periodicamente para ter os dados mais atualizados.

    Um evento de sincronização deve ser disparado periodicamente. Como a sincronização
pode se tornar um processo custoso, deve ser, de preferência, executada dentro de um WorkerPool,
para que não interfira com o funcionamento da aplicação para o usuário.

    A seguir é apresentada a rotina em Javascript da aplicação Anotações que busca as atuali-
zações na base de dados remota. Esta rotina usa uma tabela local notes_version que guarda
o timestamp da última atualização, e requisita as notas alteradas depois desse timestamp.


djGears.prototype.get_updates = function(){
     var rs;
     //set new updated time
     this.query(’update notes_version set last_mod = datetime("now");’);
     //Only import the new ones
     $.getJSON(’/notes/?xhr=1&last_mod=’+this.last_mod+’’,function(r){
          for (var n in r){
27


               if (r[n].pk === undefined){
                     continue;
               }
               dg.query(’insert into notes_note ’+
                     ’(id_server,title, content,mod_date) values (?,?,?,?)’,
                     [r[n].pk, r[n].fields.title,
                          r[n].fields.content, r[n].fields.mod_date]);
           }
     });
     rs = this.query(’select version,strftime("%s",last_mod) ’+
           ’from notes_version’);
     if(rs.isValidRow()){
           this.version = rs.field(0);
           this.last_mod = rs.field(1);
     }
     rs.close();
}


    Este processo inclui um novo problema de implementação, que é a questão de conflitos. As
vezes modificações feitas no servidor e as modificações feitas localmente podem representar
um conflito. Neste caso temos que introduzir uma maneira de resolver este conflito. Algumas
opções ordenadas por dificuldade são:


    • Substituir a versão local pela do servidor.

    • Mostrar um diálogo ao usuário para que ele faça a resolução do conflito.

    • Tentar fazer uma resolução de conflitos automaticamente.
28




4        CONCLUSÃO


    Este capítulo apresenta os resultados obtidos pelo estudo desta arquitetura inovadora pro-
posta pelo Gears, bem como dificuldades encontradas durante o projeto de desenvolvimento.



4.1     Análise da Arquitetura Proposta

    As novas aplicações Web trazem a lógica cada vez mais para o lado do cliente. Isso faz com
que o código Javascript das aplicações se torne relativamente grande e complexo. É importante
conhecer bem as novidades dessa linguagem que tornam o desenvolvimento de grandes bases
de código mais amigável.

    A arquitetura proposta pelo Gears demonstrada na seção 2.3.2 (página 10) cria um novo
paradigma para desenvolvimento de aplicações Web, introduzindo funcionalidades nunca antes
disponíveis nesta plataforma.



4.2     Contribuições

    Este trabalho documenta a criação de uma aplicação rica da Web desenvolvida em Django
e utilizando o Gears para prover funcionalidades offline. Focando nos passos mais importantes
e nas decisões que devem ser tomadas pelo desenvolvedor que pretende implementar o Gears.

    Outra contribuição é a análise da arquitetura proposta pelo Gears e como isso pode afetar o
futuro das aplicações Web.



4.3     Dificuldades Encontradas

    As Aplicações Ricas da Internet são desenvolvidas em Python (ou qualquer outra linguagem
server side) e Javascript. O fato de ter que trabalhar com duas linguagens simultaneamente pode
29


causar confusão durante o desenvolvimento. Não só pelo fato de a sintaxe ser diferente, mas
também pelo fato de o Javascript ser uma linguagem que possui alguns paradigmas incomuns
como a orientação a eventos e o escopo baseado em closures.

    As aplicações Web podem ser difíceis de depurar. Uma das melhores ferramentas para fazer
debug é o FireBug, extensão para o Firefox que permite adicionar breakpoints e fazer trace do
código.

    Pelo Gears ser uma tecnologia muito nova e com muitas possibilidades, é difícil encontrar
bom material de exemplo e bibliografia. Por sorte o Google provê uma boa documentação
da API [Gears API 2008] e de problemas comuns [Gears FAQ 2008]. Mesmo assim algumas
funcionalidades não são documentadas.



4.4       Propostas de Extensão

    Dentre possíveis extensões para a continuidade deste trabalho estão:


   • Estudo da arquitetura do Adobre AIR traçando um paralelo com as funcionalidades do
      Gears.

   • Estudo das novas funcionalidades do HTML5 e como essas funcionalidades complemen-
      tam ou substituem as funcionalidades do Gears.

   • Desenvolvimento de aplicação para facilitar a criação de mecanismos de sincronização
      no Gears.
30




                 Referências Bibliográficas

[Gears API 2008]GEARS API. [S.l.], 2008. Documentação da API do Google Gears. Disponí-
 vel em: <http://code.google.com/apis/gears/design.html>. Acesso em: 30/05/2009.

[Gears FAQ 2008]GEARS FAQ. [S.l.], 2008. Perguntas e Respostas Frequentes sobre o Google
 Gears. Disponível em: <http://code.google.com/apis/gears/gears_faq.html>. Acesso em:
 30/05/2009.

[Google 2009]GOOGLE. Web Storage Portability Layer: A Common API for Web
 Storage. [S.l.], 2009. Anúncio do WSPL do Google. Disponível em: <http://google-
 opensource.blogspot.com/2009/05/web-storage-portability-layer-common.html>. Acesso
 em: 31/05/2009.

[Holovaty e Kaplan-Moss 2008]HOLOVATY, A.; KAPLAN-MOSS, J. The Definitive Guide to
 django: Web development done right. 1. ed. [S.l.]: Apress, 2008. ISBN 978-1590597255.

[Keith 2005]KEITH, J. DOM Scripting: Web design with javascript and the document
 object model. Friends of ED, 2005. 368 p. ISBN 978-1-59059-533-6. Disponível em:
 <http://www.friendsofed.com/book.html?isbn=1590595335>.

[Kilani 2007]KILANI, O. Taking web applications offline with gears. 2007. Disponí-
 vel em: <http://code.google.com/apis/gears/articles/take_app_offline.html>. Acesso em:
 04/12/2008.

[Krug 2005]KRUG, S. Don’t Make Me Think: A common sense approach to web usability. 2.
 ed. [S.l.]: New Riders Press, 2005. ISBN 978-0321344755.

[Miller 2008]MILLER, M. Cloud Computing: Web-based applications that change the way you
 work and collaborate online. [S.l.]: Que, 2008. ISBN 978-0789738035.

[Taivalsaari e Ingalls 2008]TAIVALSAARI, A.; INGALLS, D. Web browser as an application
  platform: The lively kernel experience. 2008.

[Tanenbaum e Steen 2007]TANENBAUM, A.; STEEN, M. V. Sistemas Distribuídos: Princí-
  pios e paradigmas. 2. ed. São Paulo, SP: Pearson, 2007. 416 p. ISBN 978-8576051428.
31




APÊNDICE A -- Aplicação em Django utilizando
             Gears



    Neste Apêndice está documentada uma aplicação simples de anotações utilizando Django
e disponibilizando todas as funcionalidades offline com o Gears.



A.1 Interface

    Telas da aplicação de Anotações.




                           Figura 6: Tela listando todas as notas.
32




Figura 7: Tela mostrando uma determinada nota.
33


A.2 Arquivos

    Nesta seção estão documentados os arquivos principais da implementação da aplicação de
anotações.


project
|-- __init__.py
|-- db.sqlite      <-- Banco de dados do lado do Servidor
|-- manage.py      <-- Arquivo do django de gerenciamento de projetos e aplicações
|-- notes          <-- Aplicação django
|   |-- __init__.py
|   |-- admin.py        <-- Configura interface de Administração do django
|   |-- app_media       <-- Arquivos estáticos
|   |     ‘-- notes
|   |         |-- datalayer.js        <-- Camada de abstração de dados
|   |         |-- django_gears.js <-- Funções de sincronização e setup do Gears
|   |         |-- gears_icons.png
|   |         |-- gears_init.js       <-- Arqivo padrão para inicializar o          Gears
|   |         |-- gears_test.txt      <-- Usado para testar se o cliente esta online
|   |         |-- jquery.js           <-- Biblioteca que facilita o uso do DOM e Ajax
|   |         |-- manifest.json       <-- manifest do Gears
|   |         |-- notes.js            <-- Biblioteca que faz alterações na interface
|   |         ‘-- style.css
|   |-- forms.py
|   |-- models.py       <-- Define modelo de dados
|   |-- templates       <-- django templates, usados pelas views
|   |     ‘-- notes
|   |         |-- base.html
|   |         |-- note_detail.html
|   |         ‘-- note_list.html
|   |-- urls.py         <-- Faz mapeamento de urls e views para esta aplicação
|   ‘-- views.py        <-- Lógica de negócio
|-- settings.py         <-- Configuração do django
‘-- urls.py             <-- Mapeamento de urls do projeto
34


A.2.1 Django

    Arquivos mais relevantes na implementação do Django da aplicação.


models.py

from django.db import models
from datetime import datetime
class Note(models.Model):
    mod_date = models.DateTimeField(’date modified’)
    title = models.CharField(max_length=200)
    content = models.TextField()
    def __unicode__(self):
           return self.title
    def get_absolute_url(self):
           return "/notes/%i/" % self.id
    def save(self, force_insert=False, force_update=False):
           self.mod_date   = datetime.utcnow()
           super(Note, self).save(force_insert, force_update)


urls.py

from django.conf.urls.defaults import *
from notes.models import Note
urlpatterns = patterns(’notes.views’,
    (r’^$’, ’note_list’),
    (r’^add/$’, ’note_add’),
    (r’^(?P<id>d+)/$’, ’note_detail’),
    (r’^sync/$’, ’sync’),
)


views.py

from django.http import HttpResponse, HttpResponseRedirect
from django.core import serializers
from django.shortcuts import get_object_or_404, render_to_response
from notes.models import Note
35


from django.template import RequestContext
from notes.forms import NoteForm
from datetime import datetime
def note_list(request):
    form = NoteForm()
    if request.GET.has_key("last_mod") and request.GET[’last_mod’].isdigit():
        #recuperando notas alteradas apenas a partir de certa data
        n = Note.objects.filter(mod_date__gt=datetime.fromtimestamp(
            int(request.GET[’last_mod’])))
    else:
        n = Note.objects.all()
    if request.is_ajax() or request.GET.has_key("xhr"):
        response = HttpResponse(mimetype="application/json")
        json_serializer = serializers.get_serializer("json")()
        json_serializer.serialize(n, ensure_ascii=False, stream=response)
        return response
    else:
        return render_to_response(’notes/note_list.html’,
            { ’object_list’ : n,’form’ : form},
            context_instance=RequestContext(request))
def note_detail(request, id):
    n = get_object_or_404(Note, pk=id)


    if request.is_ajax() or request.GET.has_key("xhr"):
        n = Note.objects.filter(id=id)
        response = HttpResponse(mimetype="application/json")
        json_serializer = serializers.get_serializer("json")()
        json_serializer.serialize(n, ensure_ascii=False, stream=response)
        return response
    else:
        return render_to_response(’notes/note_detail.html’, {’object’:n},
            context_instance=RequestContext(request))
def note_add(request):
    if request.method == ’POST’:
        form = NoteForm(request.POST)
36


         if form.is_valid():
             form.save()
             return HttpResponseRedirect(’/notes/’)
    else:
         return HttpResponseRedirect(’/notes/’)
def sync(request):
    if request.method == ’POST’:
         for deserialized_object in serializers.deserialize("json",
             request.POST[’data’]):
             obj = deserialized_object.object
             deserialized_object.save()
             if(obj.pk):
                   return HttpResponse(obj.pk)
    assert(False)
    return HttpResponse(’ERROR’)


A.2.2 Gears

   Arquivos mais relevantes na implementação do Gears na aplicação.


django_gears.js

function djGears(){
    this.STORE_NAME = "offline_notes";
    this.MANIFEST_FILENAME = "/media/notes/manifest.json";
    this.online=false;
    this.setup_store();
    this.db = google.gears.factory.create(’beta.database’);
    this.db.open(’db’);
    try {
         var rs;
         rs = this.query(
             ’select version,strftime("%s",last_mod,"utc") from notes_version’);
         console.log(rs);
         console.trace();
         this.version = rs.field(0);
37


            this.last_mod = rs.field(1);
            rs.close();
     } catch (e) {
            console.error("DB needs setup: "+ e.message);
            this.setup_db();
     }
     this.get_updates();


}
djGears.prototype.setup_db = function(){
     try{
            //Create tables
            this.query(’BEGIN’);
            var sql = ’CREATE TABLE IF NOT EXISTS "notes_note" (’+
                ’   "id" integer NOT NULL PRIMARY KEY,’+
                ’   "id_server" integer,’+
                ’   "mod_date" datetime NOT NULL,’+
                ’   "title" varchar(200) NOT NULL,’+
                ’   "content" text NOT NULL’+
                ’);’+
                ’CREATE UNIQUE INDEX IF NOT EXISTS "notes_note_id_server" ’+
                ’ON "notes_note" ("id_server");’;
            this.query(sql);
            sql = ’CREATE TABLE IF NOT EXISTS notes_version ’+
                ’("version" integer not null primary key, "last_mod"’+
                ’ datetime not null);’;
            this.query(sql);
            this.query(’COMMIT’);
            this.query(’INSERT INTO notes_version VALUES (1,0);’);
     } catch (ex) {
            console.error(’Could not create database: ’ + ex.message);
     }
};
djGears.prototype.query = function(sql, arr){
     var ret;
38


     try{
            console.info(sql,arr);
            return this.db.execute(sql,arr);
     }catch(e){
            console.error("query error:" + e.message +":" +sql+arr);
            throw e;
     }
};
djGears.prototype.queryToObject = function(sql, args) {
     var rs = this.query(sql, args);
     try {
            var rv = [], h;
            if (rs && rs.isValidRow()) {
                while (rs.isValidRow()) {
                       h = {fields: {}};
                       h.pk = rs.fieldByName(’id’);
                       h.model = ’notes.note’;
                       for (i = 0; i < rs.fieldCount(); i++) {
                           h.fields[rs.fieldName(i)] = rs.field(i);
                       }
                       rv.push(h);
                       rs.next();
                }
            }
     } catch (e) {
            throw e;
     } finally {
            rs.close();
            return rv;
     }
}
djGears.prototype.setup_store = function(){
     if(!window.google || !google.gears) {
            location.href = "http://gears.google.com/?action=install" +
                "&return=localhost/notes/";
39


     }else{
            localServer = google.gears.factory.create("beta.localserver");
            this.store = localServer.createManagedStore(this.STORE_NAME);
            this.store.manifestUrl = this.MANIFEST_FILENAME;
            this.store.checkForUpdate();
     }
};
djGears.prototype.get_updates = function(){
     try{
            var rs;


            //Only import the new ones
            $.getJSON(’/notes/?xhr=1&last_mod=’+this.last_mod+’’,function(r){
                      for (var n in r){
                          if (r[n].pk === undefined){
                               continue;
                          }
                          dg.query(’insert into notes_note ’+
                               ’(id_server,title, content,mod_date) values (?,?,?,?)’,
                               [r[n].pk, r[n].fields.title,
                               r[n].fields.content, r[n].fields.mod_date]);
                      }
            });
            //set new updated time
            this.query(’update notes_version set last_mod = datetime("now");’);
            rs = this.query(
                  ’select version,strftime("%s",last_mod,"utc") from notes_version’);
            if(rs.isValidRow()){
                  this.version = rs.field(0);
                  this.last_mod = rs.field(1);
            }
            rs.close();


     } catch (ex) {
            console.error(’Import error: ’ + ex.message);
40


    }
}
djGears.prototype.send_updates = function(){
    try{
           var obj;
           if(this.tsend){
                 clearTimeout(this.tsend);
           }
           //get new rows
           obj = this.queryToObject(
                 ’select id,title,content,mod_date from notes_note ’+
                 ’where id_server is null limit 1;’);
           if(typeof obj[0] == ’undefined’ || typeof obj[0].pk == ’undefined’){
                 console.log(’App atualizada’);
                 return false;
           }
           if(!this.online){
                 this.tsend = window.setTimeout("dg.send_updates()",9*1000);
                 console.log(’Aplicação offline remarcando send_updates’);
                 return false;
           }
           this.get_updates();
           //Export
           $.post(’/notes/sync/’,’data=’+JSON.stringify(obj),function(text){
                      var id = parseInt(text);
                      if(id && id>=0){
                          dg.query("update notes_note set id_server = ? ’+
                              ’where id = ? ",[id,obj[0].pk]);
                          dg.send_updates();
                      }
           });
    }catch (ex){
           console.error(’Export error: ’ + ex.message)
    }
}
41


//Check if Online
if(window.google && google.gears) {
      var request = google.gears.factory.create(’beta.httprequest’);
      var dg = new djGears();
      function pingSuccess() {
             if(request.responseText.indexOf("ok") >= 0){
                 $("#gears").attr(’class’, ’online’);
                 $("#gears_status").text("Online");
                 dg.online=true;
             } else {
                 $("#gears").attr(’class’, ’offline’);
                 $("#gears_status").text("Offline");
                 dg.online=false;
             }
      }
      function isServerAvailable() {
             var resource_to_test = "/media/notes/gears_test.txt";
             var TIME_BETWEEN_PINGS = 3*1000;
             var PING_TIMEOUT_SECONDS = 1*1000;
             resource_to_test += "?q=" + Math.floor(Math.random() * 100000);
             request.open(’GET’, resource_to_test);
             window.setTimeout("pingSuccess()",PING_TIMEOUT_SECONDS);
             request.send();
             window.setTimeout("isServerAvailable()",TIME_BETWEEN_PINGS);
      }
      isServerAvailable();
}


datalayer.js

function datalayer(){};
/**
 * Get all or one object from local database or, if not possible, from the web
 */
datalayer.prototype.getNotes = function(id,cb){
      try{
42


             var sql,
                 json_r = [];
             sql = ’SELECT * FROM notes_note ’;
             if(id>=0){
                 sql += ’WHERE id = ’+id+’;’
             }
             json_r = dg.queryToObject(sql);
             return cb(json_r);
      }catch(e){
             return $.getJSON(’/notes/?xhr=1’,cb);
      }
};
/**
 * Funcao deve ser passada para o contexto de um formulario
 */
datalayer.prototype.postNote = function(e,cb){
      var event = e || window.event;
      var el = event.target || event.srcElement;
      try{
             var sql,arr;
             sql = ’INSERT INTO notes_note (title,content,mod_date) ’+
                 ’VALUES (?,?,datetime("now"))’;
             arr = [el.title.value, el.content.value]
             dg.query(sql,arr);
             cb();
             dg.send_updates();
      }catch(e){
             $.post($(el).attr(’action’),$(el).serialize(),cb);
      }
};
var dl = new datalayer();


notes.js

      Funções responsáveis por invocar o datalayer e fazer modificações na interface do usuário.
Faz uso de instruções da biblioteca jQuery.
43


function loadNotes(event){
    dl.getNotes(-1,function(data){
          $("#notas").empty();
          $("#notas").append(document.createElement(’ul’));
          $.each(data, function(){
              $("#notas").children(":first").append(’<li>’+
                    ’<a href="/notes/’+this.pk+’/">’+this.fields.title+’</a></li>’);
              });
          $(’<form id="add_nota" method="post" action="/notes/add/">’+
          ’<p><label for="id_title">Title:</label> <input type="text" maxlength=’+
          ’"200" name="title" id="id_title"/></p><p><label for="id_content">’+
          ’Content:</label> <textarea name="content" cols="40" rows="10" ’+
          ’id="id_content"/></p><input type="submit" value="Submeter"/></form>’)
              .appendTo(’#notas’);
          $("#add_nota").submit(NovaNota);
          RegisterListEvents();
    });
    if (event) {
          event.preventDefault();
    }
}


function NovaNota(event){
    dl.postNote(event,function(){
          loadNotes();
    });
    event.preventDefault();
}


function RegisterListEvents(){
    $("#notas li>a").unbind(’click’);
    $("#notas li>a").click(function(event){
          var pk = /.*/notes/(d+)//.exec($(this).attr("href"))[1];
          dl.getNotes(parseInt(pk), function(data){
              $("#notas").empty();
44


                  $.each(data,function(){
                        $(’#notas’).append(’<h2>’+this.fields.title+’</h2>’);
                        $(’#notas’).append(’<pre>’+this.fields.content+’</pre>’);
                  });
            event.preventDefault();
            });
      });
}


function RegisterSidebarEvents(){
      $("#note_menu").unbind(’click’);
      $("#note_menu").click(loadNotes);
}
$(document).ready(function(event){


RegisterListEvents();
RegisterSidebarEvents();
loadNotes();
});

Mais conteúdo relacionado

Mais procurados

Br office writer
Br office writerBr office writer
Br office writerLuciana
 
Alternativas ao Software Proprietário
Alternativas ao Software ProprietárioAlternativas ao Software Proprietário
Alternativas ao Software ProprietárioHudson Augusto
 
Caelum java-testes-xml-design-patterns-fj16
Caelum java-testes-xml-design-patterns-fj16Caelum java-testes-xml-design-patterns-fj16
Caelum java-testes-xml-design-patterns-fj16Caique Moretto
 
Drivers de Dispositivos Linux
Drivers de Dispositivos LinuxDrivers de Dispositivos Linux
Drivers de Dispositivos LinuxHudson Augusto
 
TCC_2010_2_Fernando_Figueiredo_Torres
TCC_2010_2_Fernando_Figueiredo_TorresTCC_2010_2_Fernando_Figueiredo_Torres
TCC_2010_2_Fernando_Figueiredo_TorresFernando Torres
 
Spring framework 2.0 pt_BR
Spring framework 2.0 pt_BRSpring framework 2.0 pt_BR
Spring framework 2.0 pt_BRDiego Pacheco
 
Caelum ruby-on-rails-rr71
Caelum ruby-on-rails-rr71Caelum ruby-on-rails-rr71
Caelum ruby-on-rails-rr71Caique Moretto
 
Apostila ruby-completa
Apostila ruby-completaApostila ruby-completa
Apostila ruby-completamako2887
 
Publicado ruby on-rails-rr71
Publicado ruby on-rails-rr71Publicado ruby on-rails-rr71
Publicado ruby on-rails-rr71Fernando Palma
 
K19 k03-sql-e-modelo-relacional
K19 k03-sql-e-modelo-relacionalK19 k03-sql-e-modelo-relacional
K19 k03-sql-e-modelo-relacionalJean Lopes
 
Relatório de Projecto de Licenciatura
Relatório de Projecto de LicenciaturaRelatório de Projecto de Licenciatura
Relatório de Projecto de LicenciaturaJoel Carvalho
 
Introdução à programação em R
Introdução à programação em RIntrodução à programação em R
Introdução à programação em RMonica Barros
 
Programacao Orientada A Objetos (Java)
Programacao Orientada A Objetos (Java)Programacao Orientada A Objetos (Java)
Programacao Orientada A Objetos (Java)Robson Silva Espig
 
K19 k51-design-patterns-em-java
K19 k51-design-patterns-em-javaK19 k51-design-patterns-em-java
K19 k51-design-patterns-em-javaCaique Moretto
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaCaique Moretto
 

Mais procurados (17)

Br office writer
Br office writerBr office writer
Br office writer
 
Alternativas ao Software Proprietário
Alternativas ao Software ProprietárioAlternativas ao Software Proprietário
Alternativas ao Software Proprietário
 
Caelum java-testes-xml-design-patterns-fj16
Caelum java-testes-xml-design-patterns-fj16Caelum java-testes-xml-design-patterns-fj16
Caelum java-testes-xml-design-patterns-fj16
 
Drivers de Dispositivos Linux
Drivers de Dispositivos LinuxDrivers de Dispositivos Linux
Drivers de Dispositivos Linux
 
TCC_2010_2_Fernando_Figueiredo_Torres
TCC_2010_2_Fernando_Figueiredo_TorresTCC_2010_2_Fernando_Figueiredo_Torres
TCC_2010_2_Fernando_Figueiredo_Torres
 
Apostila tp
Apostila tpApostila tp
Apostila tp
 
Spring framework 2.0 pt_BR
Spring framework 2.0 pt_BRSpring framework 2.0 pt_BR
Spring framework 2.0 pt_BR
 
Caelum ruby-on-rails-rr71
Caelum ruby-on-rails-rr71Caelum ruby-on-rails-rr71
Caelum ruby-on-rails-rr71
 
Apostila ruby-completa
Apostila ruby-completaApostila ruby-completa
Apostila ruby-completa
 
Estrutura de dados
Estrutura de dadosEstrutura de dados
Estrutura de dados
 
Publicado ruby on-rails-rr71
Publicado ruby on-rails-rr71Publicado ruby on-rails-rr71
Publicado ruby on-rails-rr71
 
K19 k03-sql-e-modelo-relacional
K19 k03-sql-e-modelo-relacionalK19 k03-sql-e-modelo-relacional
K19 k03-sql-e-modelo-relacional
 
Relatório de Projecto de Licenciatura
Relatório de Projecto de LicenciaturaRelatório de Projecto de Licenciatura
Relatório de Projecto de Licenciatura
 
Introdução à programação em R
Introdução à programação em RIntrodução à programação em R
Introdução à programação em R
 
Programacao Orientada A Objetos (Java)
Programacao Orientada A Objetos (Java)Programacao Orientada A Objetos (Java)
Programacao Orientada A Objetos (Java)
 
K19 k51-design-patterns-em-java
K19 k51-design-patterns-em-javaK19 k51-design-patterns-em-java
K19 k51-design-patterns-em-java
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-java
 

Destaque (6)

Tendencias de seo para o futuro
Tendencias de seo para o futuroTendencias de seo para o futuro
Tendencias de seo para o futuro
 
Otimização de Landing Pages
Otimização de Landing PagesOtimização de Landing Pages
Otimização de Landing Pages
 
Marketing terms
Marketing termsMarketing terms
Marketing terms
 
Documentos electronicos eje tematico 5
Documentos electronicos eje tematico 5Documentos electronicos eje tematico 5
Documentos electronicos eje tematico 5
 
Google Analytics Hacks
Google Analytics HacksGoogle Analytics Hacks
Google Analytics Hacks
 
2010 BMW 535i Boston
2010 BMW 535i Boston2010 BMW 535i Boston
2010 BMW 535i Boston
 

Semelhante a Aplicações Web ricas com Gears para clientes offline

Guia Aberto Android ed.2
Guia Aberto Android ed.2Guia Aberto Android ed.2
Guia Aberto Android ed.2Átila Camurça
 
Apostila c# iniciantes
Apostila c# iniciantesApostila c# iniciantes
Apostila c# iniciantesCaique Moretto
 
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...Johnnatan Messias
 
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejb
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejbK19 k23-integracao-de-sistemas-com-webservices-jms-e-ejb
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejbCaique Moretto
 
K19 k41 Desenvolvimento Mobile com Android
K19 k41 Desenvolvimento Mobile com AndroidK19 k41 Desenvolvimento Mobile com Android
K19 k41 Desenvolvimento Mobile com AndroidAline Diniz
 
K19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidK19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidRaytssa Martins
 
K19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidK19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidMaluco Rafael
 
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...joselopes1984
 
Dissertação de Mestrado - Planejamento para Serviços Web Semânticos
Dissertação de Mestrado - Planejamento para Serviços Web SemânticosDissertação de Mestrado - Planejamento para Serviços Web Semânticos
Dissertação de Mestrado - Planejamento para Serviços Web SemânticosJuliana Chahoud
 
DissertacaoMScValterFinal20070216
DissertacaoMScValterFinal20070216DissertacaoMScValterFinal20070216
DissertacaoMScValterFinal20070216Valter Inacio Jr.
 
Programação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaProgramação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaJooMarcos614503
 

Semelhante a Aplicações Web ricas com Gears para clientes offline (20)

Guia Aberto Android ed.2
Guia Aberto Android ed.2Guia Aberto Android ed.2
Guia Aberto Android ed.2
 
Livro angular2
Livro angular2Livro angular2
Livro angular2
 
Tut arduino
Tut arduinoTut arduino
Tut arduino
 
Relatório Técnico: .NET Framework, ASP.NET MVC 3 e Silverlight
Relatório Técnico: .NET Framework, ASP.NET MVC 3 e SilverlightRelatório Técnico: .NET Framework, ASP.NET MVC 3 e Silverlight
Relatório Técnico: .NET Framework, ASP.NET MVC 3 e Silverlight
 
android
androidandroid
android
 
Apostila c# iniciantes
Apostila c# iniciantesApostila c# iniciantes
Apostila c# iniciantes
 
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...
Monografia: Framework Para Sistemas de Navegação de Veículos Aéreos Não Tripu...
 
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejb
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejbK19 k23-integracao-de-sistemas-com-webservices-jms-e-ejb
K19 k23-integracao-de-sistemas-com-webservices-jms-e-ejb
 
K19 k41 Desenvolvimento Mobile com Android
K19 k41 Desenvolvimento Mobile com AndroidK19 k41 Desenvolvimento Mobile com Android
K19 k41 Desenvolvimento Mobile com Android
 
Zope
ZopeZope
Zope
 
K19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidK19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-android
 
K19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-androidK19 k41-desenvolvimento-mobile-com-android
K19 k41-desenvolvimento-mobile-com-android
 
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...
Windows Registry Fixer (WRF): Automação na Criação de scripts para Controle d...
 
Dissertação de Mestrado - Planejamento para Serviços Web Semânticos
Dissertação de Mestrado - Planejamento para Serviços Web SemânticosDissertação de Mestrado - Planejamento para Serviços Web Semânticos
Dissertação de Mestrado - Planejamento para Serviços Web Semânticos
 
DissertacaoMScValterFinal20070216
DissertacaoMScValterFinal20070216DissertacaoMScValterFinal20070216
DissertacaoMScValterFinal20070216
 
Poojava
PoojavaPoojava
Poojava
 
Poojava
PoojavaPoojava
Poojava
 
Poojava
PoojavaPoojava
Poojava
 
Introdução às redes
Introdução às redesIntrodução às redes
Introdução às redes
 
Programação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaProgramação Orientada a Objetos com Java
Programação Orientada a Objetos com Java
 

Aplicações Web ricas com Gears para clientes offline

  • 1. Eduardo Cereto Carvalho Rich Internet Applications com clientes offline utilizando Gears Itatiba - São Paulo - Brasil Junho de 2009
  • 2. Eduardo Cereto Carvalho Rich Internet Applications com clientes offline utilizando Gears Monografia, apresentada à disciplina Trabalho de Conclusão de Curso II do curso de Engenha- ria da Computação da Universidade São Fran- cisco, sob a orientação do Prof. Rodrigo Cha- vez M. do Prado, como exigência parcial para conclusão do curso de graduação. Orientador: Rodrigo Chavez M. do Prado G RADUAÇÃO EM E NGENHARIA DA C OMPUTAÇÃO U NIVERSIDADE S ÃO F RANCISCO Itatiba - São Paulo - Brasil Junho de 2009
  • 3. i Sumário Lista de Figuras p. iii Resumo p. iv Abstract p. v 1 INTRODUÇÃO p. 1 1.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 3 1.1.1 Objetivos Específicos . . . . . . . . . . . . . . . . . . . . . . . . . . p. 3 2 ASPECTOS TEÓRICOS p. 4 2.1 Evolução das Aplicações Web . . . . . . . . . . . . . . . . . . . . . . . . . p. 4 2.1.1 Páginas Estáticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 4 2.1.2 Páginas com Conteúdo Multimídia . . . . . . . . . . . . . . . . . . . p. 4 2.1.3 Aplicações Ricas da Internet . . . . . . . . . . . . . . . . . . . . . . p. 5 2.1.4 Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 5 2.1.5 HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 6 2.2 Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 7 2.2.1 Ajax e DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 7 2.3 Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 9 2.3.1 Módulos do Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 10 2.3.2 Arquitetura de Sistemas Baseados em Gears . . . . . . . . . . . . . . p. 10 3 METODOLOGIA p. 14
  • 4. ii 3.1 Aplicação de anotações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 14 3.2 Aplicação em Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 14 3.2.1 Estrutura Básica de Sistemas Django . . . . . . . . . . . . . . . . . p. 15 3.2.2 Implementando Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . p. 17 3.3 Implementação do Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 19 3.3.1 Implementação Modal ou Amodal . . . . . . . . . . . . . . . . . . . p. 20 3.3.2 Conteúdo Estático . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 20 3.3.3 Identificando Estado Online/Offline . . . . . . . . . . . . . . . . . . p. 22 3.3.4 Camada de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 23 3.3.5 Sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 24 4 CONCLUSÃO p. 28 4.1 Análise da Arquitetura Proposta . . . . . . . . . . . . . . . . . . . . . . . . p. 28 4.2 Contribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 28 4.3 Dificuldades Encontradas . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 28 4.4 Propostas de Extensão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 29 Referências Bibliográficas p. 30 Apêndice A -- Aplicação em Django utilizando Gears p. 31 A.1 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 31 A.2 Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 33 A.2.1 Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 34 A.2.2 Gears . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 36
  • 5. iii Lista de Figuras 1 Arquitetura tradicional de aplicações Web . . . . . . . . . . . . . . . . . . . p. 11 2 Diagrama de sequência tradicional para aplicações Web . . . . . . . . . . . . p. 11 3 Arquitetura proposta pelo Gears . . . . . . . . . . . . . . . . . . . . . . . . p. 12 4 Diagrama de sequência para aplicações Web baseadas em Gears . . . . . . . p. 13 5 Confirmação para permitir que a aplicação use o Gears para guardar dados . . p. 19 6 Tela listando todas as notas. . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 31 7 Tela mostrando uma determinada nota. . . . . . . . . . . . . . . . . . . . . . p. 32
  • 6. iv Resumo “Aplicações Ricas da Internet” é o nome dado às aplicações Web que fazem uso pesado de Javascript para implementar uma interface dinâmica provendo uma experiência similar a das aplicações desktop convencionais. Este trabalho mostra um pouco da história das aplicações Web, e especula sobre o futuro, fazendo um estudo de tecnologias emergentes como o Gears que trazem novas possibilidades a essa plataforma.
  • 7. v Abstract “Rich Internet Applications” is the name for the Web applications that make heavy use of Javascript to implement dynamic interfaces providing a user experience similar to a regular Desktop Application. This work shows the history of Web applications, and discusses about the future of the Web as an application platform. Also it explores emerging technologies such as Gears that bring new features to this platform.
  • 8. 1 1 INTRODUÇÃO Nos últimos anos pudemos vivenciar a popularização de hardware e Internet em todo o mundo. É comum hoje em dia o indivíduo ter um computador desktop em casa, um notebook para o trabalho e mais aquele computador da namorada que ele usa nos finais de semana. Seus arquivos acabam espalhados em diversos computadores e pen drives. Alguém distraído pode facilmente se perder em meio às diferentes versões de arquivos que vão sendo criadas ao longo do tempo. Agora imagine fazer backup de tudo isso de uma maneira organizada. Pode-se pensar em muitas soluções para estes problemas, dentre elas: criar um servidor FTP em um servidor pago para centralizar tudo, usar um pen drive para ter mobilidade e manter backups nos diversos computadores ou ainda criar um elegante sistema de versões mantendo repositórios distintos que iriam sendo mesclados usando uma ferramenta de controle de versões como o GIT. Cada uma dessas soluções tem um problema, seja ele um ponto único de falha, um custo monetário mensal ou um grau de complexidade elevado. Mas com certeza nenhuma delas é uma solução trivial o suficiente para ser amplamente utilizada pelo usuário final. A computação nas nuvens [Miller 2008] surge para resolver este problema. Esse novo conceito de computação propõe que todos os dados e, às vezes, até mesmo as aplicações fiquem na Internet. As empresas como o Google começam a oferecer muitos Giga Bytes grátis para que o usuário possa guardar seus e-mails no Gmail ou documentos no GoogleDocs. Esses são dois exemplos onde tanto os dados quanto a aplicação estão nas nuvens, ou seja, nos servidores do Google. Tudo é facilmente acessível de um navegador, onde quer que o usuário esteja. É fácil, é confiável, é seguro e é muito funcional. Com a disseminação da computação nas nuvens o computador pessoal deixou de rodar as aplicações e guardar os dados passando a ser apenas uma janela para a Internet. Na prática só se precisa de um Sistema Operacional (SO) e um navegador para ter acesso a um mundo de aplicações como editores de imagem, planilhas eletrônicas, editores de texto, e-mail, etc. As aplicações desktop ficaram um tanto ameaçadas porque é improvável que elas consigam ofere- cer em curto prazo as vantagens da computação nas nuvens. Porém as aplicações na Internet
  • 9. 2 têm a desvantagem de estar atreladas ao navegador e por isso ter certas limitações. Volta-se a era dos terminais burros e mainframes, com os dados e aplicações centralizadas na Internet e os computadores fazendo o papel dos terminais burros. Os computadores de hoje são muito superiores, em termos de recursos, aos terminais burros de antigamente, porém esses recursos são muito mal utilizados nas aplicações Web. A falta de acesso direto ao SO não permite que as aplicações acessem o sistema de arquivos ou façam algum processamento mais complexo em paralelo. Todas estas aplicações estão presas ao protocolo HTTP que é simples e sem es- tado [Tanenbaum e Steen 2007] além de linguagens script para processamento client side muito lentas se comparado a uma biblioteca nativa. Caso o usuário esteja em um local sem Internet todos os seus documentos estão inacessíveis e seu computador passa a ser um peso de papel. Além disso a questão da usabilidade é importante já que as interfaces das aplicações Web são diferentes das interfaces de programas desktop equivalentes, o usuário pode sentir difi- culdade em se acostumar ao novo ambiente, o que pode gerar uma queda de produtividade expressiva [Krug 2005]. Algumas iniciativas vêm sendo tomadas para integrar as aplicações Web ao desktop a fim de eliminar ou reduzir estas desvantagens das aplicações Web. Algumas empresas lançaram seus produtos em caráter experimental usando suas próprias abordagens para o problema. A Adobe criou o AIR que permite criar aplicações Web em Flash e ActionScript que rodam como se fos- sem aplicações nativas, se aproveitando de recursos como aceleração 3D enquanto o Google, com o seu Gears, teve uma abordagem diferente privilegiando a possibilidade de guardar arqui- vos no lado do cliente e fazer processamento Javascript em paralelo. A integração tem um papel tanto de usabilidade, trazendo transparência no acesso à apli- cação Web, quanto em termos de funções, já que as aplicações desktop não estão presas ao navegador especificamente. Por isso tem mais liberdade de acesso aos recursos da máquina.
  • 10. 3 1.1 Objetivos O objetivo deste documento é fazer uma análise da evolução das aplicações Web e como o Gears pode resolver limitações desta plataforma, introduzindo funcionalidades novas. 1.1.1 Objetivos Específicos • Usar o Gears para contornar limitações das aplicações Web. • Mostrar como o uso de um framework forte facilita a criação de aplicações mais ricas. • Estudar os problemas mais comuns na implementação do Gears.
  • 11. 4 2 ASPECTOS TEÓRICOS 2.1 Evolução das Aplicações Web De maneira geral a evolução das aplicações Web pode ser definida em 3 fases distin- tas [Taivalsaari e Ingalls 2008]. • Páginas "clássicas", apenas com texto e imagens estáticas. • Páginas multimídia, com animações e conteúdo multimídia com o uso de plugins. • Rich Internet Applications ou Aplicações Ricas da Internet. 2.1.1 Páginas Estáticas Nos primórdios a Web era usada para manter arquivos HTML estáticos que possuíam links entre eles. Era como um livro gigantesco, no qual o usuário tinha a opção de pular direto para a seção que mais lhe interessava com facilidade. Este modelo foi se modernizando e as páginas começaram a se tornar dinâmicas. Lingua- gens simples eram usadas para gerar as páginas antes estáticas. Lentamente foram surgindo linguagens e frameworks focados na Web e a arquitetura dos sites foi se tornando cada vez mais complexa. 2.1.2 Páginas com Conteúdo Multimídia Mesmo com as páginas sendo geradas dinamicamente a interface do usuário ainda era está- tica. O usuário clicava num link e isso acarretava num recarregamento da página. Com o tempo foi surgindo a necessidade de adicionar dinamismo a interface do usuário. Os Java applets e o Flash deram essa possibilidade ao desenvolvedor. Os sites podiam ser melhor customizados. Animações, som e vídeo abriam um novo leque de possibilidades para
  • 12. 5 os webdesigners. Este modelo exigia que o usuário instalasse um plugin proprietário no navegador, caso con- trário este não conseguiria acessar o conteúdo. Porém não era mais preciso lidar com problemas de incompatibilidade entre os navegadores, visto que todos usavam o mesmo plugin. Essa metodologia trouxe novos problemas. O conteúdo em Flash, não era indexado pelos mecanismos de busca, o que logo se tornou um grande problema a medida que os mecanismos de busca se estabeleceram como a principal porta de entrada para a Web. Além disso uma falta de padronização de interface trouxe dificuldades de usabilidade e acessibilidade. Cada desenvolvedor criava interfaces ricas diferenciadas e que o usuário não reconhecia de imediato [Krug 2005]. 2.1.3 Aplicações Ricas da Internet As Aplicações Ricas da Internet começaram a fazer uso mais intensivo das linguagens e frameworks modernos. Além disso houve o aparecimento do Ajax. Ajax (Asynchronous Javascript and XML) é um conjunto de técnicas para alterar o conteúdo de uma página Web depois dela ter sido carregada. Na prática ela permite que apenas uma parte da página seja atualizada ao invés de fazer um novo carregamento. Por ser assíncrona essa técnica permite que o usuário interaja com a página enquanto as informações são carregadas. Esta funcionalidade existe nos navegadores desde o ano 2000, mas o termo Ajax surgiu apenas em 2005 quando a tecnologia foi popularizada. O Ajax trouxe um dinamismo novo às antigas páginas estáticas melhorando a experiên- cia do usuário drasticamente e permitindo aos desenvolvedores reinventar a Web como uma plataforma para o desenvolvimento de aplicações. O Flash deixou de ser a melhor opção para gerar interfaces ricas. E foi lentamente, sendo rebaixada para a categoria de mídia player para sites. Sites como o Youtube usam o Flash apenas para exibir vídeos e áudio, enquanto que o Ajax predomina na interface. 2.1.4 Gears As aplicações Web ficam centralizadas na nuvem. Isso significa que todos os códigos, arquivos e dados ficam em servidores e não na máquina cliente, que serve apenas como uma janela para enxergar essas aplicações.
  • 13. 6 Antes da aparição do Gears não existia uma maneira de guardar estes dados e arquivos. Os cookies podem guardar apenas uma quantidade limitada de dados, e são geralmente usados para manter sessões de usuários, provendo uma funcionalidade não inclusa no HTTP. Não existe uma maneira de guardar dados relacionais como os que são guardados nos bancos de dados do lado do servidor. Com o Gears o desenvolvedor tem uma nova opção. Pode armazenar dados no computador do usuário em um banco de dados local implementado dentro do navegador na forma de uma extensão. Isso cria um novo precedente no desenvolvimento de aplicações Web. Pode-se criar aplica- ções Web seguras que nunca enviam os dados para a nuvem, ou acelerar aplicações existentes trazendo os dados todos para o lado do cliente. Bem como tornar aplicações antes apenas aces- síveis através da Internet completamente offline. Aplicações Web contruídas desta forma podem deixar de ser do tipo thin-client/fat-server e passar a ser fat-client/thin-server. Exatamente como aplicações desktop tradicionais. 2.1.5 HTML5 A nova especificação do HTML, prevista para ser finalizada em 2010, inclui algumas funci- onalidades análogas as providas pelo Gears. Como será uma funcionalidade padrão do navega- dor pode-se antecipar que será utilizada por muitos desenvolvedores a medida que os usuários começam a utilizar os navegadores que implementam o HTML5. Além de contar com a funcionalidade de guardar dados localmente o HTML provê tags multimídia para exibir videos ou sons, e uma API Javascript para controlar essas funcionalida- des. O Objetivo do HTML5 é introduzir funcionalidades antes providas apenas por extensões e que provaram ser importantes para a construção de aplicações mais ricas baseadas na Web. O Gears provê hoje a habilidade de escrever aplicações que usam as algumas funcionali- dades do HTML5 antes que este seja liberado. O Google anunciou recentemente uma camada de abstração que permite o uso tanto do Gears como do HTML5, caso este esteja disponível, através da mesma interface [Google 2009].
  • 14. 7 2.2 Javascript O Javascript é um dialeto da especificação ECMAScript e é hoje a linguagem mais utilizada para fazer programação client side. Por ser a única linguagem amplamente implementada por todos os grandes navegadores, ela não tem muita concorrência. A programação client side foi por muito tempo chamada de DHTML ou Dynamic HTML, pois a maior utilidade para o Javascript era adicionar dinamismo ao HTML. Este dinamismo, era geralmente uma questão visual e não interferia em nada com o funcionamento das aplicações. Uma das funcionalidade mais utilizada era para prover validação a formulários. Com a popularização do Ajax o Javascript tornou-se parte integrante das aplicações. Uma vez que a lógica das aplicações começou a ser escrita no lado do cliente a linguagem precisou evoluir para suprir as necessidades dos desenvolvedores. Hoje o Javascript é uma linguagem poderosa orientada a objetos e que faz uso extensivo de eventos para capturar a interação do usuário com a página. É importante que o desenvolvedor tenha um bom domínio dessas funcionalidades na hora de implementar grandes aplicações, criando bibliotecas reutilizáveis e simples de manter [Keith 2005]. 2.2.1 Ajax e DOM O DOM ou Document Object Model, é uma representação em árvore da estrutura HTML de uma página Web. O DOM permite interações como consulta, adição, remoção ou alterações dos nós desta árvore. O Javascript possui uma interface para uso do DOM permitindo alteração dinâmica [Keith 2005]. O uso em conjunto do DOM e do Ajax é o que permite o carregamento de informação adicionais dentro de uma página sem recarregar todo o conteúdo novamente. Cada navegador implementa o Javascript em cima das especificação ECMAScript. Porém as vezes há diferenças entre as implementações. Essas diferenças entre os navegadores sempre foram uma dor de cabeça para os desenvolvedores. A medida que as aplicações crescem, e o código Javascript cresce fica mais difícil encontrar bugs e essa diferença entre os navegadores não ajuda em nada os desenvolvedores. Existem bibliotecas Javascript que padronizam a interface de comandos Ajax e para inte- ração com o DOM. Essas bibliotecas resolvem problemas como incompatibilidades com nave- gadores e deixa tempo para o programador lidar com seus próprios bugs. Dentre as bibliotecas
  • 15. 8 mais utilizadas estão o jQuery, Prototype e Dojo. As Aplicações Ricas de Internet geralmente fazem uso constante do DOM e Ajax, e por este motivo é comum o uso de alguma destas bibliotecas.
  • 16. 9 2.3 Gears O Gears é um projeto de código livre que possibilita a construção de aplicações Web mais poderosas e integradas ao desktop, as chamadas Rich Internet Applications. O Gears foi idealizado pelo Google e lançado em maio de 2007 [Gears API 2008], atual- mente está em sua versão 0.5.22.0 e é desenvolvido por funcionários do Google e membros voluntários de uma comunidade de desenvolvedores que se formou ao redor do projeto. O uso mais comum para Gears é fazer com que aplicações Web, ou pelo menos parte delas, fiquem acessíveis mesmo que não haja acesso a Internet [Kilani 2007], ou para acelerar o fun- cionamento da aplicação para que ela fique o mais parecido possível com o funcionamento de uma aplicação desktop. Atualmente as plataformas suportadas são: Windows XP/Vista, Windows Mobile, Mac, Android e Linux. O Gears é implementado como um extensão para os navegadores Firefox, Internet Explorer, Safari ou Chrome. O seu trabalho é fazer uma ponte entre a aplicação Web e o SO, fornecendo os recursos do SO para a aplicação através de uma API em Javascript. Entre os sistemas que já se beneficiam do Google Gears estão diversas aplicações do Google, MySpace, Zoho, Remember the Milk [Kilani 2007], entre outras.
  • 17. 10 2.3.1 Módulos do Gears O Gears é um sistema modular e a idéia é que no futuro mais e mais módulos sejam adicio- nados permitindo flexibilidade enquanto mantém o core do Gears bem leve. Dentre os módulos atualmente disponíveis estão: Database Provê um banco de dados local no cliente para guardar dados e recuperá-los, pos- sibilitando que esses dados possam ser utilizados mesmo sem que haja conexão com a Internet. No Gears esta camada faz uso do SQLite, um banco de dados open source pequeno mas com muitas funcionalidades. Desktop Fornece acesso ao desktop como por exemplo a possibilidade de criar ícones na má- quina cliente facilitando o acesso a aplicação Web e tornando-a mais próxima de aplica- ções locais. Geolocation Permite que a aplicação Web acesse dispositivos da máquina cliente que infor- mam a localização do usuário como um módulo GPS. Esse recurso é utilizado por exem- plo em uma aplicação de mapas rodando em um celular para poder localizar a posição exata em que o usuário se encontra em um mapa. LocalServer Permite que requisições HTTP que normalmente seriam enviadas pela Internet para um servidor remoto, sejam respondidas pela mesma máquina cliente num servidor local. Este recurso acelera o funcionamento de uma aplicação Web e inclusive permite que uma certa aplicação funcione sem acesso a Internet, e conseqüentemente ao seu ser- vidor. Dentro do LocalServer existem ResourceStores que são utilizados para guardar conteúdo estático. WorkerPool Fornece recursos para fazer processamento Javascript em paralelo para evitar que um script complexo interrompa a fluidez da aplicação. 2.3.2 Arquitetura de Sistemas Baseados em Gears Como regra geral as aplicações Web são aplicações distribuídas do tipo fat server/thin cli- ent [Tanenbaum e Steen 2007], uma vez que o cliente ou browser é responsável apenas por renderizar a interface de usuário como mostra a Figura 1. Neste modelo cada vez que o usuário realiza qualquer interação com a aplicação é feita uma requisição ao servidor e este retorna uma página HTML que representa um snapshot do sistema como ilustrado na Figura 2.
  • 18. 11 Figura 1: Arquitetura tradicional de aplicações Web Figura 2: Diagrama de sequência tradicional para aplicações Web
  • 19. 12 Figura 3: Arquitetura proposta pelo Gears O Gears propõe uma arquitetura diferente [Gears API 2008]. Através dos módulos Local- Server e Database, descritos na seção 2.3.1, o Gears tem o poder de prover páginas localmente sem precisar contactar o servidor. Isso agiliza as chamadas e possibilita o uso das aplicações mesmo sem uma conexão a Internet. Nessa arquitetura as requisições passam primeiramente por um data switch que irá identificar se os dados devem ser requisitados para o servidor remoto ou para o servidor local. Caso a requisição vá para o servidor remoto o data switch encaminha a requisição para a camada de dados remotos, que por sua vez implementa a API para recuperar os dados remotamente. Caso a requisição seja encaminhada para a camada de dados local, os dados serão recuperados do banco de dados interno do Gears. Existe ainda uma camada op- cional de sincronização responsável por sincronizar os dados do banco de dados local com os dados do servidor remoto, essa sincronização normalmente é feita por um Worker Pool sendo assim executado em segundo plano. Esta arquitetura está ilustrada na Figura 3. Na arquitetura do Gears nem sempre as requisições precisam passar pelo servidor, vide Figura 4. Isto torna o processo todo bem mais rápido já que não depende da conexão com a In- ternet. O próprio Gears trata de encaminhar as requisições que não podem ser feitas localmente e sincronizar os dados remotos com os dados locais.
  • 20. 13 Figura 4: Diagrama de sequência para aplicações Web baseadas em Gears
  • 21. 14 3 METODOLOGIA Este capítulo mostra os passos principais no desenvolvimento de uma aplicação de anota- ções em Django que faz uso do Gears. 3.1 Aplicação de anotações A aplicação que foi desenvolvida é uma aplicação simples usada como base para imple- mentar o Gears utilizando o Django como framework do lado do servidor. Dentre as características da aplicação podemos citar: • Criação de anotações com título e conteúdo. • Possibilidade de visualizar as anotações mesmo sem acesso a Internet. • Possibilidade de criar anotações mesmo sem acesso a Internet. • Sincronização de anotações enquanto a aplicação está online, para enviar ao servidor as anotações criadas em modo offline. 3.2 Aplicação em Django O Django é um framework de código livre de alto nível que encoraja o desenvolvimento rápido de aplicações Web com design limpo e pragmático utilizando a linguagem Python. A linguagem Python por sua vez tem como principais características a rápida prototipação e o fato de ter uma biblioteca básica muito completa. O framework Django se baseia no design pattern MVC (Model View Controller) que pro- põe uma divisão clara entre as camadas de modelo, visão e controle (representação de dados, interface com usuário e lógica de negócio, respectivamente) da aplicação. Esta divisão facilita
  • 22. 15 a manutenção dos sistemas e a independência das camadas entre si e torna fácil a reestruturação completa de uma dessas camadas com poucas ou nenhuma modificação nas outras camadas. Os sistemas em Django são geralmente divididos em diversas aplicações Django. Cada aplicação implementa uma ferramenta específica e estas são “plugáveis” no sistema como um todo. Elas podem interagir entre si mas há uma separação clara de código. Este modelo mais uma vez facilita a manutenção dos sistemas e estimula o reaproveitamento de código de maneira muito prática. 3.2.1 Estrutura Básica de Sistemas Django Esta seção visa exemplificar a estrutura geral de uma aplicação Django e como os diferentes aplicativos são organizados e reutilizados. Bem como os pontos importantes para criar aplica- ções em Ajax com Django. Este trabalho não pretende documentar todos os passos envolvidos no desenvolvimento de aplicações Django. Uma análise mais detalhada pode ser encontrada na bibliografia [Holovaty e Kaplan-Moss 2008] ou na home page do projeto Django 1 . Após usar o comando python django-admin.py startproject project, o Django cria uma pasta “project” com a seguinte estrutura. project/ |-- __init__.py |-- manage.py |-- settings.py ‘-- urls.py O arquivo settings.py possui configurações diversas como informações do banco de da- dos, diretórios com templates, aplicações Django instaladas, entre outros. O arquivo urls.py possui o mapeamento de urls para “views”, em outras palavras indica qual função irá ser execu- tada quando cada url for acessada. Já o arquivo manage.py disponibiliza uma extensa coleção de scripts que gerenciam e automatizam a administração do sistema, pode-se usá-lo para criar 1 http://www.djangoproject.com/
  • 23. 16 uma nova aplicação Django. $ python manage.py startapp notes $ ls project/ |-- __init__.py |-- notes | |-- __init__.py | |-- models.py | ‘-- views.py |-- manage.py |-- settings.py ‘-- urls.py Neste momento é criada uma pasta “notes” que irá agrupar os arquivos referentes a este aplicativo e nele já existem os arquivos models.py e views.py que devem ser reescritos para conter a descrição dos dados e lógica de negócio. O código utilizado neste documento pode ser encontrado no Apêndice A. Após escrever estas duas camadas o aplicativo pode ser “plugado” alterando a seguinte sessão no arquivo settings.py. INSTALLED_APPS = ( ’django.contrib.auth’, ’django.contrib.contenttypes’, ’django.contrib.sessions’, ’django.contrib.sites’, ’project.notes’, ) Desta forma o aplicativo “notes” é plugado no sistema. É perceptível que o Django já vem com alguns aplicativos habilitados por padrão como por exemplo o “django.contrib.auth” que é responsável por gerenciar usuários do sistema. Uma vez que a maioria dos sistemas Web tem usuários, é natural que o Django já venha com esta aplicação, seguindo o modelo all under the hood do Python. Claro que esta aplicação pode ser desligada facilmente desabilitando o suporte a usuários e permissões.
  • 24. 17 Após plugar a aplicação, pode-se invocar o comando python manage.py syncdb para que o Django crie no banco de dados as tabelas que refletem os modelos definidos no arquivo models.py. O Django provê uma interface orientada a objeto para acesso aos dados através da camada de modelos. Desse modo não é preciso lidar com queries SQL, o que facilita o desenvolvimento e cria uma independência do DBMS 2 . 3.2.2 Implementando Ajax Uma boa prática no desenvolvimento de aplicações com Ajax, é se certificar de que a aplica- ção continuará funcionando corretamente mesmo sem o Javascript [Keith 2005]. Uma estratégia para atingir este objetivo é seguir os seguintes passos: 1. Construa uma aplicação sem Javascript utilizando links e formulários em HTML puro e crie a lógia no servidor para responder a estas requisições. 2. Depois adicione Javascript para interceptar essas chamadas e submissões de formulário realizando-as por Ajax e atualizando apenas parte da página. Desta forma é fácil criar aplicações Ajax que são compatíveis com navegadores sem Javas- cript, ou que continuem funcionando caso haja algum erro de Javascript. A lógica em Javascript usada para interceptar as requisições na aplicação anotações, pode ser encontrada no conteúdo do arquivo notes.js, na página 42 do apêndice A.2.2. Após implementar a lógica para interceptar essas requisições em Javascript é importante certificar-se que o servidor não irá responder da mesma forma as requisições simples e as re- quisições em Ajax. Felizmente o Django provê uma maneira simples de identificar a origem da requisição através da função request.is_ajax() dentro de uma “view”. Isso é possível graças ao jQuery que insere um cabeçalho a mais na requisição HTTP facilitando sua identificação. No caso de a requisição ser feita via Ajax, a “view” não precisa retornar a página completa, apenas os dados que serão inseridos dentro da página. Estes dados podem ser retornados como HTML, texto puro, XML ou Json. O Json tem a vantagem de ser um formato compatível com um objeto Javascript e devido a isso o trabalho de extrair os dados se torna mais simples. 2 Data Base Management System: Sistema gerenciador de bancos de dados
  • 25. 18 Neste exemplo utilizamos o Django para listar todas as notas, gerar Json caso a requisição seja feita via Ajax e renderizar a página completa caso seja uma requisição normal. def note_list(request): n = Note.objects.all() form = NoteForm() if request.is_ajax(): response = HttpResponse(mimetype="application/json") json_serializer = serializers.get_serializer("json")() json_serializer.serialize(n, ensure_ascii=False, stream=response) return response else: return render_to_response(’notes/note_list.html’, { ’object_list’ : n,’form’ : form}, context_instance=RequestContext(request))
  • 26. 19 3.3 Implementação do Gears O Gears é flexível e a maneira como o desenvolvedor vai implementa-lo depende das ne- cessidades da aplicação e da dificuldade de implementação. O desenvolvedor deve ponderar a quantidade de trabalho a ser realizado e o benefício para o usuário final. Na maioria das vezes não faz sentido fazer com que toda aplicação esteja disponível offline [Gears FAQ 2008]. A medida que se acrescentam funcionalidades offline se torna necessário um mecanismo de sincronização. Este provavelmente é o momento mais complexo e sujeito a erros na implemen- tação do Gears. Para inicializar o Gears sempre se deve usar o arquivo gears_init.js que o Google dis- ponibiliza. Este script torna disponível a variável global google dentro do Javascript caso o Gears esteja instalado. Com isso podemos redirecionar o usuário para uma página de instalação caso o Gears não esteja instalado. if (!window.google || !google.gears) { location.href = ’http://gears.google.com/?action=install&’ + ’message=Baixe o Google Gears para Continuar’ + ’&return=http://localhost/notes’; } Uma vez que o Gears esteja instalado é exibido para o usuário um diálogo de segurança como o ilustrado na figura 5. Figura 5: Confirmação para permitir que a aplicação use o Gears para guardar dados
  • 27. 20 3.3.1 Implementação Modal ou Amodal A primeira decisão a ser tomada é como o Gears será habilitado e o usuário irá interagir com ele. As opções são as seguintes [Kilani 2007]: 1. Modal: O usuário deve clicar em um botão na interface que troca para o modo offline e de volta para o modo online. O Google Reader e o Remember the Milk, são dois exemplos de aplicação que utilizam este sistema. 2. Amodal: O sistema entra em modo offline automaticamente caso a Internet não esteja acessível. Este é o modelo de implementação usado no Gmail. O modelo Modal é geralmente mais simples de implementar e dependendo da aplicação pode ser o modelo ideal. A aplicação de anotações poderia ser implementada utilizando este modelo, porém decidiu-se utilizar o modelo Amodal para fins de pesquisa. 3.3.2 Conteúdo Estático Tornar o conteúdo estático offline é uma operação relativamente simples no Gears. Por este motivo este geralmente é o primeiro passo tomado pelos desenvolvedores. Além disso este é um dos recursos que mais aceleram o funcionamento da aplicação para o usuário final. Como todos os recursos estão alocados localmente a aplicação não precisa acessar a Internet, ou então acessa a Internet com muito menos frequência, e a velocidade se aproxima da velocidade de uma aplicação desktop. Este recurso usa o módulo LocalServer do Gears. Este módulo possui 3 classes, dessas iremos abordar apenas 2 necessárias para capturar e prover os recursos estáticos em um site: A classe LocalServer e a classe ManagedResourceStore. Com essas duas classes pode-se fazer o cache de arquivos estáticos como páginas HTML, código Javascript, documentos CSS, imagens, etc.
  • 28. 21 Primeiro deve-se escrever um arquivo manifest.json com os arquivos que deverão ser baixados. Exemplo de arquivo manifest.json: { "betaManifestVersion": 1, "version": "v1", "entries": [ { "url": "/notes/"}, { "url": "/media/notes/gears_init.js"}, { "url": "/media/notes/jquery.js"}, { "url": "/media/notes/notes.js"}, { "url": "/media/notes/django_gears.js"}, { "url": "/media/notes/datalayer.js"}, { "url": "/media/notes/style.css"}, { "url": "/media/notes/gears_icons.png"} ] } O Gears fica fazendo requisições repetidamente pelo arquivo manifest.json, essas geral- mente são retornadas com o código HTTP 304 (“Not Modified”). Porém caso o arquivo seja modificado ele recebe a nova versão. Caso um dos arquivos seja atualizado basta atualizar o pa- râmetro version do manifest para que as atualizações sejam buscadas. Caso contrário o Gears irá sempre prover a versão local carregada anteriormente. Esse mecanismo funciona analogamente ao mecanismo de cache do HTTP, com a diferença que ele não precisa checar as modificações para cada arquivo, o Gears apenas checa pelas modificações no arquivo manifest.json. Inicie o localserver em todas as páginas para ter certeza que sempre tem o ultimo manifest.json. localServer = google.gears.factory.create("beta.localserver"); store = localServer.createManagedStore(’mystore’); store.manifestUrl = ’http://localhost/media/notes/manifest.json’; store.checkForUpdate();
  • 29. 22 3.3.3 Identificando Estado Online/Offline Caso o Gears seja implementado usando a forma Amodal, precisa-se descobrir o status da aplicação. O Gears não possui uma interface simples para verificar se a aplicação está online ou offline, porém é fácil implementar em Javascript uma rotina que faça esta verificação. Segue uma rotina que faz este procedimento: var request = google.gears.factory.create(’beta.httprequest’); var online = false; function pingSuccess() { if(request.responseText.indexOf("ok") >= 0){ online = true; } else { online = false; } } function isServerAvailable() { var resource_to_test = "/media/notes/gears_test.txt"; var TIME_BETWEEN_PINGS = 3*1000; var PING_TIMEOUT_SECONDS = 1*1000; //parâmetro randômico para não receber arquivo em cache. resource_to_test += "?q=" + Math.floor(Math.random() * 100000); request.open(’GET’, resource_to_test); window.setTimeout("pingSuccess()",PING_TIMEOUT_SECONDS); request.send(); window.setTimeout("isServerAvailable()",TIME_BETWEEN_PINGS); } isServerAvailable(); Esta rotina basicamente busca um arquivo no servidor a cada 3 segundos. Este arquivo deve existir dentro do servidor como um arquivo texto puro com o conteúdo “ok”. Dependendo da resposta da requisição a rotina marca a variável online para refletir o estado da aplicação. Pode ser importante ou não saber o estado da aplicação, dependendo da forma de sincroni- zação que será utilizada. No exemplo incluído nesta monografia a aplicação faz uso desta rotina para informar ao
  • 30. 23 usuário o estado atual, e para desativar a sincronização dos dados com o servidor. 3.3.4 Camada de Dados A maioria das aplicações Web não possuem uma camada de dados bem definida. Isso porque como a fonte de dados era apenas uma não fazia sentido criar esta abstração. Nestes casos a implementação é mais complicada pois toda a aplicação deve ser reescrita para usar a nova camada de dados. A camada de dados é uma interface em Javascript para acesso aos dados da aplicação. É importante a construção desta camada, pois uma vez que implementa-se o Gears os dados poderão vir de duas origens distintas. O servidor ou banco de dados local. Aplicações tradicionais fazem uma requisição ao servidor pedindo por um determinado conjunto de dados. Dependendo da aplicação e implementação, esses dados podem vir em dife- rentes formatos: texto puro, HTML, XML, Json, etc. Depois que esses dados são recuperados a página é atualizada para mostrar os dados. Porém uma vez que implementamos o Gears os dados que são recuperados do banco de dados local vêm dentro de um Gears ResultSet (classe do módulo Database). Portanto tem- se um retorno diferente dependendo da origem dos dados. A camada de dados dentro de uma aplicação Web deve ser construída para normalizar os dados que são passados para a aplicação. A seguir é apresentado como a aplicação de anotações usa a camada de dados para fazer requisição de dados. var dl = new datalayer; dl.getNote(7,function(){ //mostra o titulo da Nota com id 7 em uma caixa de diálogo alert(this.fields.title); }); A classe datalayer irá verificar a existência do Gears. Caso este esteja instalado ela irá buscar a nota no banco do Gears caso não esteja instalado, o DataLayer irá fazer uma requisição Ajax ao servidor.
  • 31. 24 Exemplo de implementação de Camada de Dados: function datalayer(){}; //Seleciona uma ou todas as notas do Gears ou da Web caso este não esteja disp. datalayer.prototype.getNotes = function(id,callback){ try{ var sql = ’SELECT * FROM notes_note ’, json_r = []; if(id>=0){ sql += ’WHERE id = ’+id+’;’ } //Já retorna um Json igual ao retornado pelo Django json_r = dg.queryToObject(sql); return cb(json_r); }catch(e){ if(id>=0) return $.getJSON(’/notes/’+id+’/’,cb); return $.getJSON(’/notes/’,cb); } }; Percebe-se que independente de usar ou não o Gears o retorno é sempre um objeto Json com os dados requisitados. Esta é a abstração desejada nesta implementação. O conteúdo dinâmico das páginas deve ser armazenado dentro do banco de dados local utilizando a interface Javascript do módulo Database do Gears. Pode-se interagir com o banco de dados através de queries SQL, da mesma maneira com que se interage com um banco de dados no servidor. Porém com tudo sendo executado do lado do cliente. 3.3.5 Sincronização A sincronização dos dados locais com os dados remotos é um dos pontos mais difíceis na implementação do Gears. O desenvolvedor mais uma vez precisa ponderar que nível de sincronização faz sentido dentro da sua aplicação. O Gears não vem com nenhuma funcionalidade que implemente a sincronização automati- camente. Ao invés disso o desenvolvedor deve criar um mecanismo de sincronização.
  • 32. 25 A seguir são apresentadas algumas estratégias de sincronização por ordem de complexidade e comentários sobre a implementação de cada uma delas. Apenas Leitura Offline Neste modo baixa-se todo conteúdo, ou parte dele para o cliente. A partir daí sempre que necessário, pode-se ler o conteúdo localmente, o que acelera muito o funcionamento da aplicação. Quando alguma modificação é feita no servidor, descarta-se todo conteúdo local e “baixa” o novo conteúdo. Este é o modo mais fácil de usar o Gears para acelerar o acesso das aplicações aos dados e permite que as aplicações sejam utilizadas offline apenas para leitura. A rede social MySpace utiliza esta estratégia com Gears para acelerar as buscas no site. Todos os contatos são baixados para a máquina do usuário, e as buscas por Amigos são reali- zadas localmente. Além de livrar o servidor da carga que existe por trás de uma busca do tipo full-text-search, acelera a interface. Leitura e Escrita Offline Com uma aplicação implementando o modo somente leitura com o Gears, pode-se passar para o próximo passo. Gravar as modificação localmente. Ao invés de enviar as alterações para o servidor, fazer estas alterações diretamente no banco de dados local, tornando desnecessário carregar todos os dados novamente a cada alteração de registros. Assim a aplicação fica disponível offline tanto para leitura como para edição, porém como as modificações não são feitas no servidor perde-se uma das grandes vantagens das aplicações nas nuvens que é a vantagem de poder acessar a aplicação de qualquer localidade. Deste modo os dados vão estar sempre no cliente, e caso se mude de navegador se perde os dados. O fato de os dados nunca irem para o servidor pode ser uma vantagem. Desta maneira é possível a criação de sistemas em que os dados são apenas locais, introduzindo um nível de segurança novo em aplicações Web. Pode-se imaginar, por exemplo, uma aplicação de controle financeiro desenvolvida dessa maneira. A atualização do código da aplicação ainda pode ser feita de modo remoto, porém toda a lógica e dados ficam na máquina do usuário e nunca são enviadas para a Internet.
  • 33. 26 Sincronização Mono-usuário Esta é uma estratégia para implementar a sincronização online e offline, utilizando a pre- missa de que um usuário nunca poderá estar logado mais de uma vez no sistema. Num primeiro momento baixamos todos os dados do servidor localmente. Depois sempre que uma gravação for efetuada nos dados locais ela será marcada com uma flag para que seja enviada para o servidor assim que possível. Uma rotina é executada periodicamente que verifica se existem modificações na base local para que sejam enviadas para o servidor. Assim que a modificação é enviada para o servidor marca-se a informação como enviada. É interessante criar uma coluna de chave primária no banco de dados local, independente da coluna de chave primária do servidor, para evitar problemas de conflito. Pode-se usar o mesmo esquema do banco de dados do servidor dentro do Gears porém adicionando a coluna id_server para manter uma referência ao “id” real do registro. Sincronização Multi-usuário Esta seria a estratégia mais completa, porém a mais complexa de ser implementada. Além de gravar as modificações feitas na base local e no servidor, precisa-se consultar o servidor periodicamente para ter os dados mais atualizados. Um evento de sincronização deve ser disparado periodicamente. Como a sincronização pode se tornar um processo custoso, deve ser, de preferência, executada dentro de um WorkerPool, para que não interfira com o funcionamento da aplicação para o usuário. A seguir é apresentada a rotina em Javascript da aplicação Anotações que busca as atuali- zações na base de dados remota. Esta rotina usa uma tabela local notes_version que guarda o timestamp da última atualização, e requisita as notas alteradas depois desse timestamp. djGears.prototype.get_updates = function(){ var rs; //set new updated time this.query(’update notes_version set last_mod = datetime("now");’); //Only import the new ones $.getJSON(’/notes/?xhr=1&last_mod=’+this.last_mod+’’,function(r){ for (var n in r){
  • 34. 27 if (r[n].pk === undefined){ continue; } dg.query(’insert into notes_note ’+ ’(id_server,title, content,mod_date) values (?,?,?,?)’, [r[n].pk, r[n].fields.title, r[n].fields.content, r[n].fields.mod_date]); } }); rs = this.query(’select version,strftime("%s",last_mod) ’+ ’from notes_version’); if(rs.isValidRow()){ this.version = rs.field(0); this.last_mod = rs.field(1); } rs.close(); } Este processo inclui um novo problema de implementação, que é a questão de conflitos. As vezes modificações feitas no servidor e as modificações feitas localmente podem representar um conflito. Neste caso temos que introduzir uma maneira de resolver este conflito. Algumas opções ordenadas por dificuldade são: • Substituir a versão local pela do servidor. • Mostrar um diálogo ao usuário para que ele faça a resolução do conflito. • Tentar fazer uma resolução de conflitos automaticamente.
  • 35. 28 4 CONCLUSÃO Este capítulo apresenta os resultados obtidos pelo estudo desta arquitetura inovadora pro- posta pelo Gears, bem como dificuldades encontradas durante o projeto de desenvolvimento. 4.1 Análise da Arquitetura Proposta As novas aplicações Web trazem a lógica cada vez mais para o lado do cliente. Isso faz com que o código Javascript das aplicações se torne relativamente grande e complexo. É importante conhecer bem as novidades dessa linguagem que tornam o desenvolvimento de grandes bases de código mais amigável. A arquitetura proposta pelo Gears demonstrada na seção 2.3.2 (página 10) cria um novo paradigma para desenvolvimento de aplicações Web, introduzindo funcionalidades nunca antes disponíveis nesta plataforma. 4.2 Contribuições Este trabalho documenta a criação de uma aplicação rica da Web desenvolvida em Django e utilizando o Gears para prover funcionalidades offline. Focando nos passos mais importantes e nas decisões que devem ser tomadas pelo desenvolvedor que pretende implementar o Gears. Outra contribuição é a análise da arquitetura proposta pelo Gears e como isso pode afetar o futuro das aplicações Web. 4.3 Dificuldades Encontradas As Aplicações Ricas da Internet são desenvolvidas em Python (ou qualquer outra linguagem server side) e Javascript. O fato de ter que trabalhar com duas linguagens simultaneamente pode
  • 36. 29 causar confusão durante o desenvolvimento. Não só pelo fato de a sintaxe ser diferente, mas também pelo fato de o Javascript ser uma linguagem que possui alguns paradigmas incomuns como a orientação a eventos e o escopo baseado em closures. As aplicações Web podem ser difíceis de depurar. Uma das melhores ferramentas para fazer debug é o FireBug, extensão para o Firefox que permite adicionar breakpoints e fazer trace do código. Pelo Gears ser uma tecnologia muito nova e com muitas possibilidades, é difícil encontrar bom material de exemplo e bibliografia. Por sorte o Google provê uma boa documentação da API [Gears API 2008] e de problemas comuns [Gears FAQ 2008]. Mesmo assim algumas funcionalidades não são documentadas. 4.4 Propostas de Extensão Dentre possíveis extensões para a continuidade deste trabalho estão: • Estudo da arquitetura do Adobre AIR traçando um paralelo com as funcionalidades do Gears. • Estudo das novas funcionalidades do HTML5 e como essas funcionalidades complemen- tam ou substituem as funcionalidades do Gears. • Desenvolvimento de aplicação para facilitar a criação de mecanismos de sincronização no Gears.
  • 37. 30 Referências Bibliográficas [Gears API 2008]GEARS API. [S.l.], 2008. Documentação da API do Google Gears. Disponí- vel em: <http://code.google.com/apis/gears/design.html>. Acesso em: 30/05/2009. [Gears FAQ 2008]GEARS FAQ. [S.l.], 2008. Perguntas e Respostas Frequentes sobre o Google Gears. Disponível em: <http://code.google.com/apis/gears/gears_faq.html>. Acesso em: 30/05/2009. [Google 2009]GOOGLE. Web Storage Portability Layer: A Common API for Web Storage. [S.l.], 2009. Anúncio do WSPL do Google. Disponível em: <http://google- opensource.blogspot.com/2009/05/web-storage-portability-layer-common.html>. Acesso em: 31/05/2009. [Holovaty e Kaplan-Moss 2008]HOLOVATY, A.; KAPLAN-MOSS, J. The Definitive Guide to django: Web development done right. 1. ed. [S.l.]: Apress, 2008. ISBN 978-1590597255. [Keith 2005]KEITH, J. DOM Scripting: Web design with javascript and the document object model. Friends of ED, 2005. 368 p. ISBN 978-1-59059-533-6. Disponível em: <http://www.friendsofed.com/book.html?isbn=1590595335>. [Kilani 2007]KILANI, O. Taking web applications offline with gears. 2007. Disponí- vel em: <http://code.google.com/apis/gears/articles/take_app_offline.html>. Acesso em: 04/12/2008. [Krug 2005]KRUG, S. Don’t Make Me Think: A common sense approach to web usability. 2. ed. [S.l.]: New Riders Press, 2005. ISBN 978-0321344755. [Miller 2008]MILLER, M. Cloud Computing: Web-based applications that change the way you work and collaborate online. [S.l.]: Que, 2008. ISBN 978-0789738035. [Taivalsaari e Ingalls 2008]TAIVALSAARI, A.; INGALLS, D. Web browser as an application platform: The lively kernel experience. 2008. [Tanenbaum e Steen 2007]TANENBAUM, A.; STEEN, M. V. Sistemas Distribuídos: Princí- pios e paradigmas. 2. ed. São Paulo, SP: Pearson, 2007. 416 p. ISBN 978-8576051428.
  • 38. 31 APÊNDICE A -- Aplicação em Django utilizando Gears Neste Apêndice está documentada uma aplicação simples de anotações utilizando Django e disponibilizando todas as funcionalidades offline com o Gears. A.1 Interface Telas da aplicação de Anotações. Figura 6: Tela listando todas as notas.
  • 39. 32 Figura 7: Tela mostrando uma determinada nota.
  • 40. 33 A.2 Arquivos Nesta seção estão documentados os arquivos principais da implementação da aplicação de anotações. project |-- __init__.py |-- db.sqlite <-- Banco de dados do lado do Servidor |-- manage.py <-- Arquivo do django de gerenciamento de projetos e aplicações |-- notes <-- Aplicação django | |-- __init__.py | |-- admin.py <-- Configura interface de Administração do django | |-- app_media <-- Arquivos estáticos | | ‘-- notes | | |-- datalayer.js <-- Camada de abstração de dados | | |-- django_gears.js <-- Funções de sincronização e setup do Gears | | |-- gears_icons.png | | |-- gears_init.js <-- Arqivo padrão para inicializar o Gears | | |-- gears_test.txt <-- Usado para testar se o cliente esta online | | |-- jquery.js <-- Biblioteca que facilita o uso do DOM e Ajax | | |-- manifest.json <-- manifest do Gears | | |-- notes.js <-- Biblioteca que faz alterações na interface | | ‘-- style.css | |-- forms.py | |-- models.py <-- Define modelo de dados | |-- templates <-- django templates, usados pelas views | | ‘-- notes | | |-- base.html | | |-- note_detail.html | | ‘-- note_list.html | |-- urls.py <-- Faz mapeamento de urls e views para esta aplicação | ‘-- views.py <-- Lógica de negócio |-- settings.py <-- Configuração do django ‘-- urls.py <-- Mapeamento de urls do projeto
  • 41. 34 A.2.1 Django Arquivos mais relevantes na implementação do Django da aplicação. models.py from django.db import models from datetime import datetime class Note(models.Model): mod_date = models.DateTimeField(’date modified’) title = models.CharField(max_length=200) content = models.TextField() def __unicode__(self): return self.title def get_absolute_url(self): return "/notes/%i/" % self.id def save(self, force_insert=False, force_update=False): self.mod_date = datetime.utcnow() super(Note, self).save(force_insert, force_update) urls.py from django.conf.urls.defaults import * from notes.models import Note urlpatterns = patterns(’notes.views’, (r’^$’, ’note_list’), (r’^add/$’, ’note_add’), (r’^(?P<id>d+)/$’, ’note_detail’), (r’^sync/$’, ’sync’), ) views.py from django.http import HttpResponse, HttpResponseRedirect from django.core import serializers from django.shortcuts import get_object_or_404, render_to_response from notes.models import Note
  • 42. 35 from django.template import RequestContext from notes.forms import NoteForm from datetime import datetime def note_list(request): form = NoteForm() if request.GET.has_key("last_mod") and request.GET[’last_mod’].isdigit(): #recuperando notas alteradas apenas a partir de certa data n = Note.objects.filter(mod_date__gt=datetime.fromtimestamp( int(request.GET[’last_mod’]))) else: n = Note.objects.all() if request.is_ajax() or request.GET.has_key("xhr"): response = HttpResponse(mimetype="application/json") json_serializer = serializers.get_serializer("json")() json_serializer.serialize(n, ensure_ascii=False, stream=response) return response else: return render_to_response(’notes/note_list.html’, { ’object_list’ : n,’form’ : form}, context_instance=RequestContext(request)) def note_detail(request, id): n = get_object_or_404(Note, pk=id) if request.is_ajax() or request.GET.has_key("xhr"): n = Note.objects.filter(id=id) response = HttpResponse(mimetype="application/json") json_serializer = serializers.get_serializer("json")() json_serializer.serialize(n, ensure_ascii=False, stream=response) return response else: return render_to_response(’notes/note_detail.html’, {’object’:n}, context_instance=RequestContext(request)) def note_add(request): if request.method == ’POST’: form = NoteForm(request.POST)
  • 43. 36 if form.is_valid(): form.save() return HttpResponseRedirect(’/notes/’) else: return HttpResponseRedirect(’/notes/’) def sync(request): if request.method == ’POST’: for deserialized_object in serializers.deserialize("json", request.POST[’data’]): obj = deserialized_object.object deserialized_object.save() if(obj.pk): return HttpResponse(obj.pk) assert(False) return HttpResponse(’ERROR’) A.2.2 Gears Arquivos mais relevantes na implementação do Gears na aplicação. django_gears.js function djGears(){ this.STORE_NAME = "offline_notes"; this.MANIFEST_FILENAME = "/media/notes/manifest.json"; this.online=false; this.setup_store(); this.db = google.gears.factory.create(’beta.database’); this.db.open(’db’); try { var rs; rs = this.query( ’select version,strftime("%s",last_mod,"utc") from notes_version’); console.log(rs); console.trace(); this.version = rs.field(0);
  • 44. 37 this.last_mod = rs.field(1); rs.close(); } catch (e) { console.error("DB needs setup: "+ e.message); this.setup_db(); } this.get_updates(); } djGears.prototype.setup_db = function(){ try{ //Create tables this.query(’BEGIN’); var sql = ’CREATE TABLE IF NOT EXISTS "notes_note" (’+ ’ "id" integer NOT NULL PRIMARY KEY,’+ ’ "id_server" integer,’+ ’ "mod_date" datetime NOT NULL,’+ ’ "title" varchar(200) NOT NULL,’+ ’ "content" text NOT NULL’+ ’);’+ ’CREATE UNIQUE INDEX IF NOT EXISTS "notes_note_id_server" ’+ ’ON "notes_note" ("id_server");’; this.query(sql); sql = ’CREATE TABLE IF NOT EXISTS notes_version ’+ ’("version" integer not null primary key, "last_mod"’+ ’ datetime not null);’; this.query(sql); this.query(’COMMIT’); this.query(’INSERT INTO notes_version VALUES (1,0);’); } catch (ex) { console.error(’Could not create database: ’ + ex.message); } }; djGears.prototype.query = function(sql, arr){ var ret;
  • 45. 38 try{ console.info(sql,arr); return this.db.execute(sql,arr); }catch(e){ console.error("query error:" + e.message +":" +sql+arr); throw e; } }; djGears.prototype.queryToObject = function(sql, args) { var rs = this.query(sql, args); try { var rv = [], h; if (rs && rs.isValidRow()) { while (rs.isValidRow()) { h = {fields: {}}; h.pk = rs.fieldByName(’id’); h.model = ’notes.note’; for (i = 0; i < rs.fieldCount(); i++) { h.fields[rs.fieldName(i)] = rs.field(i); } rv.push(h); rs.next(); } } } catch (e) { throw e; } finally { rs.close(); return rv; } } djGears.prototype.setup_store = function(){ if(!window.google || !google.gears) { location.href = "http://gears.google.com/?action=install" + "&return=localhost/notes/";
  • 46. 39 }else{ localServer = google.gears.factory.create("beta.localserver"); this.store = localServer.createManagedStore(this.STORE_NAME); this.store.manifestUrl = this.MANIFEST_FILENAME; this.store.checkForUpdate(); } }; djGears.prototype.get_updates = function(){ try{ var rs; //Only import the new ones $.getJSON(’/notes/?xhr=1&last_mod=’+this.last_mod+’’,function(r){ for (var n in r){ if (r[n].pk === undefined){ continue; } dg.query(’insert into notes_note ’+ ’(id_server,title, content,mod_date) values (?,?,?,?)’, [r[n].pk, r[n].fields.title, r[n].fields.content, r[n].fields.mod_date]); } }); //set new updated time this.query(’update notes_version set last_mod = datetime("now");’); rs = this.query( ’select version,strftime("%s",last_mod,"utc") from notes_version’); if(rs.isValidRow()){ this.version = rs.field(0); this.last_mod = rs.field(1); } rs.close(); } catch (ex) { console.error(’Import error: ’ + ex.message);
  • 47. 40 } } djGears.prototype.send_updates = function(){ try{ var obj; if(this.tsend){ clearTimeout(this.tsend); } //get new rows obj = this.queryToObject( ’select id,title,content,mod_date from notes_note ’+ ’where id_server is null limit 1;’); if(typeof obj[0] == ’undefined’ || typeof obj[0].pk == ’undefined’){ console.log(’App atualizada’); return false; } if(!this.online){ this.tsend = window.setTimeout("dg.send_updates()",9*1000); console.log(’Aplicação offline remarcando send_updates’); return false; } this.get_updates(); //Export $.post(’/notes/sync/’,’data=’+JSON.stringify(obj),function(text){ var id = parseInt(text); if(id && id>=0){ dg.query("update notes_note set id_server = ? ’+ ’where id = ? ",[id,obj[0].pk]); dg.send_updates(); } }); }catch (ex){ console.error(’Export error: ’ + ex.message) } }
  • 48. 41 //Check if Online if(window.google && google.gears) { var request = google.gears.factory.create(’beta.httprequest’); var dg = new djGears(); function pingSuccess() { if(request.responseText.indexOf("ok") >= 0){ $("#gears").attr(’class’, ’online’); $("#gears_status").text("Online"); dg.online=true; } else { $("#gears").attr(’class’, ’offline’); $("#gears_status").text("Offline"); dg.online=false; } } function isServerAvailable() { var resource_to_test = "/media/notes/gears_test.txt"; var TIME_BETWEEN_PINGS = 3*1000; var PING_TIMEOUT_SECONDS = 1*1000; resource_to_test += "?q=" + Math.floor(Math.random() * 100000); request.open(’GET’, resource_to_test); window.setTimeout("pingSuccess()",PING_TIMEOUT_SECONDS); request.send(); window.setTimeout("isServerAvailable()",TIME_BETWEEN_PINGS); } isServerAvailable(); } datalayer.js function datalayer(){}; /** * Get all or one object from local database or, if not possible, from the web */ datalayer.prototype.getNotes = function(id,cb){ try{
  • 49. 42 var sql, json_r = []; sql = ’SELECT * FROM notes_note ’; if(id>=0){ sql += ’WHERE id = ’+id+’;’ } json_r = dg.queryToObject(sql); return cb(json_r); }catch(e){ return $.getJSON(’/notes/?xhr=1’,cb); } }; /** * Funcao deve ser passada para o contexto de um formulario */ datalayer.prototype.postNote = function(e,cb){ var event = e || window.event; var el = event.target || event.srcElement; try{ var sql,arr; sql = ’INSERT INTO notes_note (title,content,mod_date) ’+ ’VALUES (?,?,datetime("now"))’; arr = [el.title.value, el.content.value] dg.query(sql,arr); cb(); dg.send_updates(); }catch(e){ $.post($(el).attr(’action’),$(el).serialize(),cb); } }; var dl = new datalayer(); notes.js Funções responsáveis por invocar o datalayer e fazer modificações na interface do usuário. Faz uso de instruções da biblioteca jQuery.
  • 50. 43 function loadNotes(event){ dl.getNotes(-1,function(data){ $("#notas").empty(); $("#notas").append(document.createElement(’ul’)); $.each(data, function(){ $("#notas").children(":first").append(’<li>’+ ’<a href="/notes/’+this.pk+’/">’+this.fields.title+’</a></li>’); }); $(’<form id="add_nota" method="post" action="/notes/add/">’+ ’<p><label for="id_title">Title:</label> <input type="text" maxlength=’+ ’"200" name="title" id="id_title"/></p><p><label for="id_content">’+ ’Content:</label> <textarea name="content" cols="40" rows="10" ’+ ’id="id_content"/></p><input type="submit" value="Submeter"/></form>’) .appendTo(’#notas’); $("#add_nota").submit(NovaNota); RegisterListEvents(); }); if (event) { event.preventDefault(); } } function NovaNota(event){ dl.postNote(event,function(){ loadNotes(); }); event.preventDefault(); } function RegisterListEvents(){ $("#notas li>a").unbind(’click’); $("#notas li>a").click(function(event){ var pk = /.*/notes/(d+)//.exec($(this).attr("href"))[1]; dl.getNotes(parseInt(pk), function(data){ $("#notas").empty();
  • 51. 44 $.each(data,function(){ $(’#notas’).append(’<h2>’+this.fields.title+’</h2>’); $(’#notas’).append(’<pre>’+this.fields.content+’</pre>’); }); event.preventDefault(); }); }); } function RegisterSidebarEvents(){ $("#note_menu").unbind(’click’); $("#note_menu").click(loadNotes); } $(document).ready(function(event){ RegisterListEvents(); RegisterSidebarEvents(); loadNotes(); });