UNIVERSIDADE FEDERAL DO PARANÁ PROGRAMA DE PÓS-GRADUAÇÃO EM TECNOLOGIA ESPECIALIZAÇÃO EM TECNOLOGIA JAVA DOMINGOS DE CARVALHO VILLELA JÚNIOR COMPUTAÇÃO EM NUVEM: Desenvolvimento de aplicações empresariais ricas na internet, na Arquitetura Java, Google Web Toolkit e Google Application Engine MONOGRAFIA DE ESPECIALIZAÇÃO CORNÉLIO PROCÓPIO 2011 1 DOMINGOS DE CARVALHO VILLELA JÚNIOR COMPUTAÇÃO EM NUVEM: Desenvolvimento de aplicações empresariais ricas na internet, na Arquitetura Java, Google Web Toolkit e Google Application Engine Monografia de Especialização apresentada ao Programa de Pós-Graduação em Tecnologia da Universidade Tecnológica Federal do Paraná como requisito parcial para obtenção do título de ―Especialista em Tecnologia JAVA‖ - Área de Concentração: Computação Ubíqua. Orientador: Prof. Me. Rodrigo Henrique Cunha Palácios CORNÉLIO PROCÓPIO 2011 2 À Sueli, Priscila e Rebeca, e aos desenvolvedores de softwares que investem na computação ubíqua. 3 AGRADECIMENTOS Reverencio o Professor Me. Rodrigo Henrique Cunha Palácios pela sua dedicação e orientação deste trabalho. Agradeço à Google pelo fornecimento dos recursos de software e hardware para o desenvolvimento deste trabalho. Também gostaria de deixar registrado o meu agradecimento à minha família, pelas horas não dedicadas à minha esposa e filhas nos finais de semana. 4 People who love what they do, are usually those who are doing what they love. (Peter Serchuk, Executive Creative Director, McCannErickson, Los Angeles.) As pessoas que amam o que fazem, são geralmente aquelas que estão fazendo o que amam. (Peter Serchuk, Diretor Executivo de Criação, McCann-Erickson, Los Angeles.) 5 RESUMO VILLELA, Domingos de Carvalho Júnior. Computação em Nuvem: Desenvolvimento de aplicações empresariais ricas na internet RIA, na arquitetura Java, Google Web Toolkit ―GWT 2‖ e Google App Engine. 2011. 102 f. Monografia (Especialização em Tecnologia JAVA) – Programa de Pós-Graduação em Tecnologia, Universidade Tecnológica Federal do Paraná, Cornélio Procópio, 2011. Esta pesquisa apresenta uma nova abordagem na forma de se desenvolver sistemas empresariais. Esta inovação é a computação em nuvem, no qual os sistemas serão projetados e desenvolvidos para serem implantados em data centers altamente confiáveis e seguros. Com isto as empresas deixarão de administrar o banco de dados, unidades centrais de processamento, redes de comunicação de dados, controle de acesso, cópias de segurança dos dados e sistemas, e recursos humanos de tecnologia da informação. A proposta deste projeto foi utilizar o software e o hardware da Google, o Google App Engine em conjunto com o Google Web Toolkit 2.1. Este trabalho de pesquisa abordou a evolução da computação, computação em nuvens, aplicações ricas para internet RIA, WEB 2.0, Crome OS, Google App Engine, Sandbox, Dynamic HTML, Cascading Style Sheets, Document Object Model, Ajax, WidGets, Java Data Objects e o Google Web ToolKit. Traz como resultado a implantação um estudo de caso no data center da Google, demonstrando uma proposta inicial de projeto nas nuvens. Palavras-chave: Computação em nuvens. Google Web ToolKit. Google App Engine. 6 ABSTRACT VILLELA JR., Domingos de Carvalho. Cloud computation: Development of business applications in the RIA, in the JAVA architecture, ―GWT 2‖ Google Web Toolkit, and Goggle App Engine. 2011. 102 pp. Term paper (Specialization in JAVA Technology – Graduate Program in Technology, Universidade Tecnológica do Paraná, Cornélio Procópio, 2011. This research presents a new approach in the way how business systems are developed. Such an innovation is called cloud computing, in which systems are projected and developed in order to be implanted into highly reliable and safe data centers. By means of such a device companies will stop managing databanks, central processing units, data communications newtworks, access control, data and system security backups, and IT human resources. The proposal of this project was to use Google software and hardware, Google App Engine jointly with Google Web Toolkit 2.1. This research paper broached the development of computation, cloud computation, RIA, WEB 2, Crome OS, Google App Engine, Sandbox, Dynamic HTML, Cascading Style Sheets, Document Object Model, Ajax, WidGets, Java Data Objects and Google Web Toolkit. Such an implantation has as a result a case study in Google data center, giving a demonstration of the initial proposal of the cloud computing project. Keywords: Cloud computing. Google Web Toolkit. Google App Engine 7 LISTA DE CÓDIGOS Código 1 Código 2 Código 3 Código 4 Código 5 Código 6 Código 7 Código 8 Código 9 Código 10 Código 11 Código 12 Código 13 Código 14 Código 15 Código 16 Código 17 Código 18 Código 19 Código 20 Código 21 Código 22 Código 23 Código 24 Código 25 Código 26 Código 27 Código 28 Código 29 Código 30 Código 31 – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – Exemplo de CSS Exemplo de Código HTML Exemplo de anotações POJO e JDO Folha de estilo do date picker Fonte do DatePicker Java/GWT Exemplo de um arquivo gwt.xml para definição de módulos Ativação do gerenciamento de histórico de navegação do GWT Código para exibir mensagem do status do navegador Implementação da classe SimpleCallback Classe Presenter<D> Classe LoginFormPresenter Interface LoginFormDisplay Interface Display Classe LoginFormView Classe View Exemplo de arquivo XML para definição de interface gráfica Classe LoginFormView usando UiBinder Web.xml Exemplo de classe serializável Inferface YourService.java Inferface WorldServiceAsync WorldServiceImpl Função JavaScript sayHello(name) Função JavaScript sayHello(name) Função formatAsCurrency Exemplo de função GWT acessada pelo HTML Exemplo de um arquivo no formato JSON Exemplo de requisição feita a um servidor JSONP Resultado do parseResponse Código JavaScript para acessar o serviço Google Maps Código JavaScript para acessar o serviço catacaoacoes 30 31 34 43 44 51 54 54 58 59 60 61 62 62 63 64 65 70 71 72 73 74 78 79 79 79 81 84 84 85 86 8 LISTA DE FIGURAS Figura 1 Figura 2 Figura 3 Figura 4 Figura 5 Figura 6 Figura 7 Figura 8 Figura 9 Figura 10 Figura 11 Figura 12 Figura 13 Figura 14 Figura 15 Figura 16 Figura 17 Figura 18 Figura 19 Figura 20 Figura 21 Figura 22 Figura 23 Figura 24 Figura 25 Figura 26 Figura 27 Figura 28 Figura 29 Figura 30 Figura 31 Figura 32 Figura 33 Figura 34 Figura 35 Figura 36 Figura 37 Figura 38 Figura 39 – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – Pesquisa no Google Insights por cloud computing realizada em janeiro/2011 Supercomputador Lonestar 4 Eras e dimensões da computação Data Center da Google Papéis da computação em nuvem Exemplo de aplicação RIA e gatgets Tecnologias e tendências na Web Tabela periódica de API´s para os produtos Google Console de administração do app engine da Google Representação de uma árvore DOM Alguns WidGets do GWT 2 Comparação das tecnologias de persistências Nomes dos widgets GWT 2.1 Date Picker Biblioteca Smart-GWT Eclipse Helios 3.6 IDE Eclipse Helios 3.6 com os ícones do GWT e App Engine Detalhes da instalação do GWT e App Engine no Eclipse 3.6 Ray Ryan no Google I/O 2009 Criação de um projeto GTW Estrutura de diretórios de um projeto GTW Modo de desenvolvimento do GWT no Eclipse Configuração dos parâmetros para implantação Implantação da aplicação no Data Center da Google Mensagem no brower Modelos MVC e MVP Diagrama de classes UML para o padrão MVP da tela de login Criação de um arquivo UiBinder Tecnologia Remote Method Invocation Arquitetura do GWT Serialização de um objeto, e persistência em disco rígido Sintaxe do JSON Arquivo JSON processado, com outros widgets acrescentados UTFPR no Google Maps Cotação de ações no <div id=‖stokList‖> Diagrama de classes do projeto simulação de cotação de ações Estudo de caso implantado no app engine Equipamentos com software Android e Chrome OS Prós, contras e crescimento da computação em nuvens 14 17 18 19 20 24 25 27 28 31 33 36 42 42 46 47 47 48 48 49 50 52 53 53 55 56 58 64 68 69 71 81 82 85 86 88 88 90 91 9 LISTA DE QUADROS Quadro 1 – Pacotes java.lang suportados pelo GWT Quadro 2 – Pacotes java.lang.annotation suportados pelo GWT Quadro 3 – Pacotes java.util suportados pelo GWT Quadro 4 – Pacotes java.io suportados pelo GWT Quadro 5 – Pacotes java.sql suportados pelo GWT Quadro 6 – Manchetes sobre computação em nuvens 40 40 40 41 41 89 10 LISTA DE SIGLAS E ACRÔNIMOS AJAX API BigTable Blogs CaaS CSS DaaS DeskTop DOM EJB ERP Gadgets GAE Googlipse GQL GUI GWT IaaS ID IDE JDBC JDO Jetty JPA JRE JSF JSNI JSP KHTML LAN MVC MVP OLAP OLTP PaaS PC POJO RIA RMI RPC Asynchronous JavaScript and XML Application Programming Interface Local de persistência de objetos do App Engine Site para publicação rápida e pessoal de artigos Comunicação como um Serviço Cascanding Style Sheets Desenvolvimento como um Serviço Computadores tradicionais de mesa e não portátil Document Object Model Enterprise Java Beans Enterprise Resource Planning Software ou serviço que pode ser agregado a um ambiente maior Google Application Engine Plugin GWT para desenvolvimento de aplicações no IDE Eclipse Google Query Language Grafical User Interface Google Web ToolKit Infraestrutura como um Serviço Indentificador de um objeto ou dado Ambiente de Desenvolvimento Integrado Java Database Connectivity Java Data Objects Servidor de aplicações Java Persistence API Java Runtime Environment Java Server Faces Java Script Native Interface Java Server Pages web browser engine, layout engine ou rendering engine do browser Local Area NetWork Model View Contoller Model View Presenter OnLine Analytical Processing OnLine Transaction Processing Plataforma como um Serviço Personal Computer Plain Old Java Objects Aplicações Ricas para Internet Remote Method Invocation Remote Method Call 11 RSS SaaS SQL TI URL W3C WAN Widgets Recurso para agregar conteúdo Web juntamente com os links Software como um Serviço Sequencial Query Language Tecnologia da Informação Uniform Resource Locator World Wide Web Consortium Wide Area NetWork Componentes de interface gráfica 12 SUMÁRIO 1 INTRODUÇÃO 1.1 OBJETIVOS 1.2 JUSTIFICATIVA 1.3 MOTIVAÇÃO 1.4 ESTRUTURA DO TRABALHO 13 13 13 14 15 2 FUNDAMENTAÇÃO TEÓRICA 2.1 EVOLUÇÃO DA COMPUTAÇÃO 2.1.1 Computação em Cluster 2.1.2 Computação em Grade 2.1.3 Computação Ubíqua 2.1.4 Computação em Nuvens 2.1.4.1 Infraestrutura como um serviço 2.1.4.2 Plataforma como serviço 2.1.4.3 Software como serviço 2.2 ENTERPRISE RESOURCE PLANNING – ERP 2.3 APLICAÇÕES RICAS PARA INTERNET – RIA 2.4 WEB 2.0 2.5 CROME OS 2.6 GOOGLE APPLICATION ENGINE – GAE 2.7 SANDBOX 2.8 DYNAMIC HTML 2.9 CASCADING STYLE SHEETS 2.10 DOCUMENTO OBJECT MODEL 2.11 ASYNCHRONOUS JAVASCRIP AND XML 2.12 WIDGETS 2.13 JAVA DATA OBJECTS 16 16 16 18 18 19 21 21 22 22 23 24 25 26 29 29 30 31 32 32 33 3 GOOGLE WEB TOOLKIT 3.1 COMPILADOR 3.2 JRE EMULATION LIBRARY 3.3 UI LIBRARY 3.4 SETTING UP GWT 3.5 PROJETO E DESENVOLVIMENTO 3.6 TRABALHANDO COM BROWERS 3.7 DESENVOLVIMENTO DE INTERFACE COM O USUÁRIO 3.8 COMUNICAÇÃO COM O SERVIDOR DE APLICAÇÕES 3.9 MISTURANDO JAVASCRIPT E GWT 3.10 ADICIONANDO API 37 38 39 41 46 49 54 55 67 77 84 4 ESTUDO DE CASO 87 5 CONCLUSÃO REFERÊNCIAS 89 92 APÊNDICES 95 13 1 INTRODUÇÃO Vender recursos computacionais como infraestrutura, plataforma (GWT/eclipse) ou software sob demanda, de acordo com a necessidade do cliente de TI, não é novidade, porém se tornava limitada às grandes instituições capazes de adquirir recursos computacionais de grandes fornecedores de poder computacional. 1.1 OBJETIVOS O objetivo deste trabalho é explorar a possibilidade de desenvolvimento de sistemas empresariais no paradigma de computação em nuvens, com a linguagem de programação Java e com a arquitetura de TI que a Google está disponibilizando ao mercado, o ―Google Application Engine‖ e o ―Google Web Toolkit 2‖. 1.2 JUSTIFICATIVA A primeira transformação no mercado de TI em grande escala ocorreu na década de 80, com o uso dos computadores pessoais (PCs) pelas empresas. As empresas tiveram que fazer pesados investimentos, todos os colaboradores de uma empresa podiam ter um computador pessoal potente conectado via rede local em sua mesa. Desta forma 80% dos custos dos departamentos de TI são destinados para a manutenção do serviço e não em estratégia. Este grande custo, porém não traz um avanço estratégico para a empresa, justificando desta forma a importância de repassar o controle dos dados e o processamento dos serviços de TI para servidores localizados na nuvem (CARR, 2010). 14 1.3 MOTIVAÇÃO Acredita-se que essa migração dos sistemas empresariais para as nuvens que já começou, deva levar entre 15 e 20 anos, e será inevitável (CARR, 2010). Na Figura 1 mostra através da ferramenta Google Insights, que retorna um gráfico com a proporção de pesquisas de um termo em relação aos anos, um interesse crescente por cloud computing, e também por app engine e GWT, especialmente na Índia onde são desenvolvidos os grandes sistemas empresariais. Figura 1 – Pesquisa no Google Insights por cloud computing realizada em janeiro/2011 Fonte: GOOGLE Trends (2011). 15 1.4 ESTRUTURA DO TRABALHO No capítulo 2 foi descrito a evolução da computação até chegar às nuvens, as bases tecnológicas que foram utilizadas como o conceito computação em cluster e grid, computação ubíqua, computação em nuvens, Enterprise Resourse Planning, aplicações ricas para internet, WEB 2.0, Chrome OS, Google Application Engine, Sandbox, Dynamic HTML, Cascading Style Sheets, Document Object Model, AJAX, WidGets, e o Java Data Objects. No capítulo 3 foi apresentado o Google Web Toolkit, e como configurar o ambiente de desenvolvimento integrado ―Eclipse‖ para trabalhar no ambiente em nuvens com o Google App Engine. No capítulo 4 foi apresentado o resultado de uma aplicação implantada no App Engine e no capítulo 5 uma conclusão deste estudo com as perspectivas futuras da tecnologia em nuvens, especialmente as propostas da Google. No apêndice A e B estão os códigos fontes da classe CotacaoAcoes.java e da página CotacaoAcoes.html. 16 2 FUNDAMENTAÇÃO TEÓRICA Para a compreensão do atual estado da computação em nuvem, este capítulo faz uma revisão das bases tecnológicas que serão necessárias para o desenvolvimento de modernos sistemas aplicativos que serão hospedados no ambiente de cloud computing. 2.1 EVOLUÇÃO DA COMPUTAÇÃO Nos primórdios da computação por volta de 1943, o processamento era feito em um único computador (Eniac), depois surgiu o computador multitarefa com uma CPU e vários terminais (IBM 4341), por volta de 1974 vieram os computadores pessoais PC que hoje possuem processamento paralelo (Intel i3, i5, i7 e Xeon). Com a evolução da internet, linguagens de programação, virtualização, e computação distribuída, com as tecnologias de Cluster, Grade e Ubíqua, tornaram possível a computação em nuvem. Estas tecnologias levam à necessidade de aplicativos que possam ser acessados de forma eficiente de qualquer lugar. Este paradigma de computação ubíqua criou a necessidade de repensar o modo como as aplicações são desenvolvidas e disponibilizadas, ao mesmo tempo em que motivou o desenvolvimento de tecnologias capazes de dar suporte ao seu aperfeiçoamento. 2.1.1 Computação em Cluster Um cluster, é composto por um conjunto de computadores, pode ser construido a partir de computadores convencionais, que são ligados em rede locais, comunicando-se através do sistema operacional, funcionando como se fossem uma máquina única de grande porte. Os tipos mais conhecidos de cluster são: Cluster de Alto Desempennho: Ele funciona permitindo que haja uma grande carga de processamento com computadores comuns. 17 Cluster de Alta Disponibilidade: Os sistemas permanecem ativos por um longo período de tempo e em plena condição de uso. Estes clusters nunca param de funcionar, e conseguem detectar erros, se protegendo de possíveis falhas. Cluster para Balanceamento de Carga: Esse cluster tem como função equilibrar a distribuição do processamento entre as máquinas. Requer um monitoramento constante em seus mecanismos de redundância, pois se houver alguma falha, ocorrerá uma interrupção no seu funcionamento. Os clusters dos data centers mais modernos são construidos com vários blades (um servidor blade é um despojado computador servidor com um design modular otimizado para minimizar o uso de espaço físico e energia). Na Figura 2 é mostrada a foto do Lonestar 4 do centro de computação avançado da universidade do Texas em Austin, que entrou em operação em fevereiro de 2011. Este cluster é composto por 1.888 blades PowerEdge M610 da Dell, cada blade contendo dois processadores Intel Xeon X5600 Westmere, de seis núcleos, o sistema atinge um pico de 302 teraflops (um teraflop equivale a um trilhão de operações por segundo), tem um total de 44,3 terabytes de memória RAM e 1,2 petabytes de armazenamento de disco (MILLER, 2011). Figura 2 – Supercomputador Lonestar 4 Fonte: Miller (2011). 18 2.1.2 Computação em Grade Computação em grade, é um modelo computacional capaz de alcançar uma alta taxa de processamento dividindo suas tarefas entre diversos clusters, podendo ser em rede local (LAN) ou rede de longa distância (WAN), que formam uma única máquina virtual. Esses processos são balanceados entre os cluters do grid computing, evitando a ociosidade de processamento de máquinas pertencentes à grade. 2.1.3 Computação Ubíqua A computação ubíqua é a junção da computação móvel e da computação pervasiva. O conceito de computação pervasiva indica que o computador está embarcado no ambiente de forma invisível para o usuário (WLAN). O computador tem a capacidade de obter informações do ambiente no qual ele está inserido, e utilizar este ambiente para configurar, ajustando a aplicação para melhor atender as necessidades do dispositivo ou usuário. Na Figura 3 é mostrada as eras e as dimensões da computação. Figura 3 – Eras e dimensões da computação Fonte: Adaptado de Weiser (2011). Na Figura 4 ilustra um dos Data Centers da Google, onde podemos ver o Cluster, o Grid computing no mapa mundi, o armazenamento de dados em raids (conjunto independente de discos redundantes), a infraestrutura de rede e um dos prédios com seus resfriadores a vista, para abrigar toda esta tecnologia (GOOGLE DATA CENTER..., 2009). 19 Figura 4 – Data Center da Google. Fonte: Adaptado de GOOGLE Data Center... (2009). 2.1.4 Computação em Nuvens Uma definição para o paradigma de computação em nuvens, podendo ser tomada como referência é: Computação em nuvem é um paradigma de computação em larga escala que possui foco em proporcionar economia de escala, em que um conjunto abstrato, virtualizado, dinamicamente escalável de poder de processamento, armazenamento, plataformas e serviços, são disponibilizados sob demanda para clientes externos através da internet. (FOSTER apud MÜLLER, 2010, p. 18). A idéia da computação em nuvem consiste em que tudo é serviço, uma espécie de self-service de tecnologias da informação, disponibilizados ao usuário, podendo ser ele um 20 desenvolvedor ou usuário final. Muitos serviços de computação em nuvem são oferecidos pelo modelo chamado Utility Computing, o qual é definido como um pacote de recursos computacionais medidos e cobrados de forma semelhante aos serviços de utilidade pública, como eletricidade, água, telefone, TV por satélite ou banda larga. Este modelo prevê uma otimização dos investimentos feitos pelos clientes nos recursos de hardware, diminuindo a necessidade de grandes investimentos iniciais, possibilitando o aluguel de mais recursos à medida que forem necessários, podendo ainda alguns provedores de serviços se ajustarem dinamicamente às necessidades de demanda, na medida em que o cliente contratar mais recursos apenas para momentos de pico, evitando que recursos fiquem ociosos a maior parte do tempo. Atualmente os serviços de computação em nuvem possuem três categorias bem definidas de acordo com os recursos e o modo que estes recursos são disponibilizados. Na Figura 5 é ilustrada que a computação em nuvem é impulsionada pelos conceitos de utility computing, on-demand computing, autonomic computing e Green IT, e as categorias de serviços: Infraestrutura como um Serviço (IaaS) Plataforma como um Serviço (PaaS) Software como um Serviço (SaaS) Figura 5 – Papéis da computação em nuvem Fonte: Adaptado de WHAT... (2011). 21 2.1.4.1 Infraestrutura como um serviço A Infraestrutura como um serviço (IaaS), e que geralmente se apóia em tecnologias como virtualização, é a base dos serviços de computação em nuvem, sendo a parte que se refere à disponibilização dos recursos de hardware formados pelos servidores, armazenamento e processadores. O consumidor do serviço adquire uma máquina virtual operando sobre a estrutura de servidores do provedor, sendo a quantidade de processamento e armazenamento contratados disponibilizados através da configuração adequada de tais máquinas virtuais. A vantagem destes serviços se encontra na facilidade de contornar problemas de escalabilidade dos sistemas, na grande capacidade de suportar demandas crescentes por recursos de forma uniforme, bastando para isto apenas ajustar as configurações das máquinas virtuais contratadas. 2.1.4.2 Plataforma como serviço Plataforma como um Serviço (PaaS) que se destina aos desenvolvedores, é um tipo de serviço que procura prover toda a estrutura necessária para um ambiente de desenvolvimento. Neste serviço o ambiente de desenvolvimento disponibiliza uma plataforma computacional completa, incluindo sistema operacional, linguagens de programação, bibliotecas e sistemas gerenciadores de banco de dados, disponíveis através da nuvem. Deste modo os desenvolvedores podem construir suas aplicações sem a necessidade de instalar qualquer ferramenta no seu computador e distribuí-la de forma simples. Um serviço completo de PaaS todo o ciclo de vida do software deve ser suportado no mesmo ambiente computacional, reduzindo os custos de desenvolvimento, manutenção e distribuição das novas versões das aplicações. 22 2.1.4.3 Software como serviço Uma definição para o modelo Software como um Serviço (SaaS), poderia ser a de software distribuído como um serviço hospedado e acessado através da internet. Podemos citar uma variedade de exemplos de aplicações em que neles se enquadram, como é o caso das aplicações de webmail, aplicações que tornaram praticamente dispensáveis os aplicativos clientes de e-mail desktop convencionais, sites de compartilhamento de fotos e vídeos, e aplicações de escritório como as disponibilizadas pelo Google através do GoogleDocs. Computação em nuvem despertou a necessidade para o desenvolvimento de novas tecnologias e propostas no desenvolvimento e distribuição de aplicações, bem como tecnologias de suporte e infraestrutura, mostrando ser um campo com grande potencial de geração de novas necessidades, que terão que ser supridas pelos futuros profissionais de TI. Alguns autores também consideram DaaS e CaaS como modelo de serviço de computação em nuvem. O DaaS (Development as a Service) é uma aplicação Web que usa conteúdo de mais de uma fonte para criar um novo serviço completo, podem possuir códigos de terceiros que se comunicam através de uma interface publica ou de uma API como os RSS, Widgets e Blogs. O CaaS (Communication as a Service) é o conjunto de serviços que satisfaz a função de comunicação, como telefonia IP, mensagens instantâneas e videoconferência. 2.2 ENTERPRISE RESOURCE PLANNING – ERP ERP ou Sistemas Integrado de Gestão Empresarial são sistemas de informação que integram em um único sistema todos os dados e processos de uma organização empresarial. A integração pode ser analisada sob a perspectiva funcional (sistemas de: finanças, contabilidade, recursos humanos, fabricação, marketing, vendas, compras, etc) e sob a perspectiva sistêmica com os sistemas transacionais (OLPT), e os sistemas analíticos (OLAP) para prover as informações para tomada de decisão pelos gestores da organização. Os ERPs são implantados em uma infraestrutura de software desenvolvida para integrar os diversos setores de uma empresa, possibilitando a automação dos processos empresariais, e armazenamento de todos os dados de negócios em um único banco de dados. 23 Processando os dados deste banco de dados, são geradas informações para os gestores, que por sua vez criam conhecimento que geram riquezas e lucro para as empresas. O maior benefício que um sistema de ERP proporciona a uma corporação, está na maior confiabilidade dos dados, processos on-line, e a diminuição do retrabalho. Algo que é atingido com o comprometimento dos funcionários, cada um com suas responsabilidades por fazer os lançamentos que alimentam toda a cadeia de módulos do sistema, e que fazem com que a empresa possa interagir em tempo real. Desta forma, as informações fluem pelos diversos módulos em tempo real. Um pedido de vendas dispara um processo de fabricação com o envio de dados para multiplos módulos, do estoque de insumos à logística do produto. Tudo realizado com dados integrados e não redundantes. 2.3 APLICAÇÕES RICAS PARA INTERNET - RIA Aplicações Ricas para Internet (RIA - Rich Internet Application) são Aplicações Web que tem funcionalidades de softwares tradicionais do tipo Desktop. RIA típicos injetam todo o processamento da interface para o navegador da internet, que assincronamente disparam pedidos de processamento para o servidor de aplicação, com tecnologia JavaScript e XML, o AJAX. RIAs na maioria dos casos não necessitam de instalação na máquina cliente e rodam localmente em um ambiente seguro chamado sandbox. Sandbox executa seus programas em um espaço separado (caixa de areia) que é apagado automaticamente, impedindo fazer alterações permanentes no computador cliente. Executando o browser sob a proteção do Sandbox assegura que todo o software mal intencionado baixado pelo navegador está preso na caixa de areia, e podem ser descartados trivialmente. O histórico de navegação, cache, cookies e arquivos temporários coletados durante a navegação na Web estariam na caixa de areia e não vaza para o Sistema Operacional, vírus e outros softwares mal intencionados que podem estar escondidos em e-mail não pode sair da caixa de areia e não pode infectar o sistema real. Na Figura 6 é ilustrada uma aplicação RIA (iGoogle) implementada com o GWT pela Google. O iGoogle usa o conceito de gadgets, um pequeno objeto tecnológico, que tem uma função específica. Estes gadgets têm o comportamento similar de janela no ambiente desktop, onde possuem a funcionalidade de maximizar, mover, remover, inserir novos gadgets e configurar a aparência dos mesmos. Os gadgets são construídos a partir dos widgets. 24 Figura 6 – Exemplo de aplicação RIA e gatgets Fonte: iGOOGLE (2011). 2.4 WEB 2.0 O termo Web 2.0 é utilizado para descrever a segunda geração de comunidades e serviços Web como AdSense, Ajax, Blogs, Mash-ups, RSS, Tagging [rotulação] e Wikis. Apesar da conotação de uma nova versão para a Web, não se refere à inovação de técnicas, mas a uma mudança na forma como ela é utilizada por usuários e desenvolvedores, tendência que reforça o conceito de troca de informações e colaboração dos internautas com sites e serviços virtuais. A idéia é que o ambiente on-line se torne mais dinâmico e que os usuários colaborem para a organização de conteúdo (MOREIRA, 2009). Como toda forma de classificação histórica, não pode se dizer exatamente quando termina ou começa a Web 2.0 cronologicamente. Na Figura 7 é ilustrado estes padrões e tendências de comportamento na rede, colaborando com a organização de idéias e conceitos em uma indústria nova e complexa, por sofrer muitas mutações justamente por estar ainda em sua fase embrionária. 25 Na web 2.0 como plataforma, os sites deixam de ter uma característica estática para se transformarem em verdadeiros aplicativos no servidor. As funcionalidades dos sites serão muito mais poderosas, lembrando a sofisticação de softwares que rodam no desktop de um PC. Estes aplicativos web tem também uma integração mais eficiente com a interface no cliente (browser), que passa a ser mais poderosa com tecnologias como XML e JavaScript, o AJAX, que podem gerar uma usabilidade mais intuitiva e que lembra as interfaces desenvolvidas em código de baixo nível (C++ e afins) (MOREIRA, 2009). Figura 7 – Tecnologias e tendências na Web Fonte: Hodgson (2008). 2.5 CROME OS A computação em nuvem leva ao fim os sistemas desenvolvidos no modelo DeskTop com o surgimento do Chorme OS da Google. Com o surgimento dos netbooks com sistema operacional Chrome OS, smartPhones com sistema operacional Android da Google, tablets com sistema operacional Android 3.0 e redes sem fio ligadas à internet em alta velocidade, não há mais a necessidades de termos grandes Hard Disk, memórias RAM de 8 GB, 26 processadores multiprocessados com até 4 nucleos, compra, instalação e manutenção de software, backups atualizados, preocupação com segurança dos dados e virus nas máquinas clientes. Para utilizar algum serviço nas nuvens basta termos uma rede banda larga, e um equipamento com um navegador internet ou com Chorme OS onde o próprio navegador é o sistema operacional. Alguns usuários ainda necessitarão de aplicações DeskTop, os desenvolvedores de software por exemplo continuarão com suas potentes máquinas, assim como os usuários de games de ponta em que é exigido grandes processadores. Os Chromebooks são uma versão radical do conceito de netbook com o sistema operacional Chrome OS, podem ser definidos como a experiência de netbook levada às ultimas consequências. Aqui a ideia é ter tudo armazenado na nuvem para que a máquina seja o mais rápida e leve possível. O Chromebook fará tudo baseado na web. Nesta arquitetura não é o computador pessoal que envia e-mail ou edita um documento, ele é apenas um meito para solicitar e receber os serviços da nuvem. 2.6 GOOGLE APPLICATION ENGINE - GAE O Google foi um dos primeiros a implantar uma plataforma em cloud aberta para desenvolvimento de aplicativos. O Google Application Engine, App Engine ou GAE é um serviço contido no modelo de IaaS, DaaS e PaaS, que diferentemente de seu conceito original, em que todo o ambiente responsável pelo ciclo de desenvolvimento e publicação do software se dá através de ferramentas disponibilizadas via web, disponibiliza um ambiente desktop completo através de plugins para o Eclipse IDE chamado de Googlipse para criar as aplicações. Com o Google App Engine, pode-se criar aplicativos web nos mesmos moldes de sistemas escaláveis dos aplicativos do Google. Os aplicativos implantados no Google App Engine são fáceis de criar, manter e escalar à medida que seu tráfego e armazenamento de dados precisam crescer. Uma vez o implantado o sistema no app engine, os clientes já poderão acessar e usar o aplicativo. O Google é conhecido por ser altamente confiável, e por sua infraestrutura de alto desempenho. Com o Google App Engine, pode-se beneficiar dos 10 anos de experiência e conhecimento que o Google possui em executar sistemas altamente escaláveis e orientados 27 para o desempenho. As mesmas políticas de segurança, privacidade, escalabilidade e proteção de dados para os seus aplicativos se aplicam a todos os aplicativos do Google App Engine. A Google oferece um leque de API´s para acessos a seus serviços. A idéia da Google é fornecer estas API´s para usar a nuvem da Google em sistemas, precisando disponibilizar vídeos em uma aplicação use a You-tube API. Estas API´s podem ser vistas na Figura 8. Figura 8 – Tabela periódica de API´s para os produtos Google Fonte: GOOGLE´S... (2011). O Google App Engine sempre será gratuito para iniciar, afirma a Google, até o limite de 500 MB de armazenamento e 5 milhões de acessos de página mensais, e quando este limite for atingido é só ativar o faturamento e pagar o que for usado com os seguintes preços em dólar americano. Tabela 1 - O custo dos recursos de computação do app engine da Google Recurso Unidade Custo unitário Largura de banda de saída gigabytes $0,12 Largura de banda de entrada gigabytes $0,10 Horas da CPU $0,10 gigabytes por mês $0,15 Tempo de CPU Dados armazenados Destinatários de e-mail destinatários $0,0001 Fonte: BILLING... (2011). Conclui-se pela Tabela 1, que com $0.94 mensais é possível manter um sistema com uso de 2 horas de CPU ($0.20), 2 GB de armazenamento ($0.30), 2 GB de saída de informações ($0.24) e 2 GB de entrada de dados ($0.20). Através do console de administração 28 do aplicativo é possível gerenciar o orçamento do aplicativo, bem como os recursos consumidos por ele. Na Figura 9 é mostrada a console da máquina virtual do GAE que será usada no estudo de caso deste trabalho, para acessar o serviço deve fazer login. Google Application Engine possui suporte a aplicativos criados com o uso das linguagens de programação Python e Java. O App Engine permite o uso das bibliotecas padrões da linguagem Java, que será usado neste trabalho, com exceção das que infrinjam as restrições impostas com o grande objetivo de garantir o bom funcionamento do sistema. Para diminuir o efeito negativo das restrições, o Google App Engine criou uma série de serviços que facilitam o desenvolvimento e execução de determinadas tarefas. Os aplicativos criados e disponibilizados a partir do Google App Engine podem ser acessados a partir do domínio livre no padrão appspot.com oferecido pelo serviço adicionado ao identificador da aplicação escolhido na hora da sua criação, ficando da forma: identificador.appspot.com. (ex: http://www.tccposjavautfpr.appspot.com/ domínio criado para o estudo de caso). Figura 9 – Console de administração do app engine da Google Fonte: RUN... (2011). 29 2.7 SANDBOX O Application Engine, implementa de forma inovadora o paradigma de computação em nuvem, em que o armazenamento e processamento do aplicativo são distribuídos entre os clusters da Google, e necessita de um ambiente virtual seguro para cada aplicativo. Este ambiente chamado de sandbox disponibiliza acesso limitado ao sistema operacional. Esta limitação possibilita que o Google App Engine distribua as solicitações de web da aplicação entre diversos clusters, podendo iniciar ou interromper os servidores para atender às demandas de tráfego. O GAE também permite que cada aplicação possua uma área isolada (caixa de areia) confiável e segura independente de hardware, sistema operacional e localização física do servidor, garantindo que uma aplicação não influencie no funcionamento de outras. Este método de virtualização além de possibilitar a distribuição na execução do aplicativo, evita em um ambiente compartilhado, o uso abusivo de recursos por uma aplicação afetando desempenho das demais. 2.8 DYNAMIC HTML Dynamic HTML, ou DHTML, é união das tecnologias javascript, HTML e uma linguagem de apresentação, como as folhas de estilo CSS, tudo funcionando em conjunto com o Modelo de Objeto de Documentos (DOM), para permitir que uma página Web seja modificada dinamicamente no próprio navegador da máquina do cliente, sem necessidade de novos acessos ao servidor web. A especificação oficial do DHTML foi feita pela W3C, mas a Netscape e a Microsoft incluíram vários recursos extras que ajudaram ainda mais o DHTML. Esses DHTMLs incluiram novas capacidades de alterar as propriedades das marcações tags HTML dinamicamente. O DHTML da Microsoft, permite que se adicionem efeitos como sombra e néon a imagens apresentadas dentro de um documento HTML. DHTML é um conjunto de recursos que fornecem um controle inovador sobre a apresentação do conteúdo de páginas da Web, além de possibilitar a inclusão de componentes (widgets) multimédia, como animações, diretamente no código HTML, sem a necessidade de plug-ins. O HTML Dinâmico é adotado, por estabelecer novos patamares de usabilidade e movimento na internet a um baixo custo medido em velocidade, abrangência e flexibilidade (HTML..., 2011) 30 2.9 CASCADING STYLE SHEETS Cascading Style Sheets (CSS) é uma linguagem de estilo utilizada para padronizar a apresentação de documentos codificados em uma linguagem de marcação, como HTML ou XML. Seu principal benefício é estabelecer uma separação entre o formato e o conteúdo de um documento HTML. Ao invés de especificar a formatação dentro do documento, o desenvolvedor cria um link para uma página que contém os estilos, fazendo o mesmo para todas as páginas de um site. Quando quiser alterar a aparência do site basta portanto modificar apenas o arquivo CSS. body { font-family: Arial, Verdana, sans-serif; background-color: #FFFFFF; margin: 5px 10px; } Código 1 - Exemplo de CSS Fonte: Autoria própria. O Código 1 é um exemplo de arquivo CSS em que define para o corpo da página HTML, um fonte padrão Arial, se não existir este fonte na máquina cliente o CSS substitui por Verdana, caso não exista define qualquer fonte sans-serif, este estilo define também a cor no formato hexadecimal que no caso é branco, e as margens. A documentação detalhada do CSS pode ser obtidas no site da W3C World Wide Web Consortium, um consórcio de diversas empresas que trabalham juntas para estabelecer padrões para a Internet. Hoje ainda nenhum browser suporta igualmente as todas as definições do CSS. Desta forma, o webdesigner deve verificar o comportamento de suas folhas de estilo em browsers de vários fabricantes, e especialmente em mais de uma versão, para se garantir que o que foi codificado seja apresentado da forma planejada. 31 2.10 DOCUMENTO OBJECT MODEL Document Object Model (DOM) fornece uma representação estruturada de um documento HTML (no contexto de navegadores web) a partir da qual seus elementos podem ser manipulados através de JavaScript, e fornece uma notação padronizada entre os navegadores. Mesmo não sendo totalmente, é razoavelmente padronizada, por isto a importância de se testar as páginas em diferentes navegadores e em diferentes versões. Qualquer alteração feita em um elemento da árvore é imediatamente refletida na página que está sendo exibida pelo navegador. <html> <head> <title>Ajax - conceitos básicos</title> </head> <body> <h1>Exemplo de árvore DOM</h1> </body> </html> Código 2 - Exemplo de Código HTML Fonte: Lima (2010). Na Figura 10 é mostrada a representação da árvore DOM feita pelo browser: Figura 10 – Representação de uma árvore DOM Fonte: Lima (2010). 32 Todos os componentes da HTML são representados como um nó na árvore DOM, inclusive fragmentos de texto. Existem tipos diferentes de nó. Nó de elemento, para representar <Tags> da HTML, nó de atributo, para representar uma propriedade de um nó de elemento, e nó de texto, para representar cadeias de caracteres da página. Cada nó pode possuir ou não filhos e pertencer a um único pai, cada nó pode possuir um atributo identificador, que através de JavaScript pode-se recuperar, adicionar, modificar e remover nó na árvore DOM. Toda alteração é refletida na página sem a necessidade de carregar o documento HTML novamente. 2.11 ASYNCHRONOUS JAVASCRIPT AND XML Asynchronous JavaScript and XML (AJAX), é uma técnica de programação que faz uso conjunto de outras tecnologias como DHTML e XML. Grande parte da programação é realizada no navegador do cliente, totalmente baseado em Java Script, XML e utilização da árvore DOM que os navegadores implementam para promover a atualização de partes específicas da aplicação. Ajax permite solicitações assíncronas a um determinado serviço e atualiza somente os campos necessários para executar os requisitos da aplicação, ao invés de recarregar toda a página, desta forma permite maior interatividade da página e torna as aplicações web mais dinâmicas. (LIMA, 2010). 2.12 WIDGETS O elemento básico de um programa com interface gráfica se chama widget, podem ser janelas, botões, menus, ícones, barras de rolagem, etc. Um programa deve definir uma hierarquia de árvore invertida de widgets, na qual alguns widgets estão subordinados a outros. Normalmente, todos os widgets são subordinados a um widget principal. Trabalhar com vários widgets é a principal diferença entre um programa GUI e um programa normal. No último caso, o desenvolvedor procura sempre saber qual ponto do software está sendo executado, no programa GUI é o sistema gerenciador de janelas que escolhe qual parte do software (ou seja, qual parte de qual widget) está sendo rodado. As mensagens entre os 33 diversos widgets usualmente é feita de forma indireta, eles disparam mensagens indicando as ações executadas sobre ele, e estas mensagens são recebidas pelos outros widgets para efetuar as ações desejadas. Na figura 11 é ilustrado alguns widgets do GWT 2. Figura 11 – Alguns WidGets do GWT 2 Fonte: Adaptado de WIDGET... (2011). 2.13 JAVA DATA OBJECTS Java Data Objects (JDO), trata-se de um padrão Java para persistência de dados independente do sistema de banco de dados utilizado, uma aplicação que utiliza este padrão para modelar suas entidades de dados para utilizar como sistema de armazenamento o BigTable do Google ou migrar para algum banco de dados relacional, como o MySQL, sem que isso afete seu modelo de dados. Deste modo perde-se um pouco em eficiência de modelagem, mas se ganha muito em portabilidade. Para que isto seja possível é necessário que haja uma implementação do padrão executando em nível de servidor JVM, responsável 34 por mapear os modelos fisicamente ao sistema escolhido. O responsável por esta tarefa no App Engine é o DataNucleus Access Platform implementando a versão 2.3 do JDO. A modelagem das entidades baseia-se nos chamados POJOs (Plain Old Java Objects), que nada mais são do que objetos simples dotados de atributos ou propriedades, e métodos de acesso (atribuição e obtenção) a estes atributos, adicionados de anotações JDO para torná-los passíveis de persistência, analogicamente como acontece com a tecnologia hibernate (JAVA..., 2011). A linguagem de persistência no DataStore do GAE é o GQL Google Query Language, muito parecido com o SQL. A hospedagem no GAE foi desenvolvida para utilizar aplicações 100% cloud, logo é disponibilizado para todas as contas registradas um banco NoSQL para toda aplicação criada. A plataforma GAE disponibiliza o padrão JDO e JPA. O DataStore da Google é o Bigtable projetado de forma confiável a escala de petabytes de dados e milhares de máquinas servidoras. Uma entidade persistente no sistema de armazenamento a ser modelada com JDO utiliza uma classe simples, contendo atributos, métodos de acesso aos atributos e anotações JDO correspondentes. O nome da entidade será definido pelo nome da classe, e os nomes das propriedades que serão armazenadas serão os mesmos definidos no modelo. A anotação @PersistenceCapable define que a classe é apta a ser persistida. package guestbook; import java.util.Date; import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; import com.google.appengine.api.users.User; @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Greeting { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private User author; @Persistent private String content; @Persistent private Date date; public Greeting(User author, String content, Date date) { 35 this.author = author; this.content = content; this.date = date; } public Long getId() { return id; } public User getAuthor() { return author; } public String getContent() { return content; } public Date getDate() { return date; } public void setAuthor(User author) { this.author = author; } public void setContent(String content) { this.content = content; } public void setDate(Date date) { this.date = date; } } Código 3 - Exemplo de anotações POJO e JDO Fonte: JAVA... (2011). Esta classe simples define três propriedades para uma saudação: author, content e date. Esses três atributos privados da classe acima são anotados com @Persistent para informar que o DataNucleus deve persisti-los como propriedades de objetos no armazenamento de dados do Google App Engine. Essa classe define os métodos set e get das propriedades ou atributos. Elas são usadas apenas pelo aplicativo e não são necessárias para a JDO. A classe define também um atributo chamado id, um Long anotado como @Persistent e @PrimaryKey. O armazenamento de dados do Google App Engine usa o conceito de chaves de entidade e pode representar a chave de diversas maneiras no objeto. Nesse caso, o campo da chave que é o identificador de um objeto do tipo Greeting é um inteiro long, e é definido automaticamente como um ID numérico exclusivo quando o objeto é salvo. Na Figura 12 é ilustrada uma comparação entre as tecnologias de persistência JDBC, JPA, EJB2, ORM proprietários e o JDO. 36 Figura 12 – Comparação das tecnologias de persistências Fonte: JAVA... (2011). Benefícios do uso de JDO para Programação de Aplicativos: Facilidade de uso: Os desenvolvedores de aplicativos podem se concentrar em seu modelo de objeto de domínio e deixar os detalhes de persistência (campo-a-campo de armazenamento de objetos) para a implementação JDO. Portabilidade: aplicações escritas com a API JDO podem ser executadas em várias implementações sem recompilar ou alterar o código fonte. Metadados que descreve o comportamento externo de persistência para o código-fonte do Java inclue a maioria dos recursos mais usados do mapeamento O/R, e é altamente portável. Independência Banco de Dados: Aplicações escritas com a API JDO são independentes do banco de dados. JDO dá suporte a muitos tipos diferentes de armazenamentos de dados transacionais, incluindo bancos de dados relacionais e objeto, XML, arquivos simples, e outros. Alto desempenho: Os desenvolvedores de aplicativos podem delegar os detalhes de persistência para a implementação JDO, que podem otimizar o acesso a padrões de dados para um ótimo desempenho. Integração com EJB: As aplicações podem tirar proveito dos recursos do EJB, tais como o processamento de mensagens a distância, coordenação de transações distribuídas automática e segurança, utilizando os modelos de objeto do mesmo domínio em toda a empresa. 37 3 GOOGLE WEB TOOLKIT O Google Web Toolkit é um kit de desenvolvimento de aplicações web da Google, que permite desenvolver interfaces ricas, escrevendo código fonte na linguagem de programação Java, gerando JavaScript compatíveis com a maioria dos navegadores Web. A formatação do GWT foi elaborada para a utilização da plataforma GAE, pois a padronização da estrutura do projeto facilita escalar a aplicação desenvolvida e é uma alternativa ao JSF para o desenvolvimento orientado a componentes (GOOGLE WEB..., 2011). A ferramenta trabalha com o código dividido em duas partes distintas, uma com código a ser executado pelo cliente e outra com código a ser executado pelo servidor através de chamadas assíncronas feitas pelo código no cliente. O código Java destinado a ser executado pelo cliente é automaticamente compilado pelo Google Web Toolkit para código JavaScript capaz de ser executado por navegadores, deixando a cargo do compilador questões de compatibilidade entre navegadores e de otimização. Aplicativos baseados neste conceito têm uma maior usabilidade por evitar o uso excessivo de solicitações e se aproximar da interação proporcionada por aplicativos para desktop, evitando freqüentes carregamentos das páginas do aplicativo, melhorando a experiência de uso, algo que é um dos principais problemas de aplicativos web. O próprio Google utiliza esta ferramenta em vários de seus aplicativos, o Gmail, a rede social Orkut e o conjunto de ferramentas como processadores de texto e planilhas do Google Docs. O GWT pode ser utilizado por qualquer aplicativo Java para web e possui integração com o Google Application Engine, sendo distribuído juntamente com seu plug-in para Eclipse o Googlipse. O modelo de desenvolvimento de aplicações GWT, tornou possível que uma aplicação Web seja escrita inteiramente em Java, desobrigando a usar tecnologias de páginas dinâmicas como o JSP por exemplo. Por meio do processo de compilação, o GWT gera código JavaScript cross-browser, garantindo que uma aplicação seja construída através de uma forma de programação, que utiliza tecnologias implementadas em qualquer navegador Web que suporte as especificações do W3C. Desde seu lançamento na conferencia JavaOne em maio de 2006, o GWT vem evoluindo passando da versão 1.0 para a 2.1 atualmente, que traz muitas novidades, entre elas novos widgets com suporte a data binding (recurso permite efetuar a ligação com dados de diversas fontes de dados sem ter que escrever código, permitindo gerenciar a execução e edição de dados complexos) e um framework Model-View-Presenter. 38 Uma desvantagem do GWT atualmente é que suas páginas não podem ser indexadas pelos mecanismos de busca, uma vez que elas são geradas dinamicamente. Para contornar o problema é usado cloaking, que é uma técnica utilizada por webmasters para entregarem conteúdos diferentes de uma mesma URL para visitantes específicos do site. Os visitantes podem ser classificados pelo tipo de Web Crawler (programa de computador que navega pela World Wide Web de uma forma metódica e automatizada) Human User ou por localidade. Existem 3 métodos de cloaking, o cloaking por User-Agent que detecta o user-agent e o classifica, o cloaking por IP Delivery que entrega um conteúdo diferente para um usuário de IP específico, e o cloaking por Geo-Targeting que fornece um conteúdo diferente para usuários dentro de uma faixa de IPs que delimitam uma região do mundo específica (MÜLLER, 2011) O GWT possue tres componentes básicos, o compilador Java-to-JavaScript, o emulador Java Runtime Environment (JRE) e a liblioteca de interface gráficas com o usuário (GUI). 3.1 COMPILADOR O compilador Java trabalha a partir das versões 1.5, e produz distintos códigos JavaScript para serem executados em todos os browser suportados. Hoje todas as versões do Safari e FireFox, Opera, versões 6,7 e 8 do Internet Explorer, e Google Chrome suportam JavaScript, e são baseados no mesmo layout do WebKit (motor de renderização para navegadores que foi desenvolvido baseado no KHTML). O JavaScript gerado fica muito maior se for usado a internacionalização, que são processos de desenvolvimento e/ou adaptação do softwares para uma língua e cultura de um país. O código gerado pode ser minimizado para otimizar o download e facilitar o code splitting, onde o JavaScript é quebrado em pedaços e feito o download sob demanda. O compilador tem diversos otimizadores de código, que produz códigos JavaScript de alta qualidade, as mais importantes são: Dead Code Elimination: Códigos que nunca são chamados não são incluidos no JavaScript gerado, por exemplo caso o software use uma classe com dez métodos e só é usado dois métodos dos dez, será gerado código somente para os médotos chamados. Similarmente se esta classe herda outros métodos de outra classes e não são chamados, estes métodos não serão gerados no JavaScript. 39 Constant Folding: Quando o valor de uma expressão é conhecido em tempo de compilação, ele é calculado neste momento e o resultado será usado no código JavaScript gerado. Por exemplo, a instrução no GWT Window.alert(―Hello ―+‖World‖); gerará o código $wnd.alert(―Hello World‖) no JavaScript. Copy Propagation: O valor de uma variável conhecida pode ser eliminada em tempo de compilação. Por exemplo o codigo int a=15; int b=a*a+5; a segunda instrução será compilada como int b=230. String Interning: Para evitar a criação de strings de mesmo mone em java, pois elas são imutáveis, ou seja para alterar seu valor é necessário a criação de outro objeto string, elas são criadas internamente uma única vez com o nome $intern_22 por exemplo e usada em todo o código java. Code Inlining: O GWT substitui a chamada dos métodos pelo seu corpo, caso ele seja pequeno e simples. O JavaScript não tem inteiro de 64 bits, então o GWT emula variáveis long com um par de inteiros de 32 bits. Isto funciona bem mas é lento, e quando se usa JSNI (Java Script Native Interface) não é possível passar esta variável. Para números ponto flutuante, JavaScript prove somente double 64 bits, que pode gerar overflow e resultados imprecisos, pois estas operações não funcionam exatamente como em Java. Exceptions são manipuladas diferentes que Java. Em JavaScript a maioria das exeções Java como NullPointerExeption ou MemoryOverFlowExeption são traduzidas por JavaScriptExeption. Isto causa um problema, um NullPointerExeption não pode ser diferenciado de um MemoryOverFlowExeption em JavaScript. 3.2 JRE EMULATION LIBRARY Google Web Toolkit inclui uma biblioteca que emula um subconjunto da biblioteca de runtime do Java. Nos Quadros 1, 2 e 3 são mostrados o conjunto de pacotes JRE, que o GWT pode traduzir automaticamente. 40 Pacotes java.lang ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError Boolean Byte CharSequence Character Class ClassCastException Cloneable Comparable Deprecated Double Enum Error Exception Float IllegalArgumentException IllegalStateException IndexOutOfBoundsException Integer Iterable Long Math NegativeArraySizeException NullPointerException Number NumberFormatException Object Override Runnable RuntimeException Short StackTraceElement String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Throwable UnsupportedOperationException Void Quadro 1 – Pacotes java.lang suportados pelo GWT Fonte: GOOGLE WEB… (2011). Pacotes java.lang.annotation Annotation AnnotationFormatError AnnotationTypeMismatchException Documented ElementType IncompleteAnnotationException Inherited Retention RetentionPolicy Target Quadro 2 – Pacotes java.lang.annotation suportados pelo GWT Fonte: GOOGLE WEB… (2011). Pacotes Java.util AbstractCollection AbstractList AbstractMap AbstractQueue AbstractSequentialList AbstractSet ArrayList Arrays Collection Collections Comparator ConcurrentModificationException Date EmptyStackException EnumMap EnumSet Enumeration EventListener EventObject HashMap HashSet IdentityHashMap Iterator LinkedHashMap LinkedHashSet LinkedList List ListIterator Map Map.Entry Quadro 3 – Pacotes java.util suportados pelo GWT Fonte: GOOGLE WEB… (2011). MissingResourceException NoSuchElementException PriorityQueue Queue RandomAccess Set SortedMap SortedSet Stack TooManyListenersException TreeMap TreeSet Vector 41 Pacotes java.io FilterOutputStream PrintStream OutputStream Serializable Quadro 4 – Pacotes java.io suportados pelo GWT Fonte: GOOGLE WEB… (2011). Pacotes java.sql Date Timestamp Time Quadro 5 – Pacotes java.sql suportados pelo GWT Fonte: GOOGLE WEB… (2011). Pacotes extras para prover funcionalidades ao GWT: com.google.gwt.i18n.client.DateTimeFormat e com.google.gwt.i18n.client.NumberFormat prove funções para formatação. com.google.gwt.core.client.Duration prove funções de timing. com.google.gwt.user.client.Random função para substituir java.util.Random. com.google.gwt.user.client.Timer função para substituir java.util.Timer. 3.3 UI LIBRARY GWT prove um grande conjunto de widgets e painéis. Usar widgets é similar a usar swing em aplicações desktop, mas não há gerenciador de layout, e painéis ou CSS são usados para posicionar os objetos. Widgets são mapeados dentro do browser como objetos, e compartilha o aspecto visual de cada navegador web. Estilos podem ser aplicados a cada objeto separadamente ou genericamente usando CSS que é a solução preferencial. Na Figura 13 é mostrado os nomes dos widgers do GWT 2.1. 42 Figura 13 – Nomes dos widgets GWT 2.1 Fonte: Adaptado de WIDGET... (2011). Exemplo: Criação de um Date Picker. Na Figura 14 é mostrado a imagem de um date picker. Figura 14 – Date Picker. Fonte: DATE… (2011). 43 .gwt-DatePicker { border: 1px solid #A2BBDD; cursor: default; } .gwt-DatePicker td, .datePickerMonthSelector td:focus { outline: none } .datePickerMonthSelector td:focus { outline: none } .datePickerDays { width: 100%; background: white; } .datePickerDay, .datePickerWeekdayLabel, .datePickerWeekendLabel { font-size: 75%; text-align: center; padding: 4px; outline: none; } .datePickerWeekdayLabel, .datePickerWeekendLabel { background: #C3D9FF; padding: 0px 4px 2px; cursor: default; } .datePickerDay { padding: 4px; cursor: hand; cursor: pointer; } .datePickerDayIsToday { border: 1px solid black; padding: 3px; } .datePickerDayIsWeekend { background: #EEEEEE; } .datePickerDayIsFiller { color: #888888; } .datePickerDayIsValue { background: #aaccee; } .datePickerDayIsDisabled { color: #AAAAAA; font-style: italic; } .datePickerDayIsHighlighted { background: #F0E68C; } .datePickerDayIsValueAndHighlighted { background: #bbddd9; } .datePickerMonthSelector { background: #C3D9FF; width: 100%; 44 } .datePickerPreviousButton, .datePickerNextButton { font-size: 120%; line-height: 1em; color: blue; cursor: hand; cursor: pointer; padding: 0px 4px; } td.datePickerMonth { text-align: center; vertical-align: center; white-space: nowrap; font-size: 70%; font-weight: bold; color: blue; } .gwt-DateBox input { width: 8em; } .dateBoxFormatError { background: #ffcccc; } .dateBoxPopup { } Código 4 – Folha de estilo do date picker Fonte: DATE… (2011). /** * The constants used in this Content Widget. */ public static interface CwConstants extends Constants { String cwDatePickerBoxLabel(); String cwDatePickerDescription(); String cwDatePickerLabel(); String cwDatePickerName(); } /** * An instance of the constants. */ private final CwConstants constants; /** * Initialize this example. */ @SuppressWarnings("deprecation") @Override public Widget onInitialize() { // Create a basic date picker DatePicker datePicker = new DatePicker(); final Label text = new Label(); // Set the value in the text box when the user selects a date datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() { public void onValueChange(ValueChangeEvent<Date> event) { 45 Date date = event.getValue(); String dateString = DateTimeFormat.getMediumDateFormat().format(date); text.setText(dateString); } }); // Set the default value datePicker.setValue(new Date(), true); // Create a DateBox DateTimeFormat dateFormat = DateTimeFormat.getLongDateFormat(); DateBox dateBox = new DateBox(); dateBox.setFormat(new DateBox.DefaultFormat(dateFormat)); // Combine the widgets into a panel and return them VerticalPanel vPanel = new VerticalPanel(); vPanel.add(new HTML(constants.cwDatePickerLabel())); vPanel.add(text); vPanel.add(datePicker); vPanel.add(new HTML(constants.cwDatePickerBoxLabel())); vPanel.add(dateBox); return vPanel; } Código 5 – Fonte do DatePicker Java/GWT Fonte: DATE… (2011). O código java acima mostra a criação de um date picker, onde os objetos são inseridos em um painel (vPanel) e ele é retornado pelo método publico widget. Caso esta função seja chamada por um JavaScript em uma página HTML o Date Picker será desenhado no local chamado. A coleção de Widgets GWT nativos ainda é limitada, espaço que acaba sendo preenchido por bibliotecas de terceiros como Ext-Sencha, Smart-GWT e GWT Mosaic. Na Figura 15 é ilustrada a biblioteca Smart-GWT com 300 exemplos de uso de widgets (SMART…, 2011). 46 Figura 15 – Biblioteca Smart-GWT Fonte: SMART... (2011). 3.4 SETTING UP GWT O Plug-in do Google para o Eclipse (Figura 16 e 17) é a maneira mais rápida de começar o desenvolvimento de aplicativos do Google Web Toolkit e do Google App Engine. Com a instalação do plug-in é possível a implementação de um ―Hello World‖ Ajax em questão de minutos. Basta instalar o plug-in e começar. O estudo de caso deste trabalho usará o Eclipse 3.6 (Helios). Os detalhes para obtenção do Eclipse e dos plugins estão descritos em GOOGLE CODE. Na Figura 18 é mostrada a instalação dos plugins do GWT no eclipse, o Google Plugin para o Eclipse 3.6 está na versão 1.4.2, o Google App Engine Java SDK está na versão 1.4.0 e o Google Web ToolKit DSK está na versão 2.1.1, as ultimas versões disponíveis até este momento. 47 Figura 16 – Eclipse Helios 3.6 Fonte: Autoria própria. Figura 17 – IDE Eclipse Helios 3.6 com os ícones do GWT e App Engine Fonte: Autoria própria. Uma preocupação no uso do GWT é conhecer as melhores práticas ao desenvolver aplicações, para escrever código desacoplado, testável e manutenível. Ray Ryan um dos arquitetos do GWT no Google I/O em 2009 e 2010 (Figura 19) discutiu a inexistência de uma API nativa implementando estas melhores práticas, ficava a cargo do desenvolvedor interpretá-las e programar a sua própria arquitetura caseira. Com o GWT 2.1 a Google começa a preencher estas lacunas, entre as novidades da nova versão está o Data Presentation Widgets, o Data Binding com editors e o Framework GWT-MVP, baseado em Atividades e Lugares (Activities e Places). 48 Figura 18 – Detalhes da instalação do GWT e App Engine no Eclipse 3.6 Fonte: Autoria própria. Figura 19 – Ray Ryan no Google I/O 2009. Fonte: GOOGLE I/O... (2009). 49 3.5 PROJETO E DESENVOLVIMENTO Depois de tudo instalado localmente, pois o eclipse ainda não trabalha nas nuvens, basta criar um novo projeto informando o local no HD (workspace) em que será gravado e seu nome. Na Figura 20 é ilustrada a janela de criação de um projeto GWT. Figura 20 - Criação de um projeto GTW. Fonte: Autoria própria. 50 A ferramenta GWT cria uma estrutura de diretórios como a ilustrada na Figura 21. Figura 21 – Estrutura de diretórios de um projeto GTW Fonte: Autoria própria. Todo o código Java desenvolvido como classes Java e servlets fica residente no diretório src (source) que é dividido pelos sub-diretórios client (código que é executado no browser do usuário), shared (código que pode ser executado tanto do lado cliente como do lado servidor) e o diretório server (código que é executado exclusivamente no lado do servidor). As classes de teste ficam no diretório test. No pacote META INF ficam as configurações XML para persistência, no pacote App Engine SDK ficam o SDK para o desenvolvimento em cloud, no pacote JRE ficam o Java runtime no pacote WEB-INF contém a pasta lib para agregar drivers e frameworks do projeto. O código gerado pela ferramenta para distribuição da aplicação fica no diretório war (Web Archive). Os arquivos com extensão war são um compactado de todo o código para implantação no servidor de aplicação. No diretório ―war‖ também ficam os arquivos estáticos como os de formatação CSS, HTML e imagens por exemplo. A unidade básica do GWT são os módulos. Estes módulos são usados pela aplicação cliente ou para criação de bibliotecas que serão usadas por outras aplicações. A definição dos módulos estão no arquivo gwt.xml, como exemplificado no Código 6. 51 <?xml version="1.0" encoding="ISO-8859-1"?> <module rename-to='cotacaoacoes'> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/> --> <!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <inherits name='com.google.gwt.user.theme.standard.Standard'/> <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> --> <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> --> <!-- Other module inherits --> <!-- Specify the app entry point class. --> <entry-point class='com.dvillela.gwt.cotacaoacoes.client.CotacaoAcoes'/> <!-- Specify the paths for translatable code <source path='client'/> <source path='shared'/> --> </module> Código 6 - Exemplo de um arquivo gwt.xml para definição de módulos Fonte: Autoria própria, utilizando o Eclipse. Nesta definição de módulo o código, encoding="ISO-8859-1" permite o uso de caracteres em português, <module rename-to='cotacaoacoes'> define o nome do módulo, <inherits name='com.google.gwt.user.User'/> indica herança das classes gwt.user, <entrypoint class='com.dvillela.gwt.cotacaoacoes.client.CotacaoAcoes'/> especifica o módulo de entrada quando o aplicativo for executado e <inherits name= 'com.google.gwt.user.theme.standard.Standard'/> especifica o uso do estilo default para os widgets. Depois de tudo desenvolvido, a fase de testes basta executar o projeto como uma aplicação Web. Na Figura 22 é ilustrada a forma de entrar em modo de desenvolvimento e teste da aplicação. Na janela Console é informado os erros de compilação ou as mensagens de compilação com sucesso. Na janela Development Mode é informada a URL para teste local, a ferramenta de desenvolvimento simula um servidor de aplicação (Jetty), que compõem o desenvolvimento para cloud computing utilizando o Google Application Engine. 52 Figura 22 – Modo de desenvolvimento do GWT no Eclipse Fonte: Autoria própria. Depois de testada a aplicação, é necessário definir o Application ID e sua versão (controle de versões) para fazer a implantação no Data da Google. A versão do SDK do App Engine no servido da Google está na versão 1.4.1 neste momento, e no ambiente de desenvolvimento está disponível a versão 1.4.0. Na Figura 23 é ilustrada esta janela. 53 Figura 23 – Configuração dos parâmetros para implantação Fonte: Autoria própria. Finalmente para terminar a implantação no Data Center é necessário o uso de uma conta no Google, pode ser a mesma do Gmail. Na Figura 24 é ilustrada esta janela. Todo este processo está descrito em detalhes no Google Code. Figura 24 – Implantação da aplicação no Data Center da Google Fonte: Autoria própria. 54 3.6 TRABALHANDO COM BROWERS Um problema para as aplicações escritas com a ferramenta GWT é voltar à tela anterior no browser usando Alt+Backspace, combo ou botão do browser, porque as aplicações GWT são executadas em uma única janela criada dinamicamente e sendo modificada conforme a necessidade, e esta ação provavelmente farão uma desconexão da aplicação com o usuário, ou algo inesperado de difícil tratamento. O usuário não pode esperar que uma aplicação GWT se comporte de forma diferente das outra aplicações Web, o desenvolvedor não tem como desabilitar o Alt+Backspace, por este motivo o GWT possui métodos para tratar de históricos. Para usar as classes de gerenciamento de históricos do GWT é necessário inserir no corpo <body> da página HTML o seguinte código JavaScript. <!-- OPTIONAL: include this if you want history support --> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position: absolute; width: 0; height: 0; border: 0"> </iframe> Código 7 – Ativação do gerenciamento de histórico de navegação do GWT. Fonte: Autoria própria. Outro problema encontrado é a bloqueio de execução de JavaScript na configuração dos navegadores. O que o desenvolvedor pode fazer no máximo é gerar uma exceção no código HTML, informando o usuário para habilitar a execução de códigos JajaScript, ou a aplicação não será executada. Para fazer isto basta acrescentar ao código HTML o seguinte código. O Código 8 faz com que o navegador do cliente emita uma mensagem caso ele não esteja habilitado para executar JavaScript. <!-- RECOMMENDED if your web app will not function without JavaScript enabled --> <noscript> <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; border: 1px solid red; padding: 4px; font-family: sans-serif"> Your web browser must have JavaScript enabled in order for this application to display correctly. </div> </noscript> Código 8 – Código para exibir mensagem do status do navegador Fonte: Autoria própria. 55 O resultado caso a execução de JavaScript não esteja habilitada, é a mensagem que aparece no navegador como a mostrada na figura 25, alertando que a execução de JavaScript não está habilitada. Figura 25 - Mensagem no browser Fonte: Autoria própria. 3.7 DESENVOLVIMENTO DE INTERFACE COM O USUÁRIO O padrão de desenvolvimento clássico de interface com o usuário é o MVC (ModelView-Controller), que surgiu com o Smalltalk na década de 80, tinha como principal objetivo implementar uma alta independência entre os módulos do modelo,a view, a apresentação e a lógica. Basicamente o padrão MVC é composto de: Model, aqui se encontram toda a lógica de negócios da aplicação, Para sistemas baseados em Web, isto significa servlets, web services ou qualquer outra forma de implementação de requisitos do sistema no lado do servidor de aplicação. View, aqui estão todos os widgets necessários para interação com o usuário. Para sistemas Web a camada de view reside no lado do cliente. Controller, sua função é traduzir as ações do usuário para a camada de modelo. Dependendo do framework usado ele pode se encontrar o lado cliente ou no lado servidor, mas isto não é relevante aqui. Com o surgimento de novas tecnologias como o GWT, e o aperfeiçoamento dos frameworks de interface, o modelo MVC ficou mais difícil de ser seguido pelas aplicações que utilizem estes componentes, os próprios componentes passaram a ter agora meios melhores de manipulação de eventos realizados pelos usuários, e o padrão MVC não permite que a camada view possa ser manipulada diretamente como acontece com JSP, por exemplo, ou seja, precisamos disparar um evento e deixar que a servlet trate esta mudança (recarregar a 56 págiana web). Desta forma a camada de Controller passou a cair em desuso, já que caso fosse utilizado os componentes estariam sendo subtilizados (CAMILO, 2010) Para solucionar este problema, surge o modelo MVP (Model View Presenter), uma variação do padrão MVC clássico, porém mais adequada para as novas tecnologias como o GWT. Neste modelo, as responsabilidades que eram do Controller são redistribuídas entre as camadas View e o Presenter, a View se encarrega de lidar com as entradas dos usuários, e o Presenter se encarrega de interagir com o Modelo, desta forma, o Presenter tem direito de interagir diretamente com a View. Basicamente o padrão MVP é composto de: Model, tem a mesma regra do modelo MVC, mas somente se comunica com a camada Presenter. View, tem regra similar ao modelo MVC, mas não de comunica com a camada Model. Sempre que o usuário dispara um evento, esta camada informa o Presenter sobre o evento, que pode pedir para a camada View se atualizar. Presenter, é a novidade deste padrão, por ser uma ponte entre a camada de Model e a camada View. Em resposta para eventos de usuários esta camada pode se comunicar com o Model e dependendo da resposta pode enviar comandos para a camada de View. Na Figura 26 é ilustrado o relacionamento das camadas nos modelos MVC e MVP. Figura 26 – Modelos MVC e MVP Fonte: Camilo (2010). 57 No padrão MVP a camada View é muito simples e praticamente não tem código, terá somente código para criar widgets, pegar e setar seus valores e disparar eventos para a camada Presenter. Se o usuário entrar com um valor em um widget, a camada View não fará sua validação, disparando um evento para a camada Presenter validar. Antes de implementar o padrão MVP, é necessário conhecer o conceito de callback. Nas aplicações em uma arquitetura de objetos distribuídos como é o caso do GWT, nem sempre a comunicação no estilo cliente-servidor é suficiente para atender aos requisitos da aplicação. É usual que o servidor RMI (Remote Method Invocation) aja algumas vezes com o cliente, invertendo os papéis com o cliente RMI original. Por exemplo, um applet cliente RMI. Nesse applet, não há como saber se outro cliente do mesmo objeto remoto na rede realizou alguma atualização no valor de um atributo deste mesmo objeto usado pelo applet a não ser pressionando o botão Get, e verificando se houve mudança. Essa é uma situação típica em muitas aplicações, sendo clara a necessidade de realizar tais notificações de forma automática. A tecnologia para atingir esse objetivo é utilizar a estratégia de callback. Esta técnica é utilizada quando a aplicação cliente requer um retorno do servidor, mas não quer permanecer bloqueada aguardando a resposta enquanto o servidor a processa. Através dessa tecnologia, o servidor obtém uma referência para o cliente para poder invocar remotamente um método do objeto cliente. Assim, quando o processamento do serviço solicitado for concluído o servidor pode notificar o cliente através da invocação do método disponibilizado pelo cliente para uso remoto. Assim como para o objeto servidor RMI, o cliente deve oferecer uma interface remota para o servidor (que é o cliente agora) a fim de permitir que o servidor tenha acesso ao serviço de atualização do cliente. Com callback, ambos cliente e servidor devem implementar o serviço remoto especificado. Um exemplo bem simples de callback são os métodos contidos nos aparelhos de telefônica celular, em que a operadora deve ter acesso ao método de tocar do celular, ou seja, neste caso o celular é o servidor e a operadora o cliente. Outro conceito utilizado no GWT é Generics, ou programação genérica, que serve para determinar ao compilador qual tipo de classe deve ser interpretada. Na Figura 27 é ilustrado um modelo de classes escrito na linguagem de modelagem unificada (UML) utilizando a ferramenta JUDE professional, de um projeto de tela de login no padrão MVP. As classes SimpleCallback e Presenter são classes genéricas, e é a classe LoginFormPresenter que determina o tipo de objetos que elas vão manipular. 58 A Classe Model tem diversos métodos para acessar os serviços do lado do servidor. Figura 27 – Diagrama de classes UML para o padrão MVP da tela de login Fonte: Autoria própria. A classe de abstrata SimpleCallback listada no Código 9, possibilita escrever códigos Java mais curtos, pois ela é genérica para qualquer outro projeto. import com.google.gwt.user.client.rpc.AsyncCallback; public abstract class SimpleCallback<T> implements AsyncCallback<T> { @Override public final void onFailure(Throwable caught) { // Nunca deverá ser usado 59 } @Override public final void onSuccess(T result) { goBack(result); } public abstract void goBack(T result); } Código 9 – Implementação da classe SimpleCallback Fonte: Kereki (2010). A interface AsyncCallback requer a implementação de ambos os métodos onFailure e onSuccess. Contudo não há necessidade de lidar com falhas, somente com sucessos. Esta classe abstrata SimpleCallback define os métodos onFailure e onSuccess finais, portanto não necessidade de ser implementado, e o método goBack como abstrato que necessita ser implementado futuramente. Na classe Presenter<D> descrita no Código 10, é injetado via construtor o apropriado Environment e View. A classe Presenter injeta os callbacks na classe View através do método definido na interface Display. abstract public class Presenter<D> { private String params; private D display; private Environment environment; private KeyValueMap kvm; public Presenter() { } public Presenter(String someParams, D aDisplay, Environment anEnvironment) { super(); params = someParams; display = aDisplay; environment = anEnvironment; kvm = new KeyValueMap(params); } public D getDisplay() { return display; } public Environment getEnvironment() { return environment; } public KeyValueMap getKvm() { return kvm; } } Código 10 – Classe Presenter<D> Fonte: Kereki (2010). 60 Na classe LoginFormPresenter listada no Código 11, a string PLACE serve para o bookmark e gerenciamento de histórico import com.fkereki.mvpproject.client.Environment; import com.fkereki.mvpproject.client.Presenter; import com.fkereki.mvpproject.client.SimpleCallback; import com.fkereki.mvpproject.client.rpc.LoginServiceAsync; import com.google.gwt.user.client.rpc.AsyncCallback; public class LoginFormPresenter extends Presenter<LoginFormDisplay> { public static String PLACE = "login"; LoginServiceAsync loginService; SimpleCallback<String> loginSuccessCallback; public LoginFormPresenter( final String params, final LoginFormDisplay loginDisplay, final Environment environment, final SimpleCallback<String> callback) { super(params, loginDisplay, environment); loginSuccessCallback = callback; loginService = getEnvironment().getModel().getRemoteLoginService(); loginDisplay.setName("domingos"); loginDisplay.setPassword(""); loginDisplay.setLoginCallback(new SimpleCallback<Object>() { @Override public void goBack(final Object result) { final String name = LoginFormPresenter.this.getDisplay().getName(); final String pass = LoginFormPresenter.this.getDisplay().getPassword(); loginService.getSomething(name, pass,new AsyncCallback<String>() { public void onFailure(final Throwable caught) { LoginFormPresenter.this.getEnvironment().showAlert("Failed login"); loginSuccessCallback.onFailure(new Throwable()); } public void onSuccess(final String result) { loginSuccessCallback.goBack(result); } }); } }); } } Código 11 – Classe LoginFormPresenter Fonte: Kereki (2010). 61 O Código 12 mostra a listagem da interface LoginFormDisplay que herda os métodos de Display. import com.fkereki.mvpproject.client.Display; import com.fkereki.mvpproject.client.SimpleCallback; public interface LoginFormDisplay extends Display { /** * Access the Name field * * @return Whatever the user entered in the Name field */ String getName(); /** * Initialize the Name field * * @param s * Set the name field to s; most commonly just "" or possibly a saved * name from an earlier session. */ void setName(String s); /** * Access the Password field * * @return Whatever the user entered in the Password field */ String getPassword(); /** * Initialize the Password field * * @param s * Set the password field to s; usually just "" */ void setPassword(String s); /** * Initialize the login callback, which shall be executed when the user clicks * the "Login" button * * @param acb * Set the login callback to acb. The Presenter will have to get the * Name and Password fields (by using the methods above) and perform * the needed checks. */ void setLoginCallback(SimpleCallback<Object> acb); } Código 12 – Interface LoginFormDisplay Fonte: Kereki (2010). 62 O Código 13 mostra a listagem da interface Display. import com.google.gwt.user.client.ui.Widget; /** * @author fkereki */ public interface Display { public Widget asWidget(); } Código 13 – Interface Display Fonte: Kereki (2010). O Código 14 mostra a listagem da classe LoginFormView que por sua vez herda View que herda Composite, e implementa LoginFormDisplay. import com.fkereki.mvpproject.client.SimpleCallback; import com.fkereki.mvpproject.client.View; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DockPanel; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextBox; /** * Defines a Login Form. */ public class LoginFormView extends View implements LoginFormDisplay { private AsyncCallback<Object> loginCallback; private final TextBox nameTextBox = new TextBox(); private final TextBox passwordTextBox = new PasswordTextBox(); private final Button loginButton = new Button("Log in"); private final FlexTable flex = new FlexTable(); private final DockPanel dock = new DockPanel(); /** * Defines the view for the Login Form. Since this will be shown in the main * screen, we take care of centering the fields (by using a DockPanel) so it * will look nicer. */ public LoginFormView() { loginButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { loginCallback.onSuccess(null); } }); flex.setWidget(0, 0, new Label("User name:")); flex.setWidget(0, 1, nameTextBox); 63 flex.setWidget(1, 0, new Label("Password:")); flex.setWidget(1, 1, passwordTextBox); flex.setWidget(2, 1, loginButton); dock.setWidth("100%"); dock.setHeight("100%"); dock.setHorizontalAlignment(DockPanel.ALIGN_CENTER); dock.setVerticalAlignment(DockPanel.ALIGN_MIDDLE); dock.add(flex, DockPanel.CENTER); initWidget(dock); } @Override public final String getName() { return nameTextBox.getValue(); } @Override public final String getPassword() { return passwordTextBox.getValue(); } @Override public final void setLoginCallback(final SimpleCallback<Object> acb) { loginCallback = acb; } @Override public final void setName(final String s) { nameTextBox.setValue(s); } @Override public final void setPassword(final String s) { passwordTextBox.setValue(s); } } Código 14 – Classe LoginFormView Fonte: Kereki (2010). O Código 15 mostra a listagem da classe View. import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; /** * @author fkereki */ public abstract class View extends Composite { public final Widget asWidget() { return this; } } Código 15 – Classe View Fonte: Kereki (2010). 64 Há uma forma de evitar que o código de criação dos widgets não fique dentro da classe LoginFormView vinculado a interface de usuário a duas ou três linhas de código por widget, e que facilita o trabalho com um grande número de elementos de interface. Outro problema é entender o layout produzido pelo código Java, e a comunicação entre o projeto da interface do usuário feita em HTML, CSS e XML e o código GWT. O GWT 2 criou o UiBinder que atenua o problema, permitindo que a interface com o usuário seja feita declarativamente usando linguagem de marcação XML, que é transformada em código Java pelo compilador. UiBinder aceita estilos CSS e internacionalização. Na Figura 28 é ilustrada a criação de um UiBinder pelo plugin do GWT no eclipse. Figura 28 – Criação de um arquivo UiBinder Fonte: Autoria própria. Uma versão do exemplo de login usando UiBinder é listado no Código 16. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE u:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <u:UiBinder xmlns:u='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' > <g:HTMLPanel> <h1>LoginFormView3</h1> <table> <tr> <td><g:Label text="User Name:"/></td> <td><g:TextBox u:field='nameTextBox'/></td> 65 </tr> <tr> <td><g:Label text="Password:"/></td> <td><g:PasswordTextBox u:field='passwordTextBox'/></td> </tr> <tr> <td></td> <td><g:Button text='Login' u:field='loginButton'/></td> </tr> </table> </g:HTMLPanel> </u:UiBinder> Código 16 – Exemplo de arquivo XML para definição de interface gráfica. Fonte: Kereki (2010). O compilador faz uma referencia cruzada entre o arquivo UiBinder e a nova classe LoginFormView é mostrada o Código 17. import com.fkereki.mvpproject.client.SimpleCallback; import com.fkereki.mvpproject.client.View; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.uibinder.client.UiTemplate; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextBox; /** * Defines a Login Form. */ public class LoginFormView extends View implements LoginFormDisplay { @UiTemplate("UiLoginFormView.ui.xml") interface Binder extends UiBinder<HTMLPanel, UiLoginFormView> { } AsyncCallback<Object> loginCallback; AsyncCallback<Object> nameBlurCallback; AsyncCallback<Object> passwordBlurCallback; @UiField TextBox nameTextBox; @UiField PasswordTextBox passwordTextBox; @UiField Button loginButton; private static final Binder binder = GWT.create(Binder.class); public LoginFormView() { HTMLPanel dlp = binder.createAndBindUi(this); initWidget(dlp); } @Override 66 public void enableLoginButton(final boolean b) { loginButton.setEnabled(b); } @Override public final String getName() { return nameTextBox.getValue(); } @Override public final String getPassword() { return passwordTextBox.getValue(); } @Override public final void setLoginCallback(final SimpleCallback<Object> acb) { loginCallback = acb; } @Override public final void setName(final String s) { nameTextBox.setValue(s); } @Override public void setNameBlurCallback(final SimpleCallback<Object> acb) { nameBlurCallback = acb; } @Override public final void setPassword(final String s) { passwordTextBox.setValue(s); } @Override public void setPasswordBlurCallback(final SimpleCallback<Object> acb) { passwordBlurCallback = acb; } @UiHandler("nameTextBox") void uiOnBlurName(BlurEvent event) { nameBlurCallback.onSuccess(null); } @UiHandler("passwordTextBox") void uiOnBlurPassword(BlurEvent event) { passwordBlurCallback.onSuccess(null); } @UiHandler("loginButton") void uiOnLoginButton(ClickEvent event) { loginCallback.onSuccess(null); } } Código 17 – Classe LoginFormView usando UiBinder Fonte: Kereki (2010). 67 3.8 COMUNICAÇÃO COM O SERVIDOR DE APLICAÇÕES Para a implementação de comunicação entre o lado cliente e o lado servidor, existe duas tecnologias a RPC e RMI. Marshalling é o processo de se empacotar uma coleção de objetos em um formato específico para sua transmissão em uma mensagem, e Unmarshalling é o processo inverso. RMI (Remote Method Invocation) é uma tecnologia para chamadas de métodos em objetos remotos. Para se comunicar com objetos remotos, são usados stubs e skeletons, o stub funciona semelhante a um proxy para o objeto remoto. Quando um objeto local invoca um método num objeto remoto, o stub fica responsável por enviar a chamada ao método do objeto remoto. Os passos do stub quando é invocado são: Iniciar conexão com a Virtual Machine que contém o objeto remoto. Escrever (Marshalling) e transmitir os parâmetros para a Virtual Machine remota. Esperar pelos resultados da invocação do método. Ler os resultados retornados. Retornar os valores ao objeto que executou a chamada. Na Virtual Machine remota, cada objeto deve ter um skeleton correspondente ao stub. O skeleton é responsável por enviar a chamada ao objeto remoto. Passos do skeleton quando recebe uma chamada: Ler os parâmetros (Unmarshalling) enviados pelo stub. Invocar o método no objeto remoto. Escrever (Marshalling) e transmitir o resultado ao objeto que executou a chamada. No paradigma orientado a objetos a distribuição física dos objetos é, natural. RMI é uma interface de programação que permite a execução de chamadas remotas em aplicações desenvolvidas em Java RMI, OMG CORBA (Common Object Request Broker Architecture) ou Microsoft DCOM (Distributed Common Object Model). É uma das abordagens da plataforma Java para prover as funcionalidades de objetos distribuídos. Esse sistema de objetos distribuídos faz parte do núcleo básico de Java desde a versão JDK 1.1, com sua API 68 sendo especificada através do pacote java.rmi. A Figura 29 ilustra o funcionamento desta tecnologia. Figura 29 – Tecnologia Remote Method Invocation Fonte: Adaptado RMI-IIPO (2011). O RPC, (Remote Procedure Call) é uma tecnologia de comunicação entre processos que torna possível a um programa de computador chamar um método em outro computador, conectado por uma rede. O desenvolvedor não precisa se preocupar com detalhes de implementação dessa interação remota. Do ponto de vista do código, a chamada se assemelha às chamadas de procedures locais. RPC é uma tecnologia para a implementação do modelo cliente-servidor de computação distribuída. Uma chamada de procedimento remoto é iniciada pelo cliente enviando uma mensagem para um servidor remoto para executar um método específico, uma resposta é retornada ao cliente. A implementação de chamadas a procedimento remoto é feita com os seguintes passos: O procedimento cliente chama localmente o stub cliente; Stub cliente constrói (Marshalling) a mensagem e chama o SO local; O SO local envia a mensagem ao SO remoto; O SO Remoto entrega a mensagem ao stub servidor; O stub servidor desempacota (Unmarshalling) os parâmetros e chama o procedimento servidor; O servidor realiza o trabalho retornando o resultado ao stub; O stub servidor empacota (Marshalling) o resultado em uma mensagem e chama o SO local; 69 O SO do servidor envia a mensagem ao SO do cliente; O SO do cliente entrega a mensagem ao stub cliente; O stub cliente desempacota (Unmarshalling) o resultado e o retorna ao cliente. RPC permite ao desenvolvedor GWT escrever código Java como se o lado cliente e o lado servidor estivesse residente na mesma máquina, permitindo que a conexão fique praticamente invisível. Na Figura 30 é ilustra no mecanismo de comunicação utilizado pelo GWT. Figura 30 – Arquitetura do GWT. Fonte: DEVELOPER´S... (2011). A mais importante diferença entre o RMI e o RPC é a forma de sincronismo, no RMI o processo de comunicação é síncrono ou seja ele bloqueia o processo chamador até que o processo servidor responda, e no RPC o processo de comunicação é assíncrono ou seja o processo chamador não fica bloqueado. No modelo RPC utilizado pelo GWT há algumas diferenças, por exemplo, o código do lado servidor pode usar qualquer pacote do Java, enquanto do lado cliente o código é limitado. Para implementação o RPC usa Ajax e o GWT prove as classes clientes HTTP. No lado servidor servlets são usadas estendendo a classe RemoteServiceServlet e não há limites, nesta arquiterua pode-se usar EJB (Enterprise Java Beans) ou serviços Restful (técnica de engenharia de software para sistemas hipermídia distribuídos como o www). O uso mais comum de RPC é acessar servles ou EJB no lado servidor, código particionado desta forma reduz o tempo de carga da aplicação. 70 Uma principal diferença entre as aplicações AJAX e aplicações web tradicionais em HTML é que nos aplicativos Ajax não é necessário buscar novas páginas HTML, enquanto eles executam. Como as páginas Ajax realmente funcionam mais como aplicações dentro do navegador, não há necessidade de solicitar novo HTML do servidor para fazer atualizações de interface com o usuário. No entanto, como todas as aplicações cliente/servidor, aplicações Ajax geralmente precisam buscar dados do servidor. Quando usado corretamente, RPCs pode mudar toda a lógica da interface do usuário para o cliente sem recarregar a página, resultando em um desempenho muito melhorado, diminuindo a largura de banda, e reduzindo a carga do servidor web. O código server-side que é chamado do cliente é muitas vezes referida como um serviço, portanto o ato de fazer uma chamada de procedimento remoto é por vezes referido como chamar um serviço. A palavra ―serviço‖ neste contexto não é o mesmo que web service no conceito geral. Em particular, os serviços do GWT não estão relacionados com o Simple Object Access Protocol (SOAP). Na arquitetura do GWT a interface publica YourService fica do lado cliente, e é a interface YourServiceAsync que implementa o stub é quem intermediará com o servidor o qual passa o resultado para o chamador via AsyncCallback. É na classe publica YourServiceImp que ficará todo o código Java que implementa os serviços do lado servidor. O Código 18 mostra o arquivo war/WEB-INF/lib/web.xml que fornece dados sobre a servlet remota, usando <servlet> e <servlet-mapping>. <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE web-app (View Source for full doctype...)> <web-app> <!-- Servlets --> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.fkereki.mvpproject.server.LoginServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/mvpproject/login</url-pattern> </servlet-mapping> <!-- Default page to serve --> <welcome-file-list> <welcome-file>Mvpproject.html</welcome-file> </welcome-file-list> </web-app> Código 18 – Web.xml Fonte: Kereki (2010). 71 Serialização é usada transparentemente pelo GWT, de forma genérica a serialização é uma técnica usada para persistir objetos (gravar objetos em disco ou banco de dados) ou fazer a transmissão remota de objetos via rede. Serializar é simplesmente colocar os valores dos atributos que o objeto está utilizando juntamente com suas propriedades de uma forma que fique em série (seqüencial). Objeto serializavel, tem privilégios para que o mesmo possa ser gravado em disco ou enviado por rede. Portanto a serialização é o processo de transformar um objeto, incluindo todos os atributos públicos e privados em um stream (fluxo de dados em um sistema computacional) para ser transportado. Na Figura 31 é ilustrada a gravação de um objeto em um arquivo no HD. Figura 31 – Serialização de um objeto, e persistência em disco rígido Fonte: Pereira (2010). O GWT tem seus próprios métodos de serialização, a regra para definição dos tipos serializáveis são simples. Todos os tipos primitivos (char, byte, short, int, long), tipos enumerados (string,e data), e arrays são serializáveis. Uma classe será serializável se todos seus atributos são de tipos serializáveis, com exceção dos atributos transientes e finais. No Código 19 está a listagem de um exemplo de uma classe serializável pelo GWT. import com.google.gwt.user.client.rpc.IsSerializable; public class ClientCityData implements IsSerializable { public String countryCode; public String stateCode; public String cityName; public String cityAccentedName; public int population; public float latitude; public float longitude; /** * An empty constructor method is required for serializable classes... see * <a>http://blog.js-development.com/2008/08/strange-gwt-compiler-error-when- trying.html</a > * <a>http://code.google.com/p/google-web-toolkit/issues/detail?id=540</a> */ public ClientCityData() { } 72 public ClientCityData( final String pCountryCode, final String pStateCode, final String pCityName, final String pCityAccentedName, final int pPopulation, final float pLatitude, final float pLongitude) { countryCode = pCountryCode; stateCode = pStateCode; cityName = pCityName; cityAccentedName = pCityAccentedName; population = pPopulation; latitude = pLatitude; longitude = pLongitude; } /** * Perform client-side validations. The code here is limited to the GWT * client-side available packages. * * @return "" if the client data is OK, or an error description otherwise */ public String validationProblems() { if (countryCode.isEmpty()) { return "No country specified"; } else if (stateCode.isEmpty()) { return "No region specified"; } else if (cityName.isEmpty()) { return "No city name specified"; } else if (cityAccentedName.isEmpty()) { return "No accented city name specified"; } else if (population < 0) { return "Negative population"; } else if (latitude < -90 || latitude > 90) { return "Latitude outside -90..+90"; } else if (longitude < -180 || longitude > 180) { return "Longitude outside -180..+180"; } else { return ""; } } } Código 19 – Exemplo de classe serializável Fonte: Kereki (2010). O Código 20 lista o código da interface YourService.java import java.util.LinkedHashMap; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("world") public interface WorldService extends RemoteService { public String addCity(ClientCityData cd); public Boolean cityExists( String pCountry, String pRegion, 73 String pCity); public LinkedHashMap<String, ClientCityData> getCities( String pCountry, String pRegion, int pFrom, int pQuantity); public LinkedHashMap<String, ClientCityData> getCitiesStartingWith( String pCountry, String pRegion, String pStart); public LinkedHashMap<String, String> getCountries(); public LinkedHashMap<String, String> getStates(String pCountry); } Código 20 – Inferface YourService.java Fonte: Kereki (2010). Abaixo a listagem correspondente a Async interface derivado de WorldService. Pode ser criada automaticamente pelo plugin do GWT no Eclipse. import java.util.LinkedHashMap; import com.google.gwt.user.client.rpc.AsyncCallback; public interface WorldServiceAsync { void addCity(ClientCityData cd, AsyncCallback<String> callback); void cityExists( String pCountry, String pRegion, String pCity, AsyncCallback<Boolean> callback); void getCities( String pCountry, String pRegion, int pFrom, int pQuantity, AsyncCallback<LinkedHashMap<String, ClientCityData>> callback); void getCitiesStartingWith( String pCountry, String pRegion, String pStart, AsyncCallback<LinkedHashMap<String, ClientCityData>> callback); void getCountries( AsyncCallback<LinkedHashMap<String, String>> callback); void getStates( String pCountry, AsyncCallback<LinkedHashMap<String, String>> callback); } Código 21 – Inferface WorldServiceAsync Fonte: Kereki (2010). 74 Finalmente abaixo está a listagem da implementação dos serviços no lado servidor, pode-se usar JPA ou Hibernate nesta implementação. No Google Application Engine deve-se usar o Java Data Objects. import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.LinkedHashMap; import com.fkereki.mvpproject.client.rpc.ClientCityData; import com.fkereki.mvpproject.client.rpc.WorldService; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class WorldServiceImpl extends RemoteServiceServlet implements WorldService { private static final long serialVersionUID = 1L; /* * MySQL and JDBC related constants and variables */ static String jdbc_url = "jdbc:mysql://127.0.0.1/gwtdb"; static String mysql_user = "gwtuser"; static String mysql_password = "gwtpass"; private Connection conn = null; /** * Tries to add a new city to the database. * * @return "" if the city was added, or an error message otherwise */ public String addCity(final ClientCityData cd) { final ServerCityData scd = new ServerCityData(cd); final String svp = scd.validationProblems(); if (!svp.isEmpty()) { return svp; } else { try { connectToDatabase(); final PreparedStatement ps = conn .prepareStatement("INSERT INTO cities (countryCode, stateCode, " + "cityName, cityAccentedName, population, latitude, longitude) " + "VALUES (?,?,?,?,?,?,?)"); ps.setString(1, scd.countryCode); ps.setString(2, scd.stateCode); ps.setString(3, scd.cityName); ps.setString(4, scd.cityAccentedName); ps.setInt(5, scd.population); ps.setFloat(6, scd.latitude); ps.setFloat(7, scd.longitude); ps.executeUpdate(); ps.close(); disconnectFromDatabase(); } catch (final Exception e) { return "Error adding city: " + e.getMessage(); 75 } return ""; } } public Boolean cityExists( final String pCountryCode, final String pStateCode, final String pCityName) { boolean result = false; try { connectToDatabase(); final Statement stmt = conn.createStatement(); final ResultSet rs = stmt .executeQuery("SELECT COUNT(*) FROM cities WHERE countryCode='" + pCountryCode + "' AND stateCode='" + pStateCode + "' AND cityName='" + pCityName + "'"); rs.first(); result = rs.getInt(1) > 0; stmt.close(); disconnectFromDatabase(); } catch (final Exception e) { e.printStackTrace(); } return new Boolean(result); } /** * Establish a connection to the local database and set up a statement */ private void connectToDatabase() throws Exception { DriverManager.registerDriver(new com.mysql.jdbc.Driver()); Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(jdbc_url, mysql_user, mysql_password); } /** * Disconnect from the database, closing everything */ private void disconnectFromDatabase() throws Exception { conn.close(); } public LinkedHashMap<String, ClientCityData> getCities( final String pCountryCode, final String pStateCode, final int pFrom, final int pQuantity) { final LinkedHashMap<String, ClientCityData> citiesList = new LinkedHashMap<String, ClientCityData>(); try { 76 connectToDatabase(); final Statement stmt = conn.createStatement(); final ResultSet rs = stmt .executeQuery("SELECT * FROM cities WHERE countryCode='" + pCountryCode + "' AND stateCode='" + pStateCode + "' ORDER BY cityName LIMIT " + pFrom + "," + pQuantity); while (rs.next()) { citiesList.put(rs.getString("cityName"), new ClientCityData(rs .getString("countryCode"), rs.getString("stateCode"), rs .getString("cityName"), rs.getString("cityAccentedName"), rs.getInt("population"), rs.getFloat("latitude"), rs .getFloat("longitude"))); } stmt.close(); disconnectFromDatabase(); } catch (final Exception e) { e.printStackTrace(); } return citiesList; } public LinkedHashMap<String, ClientCityData> getCitiesStartingWith( String pCountryCode, String pStateCode, String pStart) { final LinkedHashMap<String, ClientCityData> citiesList = new LinkedHashMap<String, ClientCityData>(); try { connectToDatabase(); final Statement stmt = conn.createStatement(); final ResultSet rs = stmt .executeQuery("SELECT * FROM cities WHERE countryCode='" + pCountryCode + "' AND stateCode='" + pStateCode + "' AND cityName LIKE '" + pStart + "%' ORDER BY cityName"); while (rs.next()) { citiesList.put(rs.getString("cityName"), new ClientCityData(rs .getString("countryCode"), rs.getString("stateCode"), rs .getString("cityName"), rs.getString("cityAccentedName"), rs.getInt("population"), rs.getFloat("latitude"), rs .getFloat("longitude"))); } stmt.close(); disconnectFromDatabase(); } catch (final Exception e) { e.printStackTrace(); } return citiesList; } public LinkedHashMap<String, String> getCountries() { final LinkedHashMap<String, String> countriesList = new LinkedHashMap<String, String>(); 77 try { connectToDatabase(); final Statement stmt = conn.createStatement(); final ResultSet rs = stmt .executeQuery("SELECT countryCode,countryName " + "FROM countries ORDER BY 2"); while (rs.next()) { countriesList.put(rs.getString(1), rs.getString(2)); } stmt.close(); disconnectFromDatabase(); } catch (final Exception e) { e.printStackTrace(); } return countriesList; } public LinkedHashMap<String, String> getStates( final String pCountryCode) { final LinkedHashMap<String, String> statesList = new LinkedHashMap<String, String>(); try { connectToDatabase(); final Statement stmt = conn.createStatement(); final ResultSet rs = stmt .executeQuery("SELECT stateCode,stateName FROM states " + "WHERE countryCode='" + pCountryCode + "' ORDER BY 2"); while (rs.next()) { statesList.put(rs.getString(1), rs.getString(2)); } stmt.close(); disconnectFromDatabase(); } catch (final Exception e) { e.printStackTrace(); } return statesList; } } Código 22 – WorldServiceImpl Fonte: Kereki (2010). 3.9 MISTURANDO JAVASCRIPT E GWT JavaScript é para o GWT o que assembler é para um compilador clássico como linguagem C++, e misturar código JavaScript com código Java pode ser útil. Muitas vezes, você vai precisar para integrar o GWT com JavaScript existentes desenvolvidos em biblioteca de terceiros. Ocasionalmente pode ser necessária para acesso de 78 baixo nível a funcionalidade do navegador, não expostos pela classe GWT API. O JavaScript Native Interface (JSNI) do GWT pode resolver ambos os problemas, permitindo-lhe integrar o JavaScript diretamente em seu aplicativo de código-fonte Java. O compilador GWT traduz-fonte Java em JavaScript. Às vezes é muito útil para misturar manualmente JavaScript em seu código-fonte Java. Por exemplo, a funcionalidade de nível mais baixo de certas classes core do GWT são escritas em JavaScript. GWT empresta do Java Native Interface (JNI) o conceito para implementar o JavaScript Native Interface (JSNI). Escrevendo métodos JSNI é uma técnica poderosa, mas deve ser usado com moderação, pois escrever código JavaScript é visivelmente complicado. Código JSNI é potencialmente menos portável entre os navegadores, diminui as chances de estouro de memória, e é mais difícil para o compilador otimizar. Pensamos JSNI como o equivalente web de código assembly inline, pode-se usá-lo de muitas maneiras: Implementar um método Java diretamente no JavaScript Chamada de código JavaScript em código Java e vice-versa Lançar exceções para além das fronteiras Java / JavaScript Ler e escrever campos de Java a partir de JavaScript Usar o modo de desenvolvimento para depurar a fonte Java (com um depurador Java) e JavaScript (com um depurador de script) O Código 23, por exemplo, ilustra a função sayHello(name) escrita em JavaScript declarada na página HTML que pode ser chamada de qualquer elemento dentro de um módulo do GWT. <html> <head> <script> function sayHello(name) { alert("Hello from JavaScript, " + name); } </script> <-- Include the GWT module called "Spiffy" --> <script src="org.example.yourcode.Spiffy.nocache.js"> </script> </head> ... Código 23 – Função JavaScript sayHello(name) Fonte: Kereki (2010). 79 O Código 24 mostra no código fonte Java GWT, a chamada da função sayHello() JavaScript através de JSNI. // A Java method using JSNI native void sayHelloInJava(String name) { $wnd.sayHello(name); // $wnd is a JSNI synonym for 'window' }; Código 24 – Função JavaScript sayHello(name) Fonte: Kereki (2010). Agora o contrário acessar uma função GWT no JavaScript. O Código 25 mostra a listagem da função fornatAsCurrency escrita em linguagem Java no GWT. package org.example.yourcode.format.client; public class DateFormatterLib implements EntryPoint { // Expose the following method into JavaScript. private static String formatAsCurrency(double x) { return NumberFormat.getCurrencyFormat().format(x); } // Set up the JS-callable signature as a global JS function. private native void publish() { $wnd.formatAsCurrency = @org.example.yourcode.format.client.DateFormatterLib::formatAsCurrency(D); }; // Auto-publish the method into JS when the GWT module loads. public void onModuleLoad() { publish(); } } Código 25 – Função formatAsCurrency Fonte: Kereki (2010). O Código 26 ilustra a página HTML acessando a função GWT criada. <html> <head> <-- Include the GWT module that publishes the JS API --> <script src="org.example.yourcode.FormatLib.nocache.js"></script> <-- Write some JS that uses that GWT code --> <script> function doStuff() { alert(formatAsCurrency(1530281)); } </script> </head> ... Código 26 – Exemplo de função GWT acessada pelo HTML Fonte: Kereki (2010). 80 Usando JSNI, pode-se misturar JavaScript, bibliotecas externas JavaScript, e código Java livremente de qualquer maneira. JSON (JavaScript Object Notation) é uma forma de intercâmbio de dados leve, uma alternativa ao formato XML: É fácil para os desenvolvedores Java a ler e escrever. É fácil para as máquinas de analisar e gerar. É composto por um subconjunto da linguagem de programação JavaScript. JSON é um formato de texto, que é independente das linguagens de programação, mas usa convenções que são familiares para os desenvolvedores de C, incluindo C ++, C#, Java, JavaScript, Perl, Python, e outros. Estas propriedades tornam JSON uma linguagem de troca de dados ideal. GWT suporta este protocolo, GWT2 inclui várias classes e métodos para facilitar o processamento JSON. JSON é composto de uma coleção de pares nome / valor. Em várias linguagens, isto é implementado como um objeto, dicionário, hash, tabela com chave primária, ou uma lista ordenada de valores. Estas estruturas de dados são universais. Praticamente todas as linguagens de programação modernas as usam de alguma forma. Faz sentido que um formato de dados, que é intercambiável entre linguagens de programação também basear-se nestas mesmas estruturas. JSON é um conjunto desordenado de pares nome / valor. Um objeto que começa com {(chave esquerda) e termina com } (chave direita). Cada nome é seguido por: (dois pontos) e os pares nome / valor são separados por, (vírgula). Na Figura 32 é ilustrada a sintaxe do JSON. 81 Figura 32 – Sintaxe do JSON Fonte adaptado de INTRODUÇÃO... (2011). O Código 27 ilustra um arquivo JSON gerado pelo serviço disponível na URL <http://search.yahooapis.com/NewsSearchService/V1/newsSearch?appid=YahooDemo&quer y=tablet&result=3 &language=en&output=json>, o Yahoo gera um arquivo no format JSON com as informações de notícias sobre tablets. {"ResultSet":{"totalResultsAvailable":"3253","totalResultsReturned":10,"firstResultPosition":"1","Result":[{"Ti tle":"4Q Tablet Shipments Double From 3Q; Apple's Lead Declines - Researcher","Summary":"Worldwide tablet computer shipments more than doubled sequentially in the fourth quarter, with Apple Inc.'s (AAPL) iPad the declining market leader, researcher Strategy Analytics estimated Monday.","Url":"http:\/\/www.foxbusiness.com\/markets\/2011\/01\/31\/q-tablet-shipments-double-q-appleslead-declines-researcher\/","ClickUrl":"http:\/\/www.foxbusiness.com\/markets\/2011\/01\/31\/q-tabletshipments-double-q-apples-lead-declines-researcher\/","NewsSource":"FOX Business","NewsSourceUrl":"http:\/\/www.foxbusiness.com ... omitido parte da resposta ... \/","Language":"en","PublishDate":"1296565231","ModificationDate":"1296565646"},{"Title":"5 Ways Google's Honeycomb Tablet OS Could Beat Apple's Mighty iPad","Summary":"We offer five ways Google can smoke the iPad on the feature front with its Honeycomb tablet-centric OS","Url":"http:\/\/www.pcworld.com\/article\/218376\/5_Ways_Googles_Honeycomb_Tablet_Could_Beat_Ap ple_s_Mighty_iPad.html?tk=rss_news","ClickUrl":"http:\/\/www.pcworld.com\/article\/218376\/5_Ways_Googl es_Honeycomb_Tablet_Could_Beat_Apple_s_Mighty_iPad.html?tk=rss_news","NewsSource":"PC World","NewsSourceUrl":"http:\/\/www.pcworld.com\/","Language":"en","PublishDate":"1296581452","Modifi cationDate":"1296581454"}]}} Código 27 – Exemplo de um arquivo no formato JSON Fonte: Autoria própria. O servidor de notícias gerou um ResultSet com três atributos (totalResultsAvailable, totalResultsReturned e firstResultPosition) e um outro atributo (Result) que é um array de 82 objetos, cada elemento do array representando uma notícia incluinto o título, resumo, url, fonte da notícia e linguagem entre outros. Processando este arquivo JSON em uma página HTML adequadamente, é gerada uma página como a ilustrada na Figura 33. Figura 33 – Arquivo JSON processado, com outros widgets acrescentados Fonte: Autoria própria. Os serviços para troca de dados entre aplicações via protocolo http já alcançaram bom nível de maturidade. Hoje, há várias formas de disponibilizar serviços via web, e existem diversas APIs disponíveis para atender as necessidades como mapas, agenda, autenticação de usuários, ou integração com redes sociais. Serviços pagos, públicos, serviços com mais de um plano de licenciamento para atender aos vários tipos de consumidor, hoje já estão prontos para uso. Em meio às tecnologias para intercambio de dados e comunicação entre aplicativos pela web como SOAP, REST, ou WSDL, se destacam as APIs que fornecem dados com simples requisições http diretamente via navegador internet como o JSONP. AJAX trata as requisições assíncronas remotas por meio dos protocolos XMLHttpRequest e XMLHttpResponse, que trafegam dados na forma de texto puro ou 83 arquivos XML. Esses dados são processados pelo programa javascript, que monta no browser cliente seus trechos de html sem o recarregamento da página, o JSONP requisita dados de forma assíncrona, assim como o AJAX, mas não utiliza os protocolo XMLHttp e só trabalha com objetos no formato JSON. JSON é um formato de dados que vem sendo utilizado para transporte de dados entre aplicações web. Ele está ganhando seu espaço por ser leve e de fácil implementação. O processamento dos dados em um objeto JSON requer um parse simples (usando o método eval do javascript) e não é necessário a navegação por DOM entre os nós e atributos de um XML, isto justifica a preferência pelo JSON ao invés de XML para ajax na web (INTRODUÇÃO, 2011). Há uma limitação no uso do protocolo XMLHttpRequest em se tratando de requisições entre diferentes sites (requisições crossdomain), este é modelo de segurança, implementado pelo javascript, chamdo Same Origin Policy, ou Política de Mesma Origem. Este modelo de segurança crossdomain impede que um documento leia ou envie dados para outra origem. Origens diferentes são objetos que estejam em diferentes domínios, diferentes portas ou que utilizem protocolos de comunicação diferentes entre si. Considerando a url: ―http://www.dcvillea.appspot.com/‖, podemos ter requisições que irão ter sucesso ou falhar nas seguintes situações: http://www.dcvillea.appspot.com/diretorio/pagina.html, funciona, porque é uma requisição para o mesmo host, usa o mesmo protocolo, e está dentro do mesmo site. https://www.dcvillea.appspot.com/pagina.html, não funciona, porque os protocolos são diferentes representam (―http‖,‖https‖); http://www.dcvillea.appspot.com:81/pagina.html não funciona, porque as portas são diferentes (―porta 81 e a padrão 80‖); http://www.google.com/pagina.html, também não funciona, porque se tratam de hosts diferentes; JSONP é um pseudo-protocolo que possibilita realizar requisições http e trafegar dados no formato JSON entre documentos de diversas origens. A implementação do JSONP é simples, porém é necessário que o serviço responsável pela entrega dos dados tenha a escolha de entregá-los na estrutura necessária para que eles possam ser processados no cliente. Não há restrições para o transporte de imagens e scripts de outras origens, por meio do atributo src das tags. A técnica implementada no JSONP se aproveita dessa possibilidade para carregar scripts externos conforme a necessidade, manipulando o DOM da página. O que o JSONP faz 84 para funcionar é a inclusão de uma TAG script no header <head> da página HTML. Essa tag script recebe um atributo src indicando o site externo, que responde pelos objetos no formato JSON, esse resultado é parseado e fica disponível para processamento via JavaScript. Padding ou prefix é o nome passado na requisição ao serviço, para que na resposta o método envolva as informações no formato JSON após a resposta (INTRODUÇÃO..., 2011). <head> <script type="text/javascript" src="http://domain1.com/getjson?jsonp=parseResponse" target="_blank"> </script> … Código 28 – Exemplo de requisição feita a um servidor JSONP Fonte: INTRODUÇÃO... (2011). A palavra parseResponse será a o nome da função que gerará o json, como um callback. O resultado será algo parecido com Código 28: parseResponse({―name‖:‖dvillela‖, ‖idade‖:45, esportes:[―corrida‖,‖tenis‖,‖natacao‖]}) Código 29 – Resultado do parseResponse Fonte: INTRODUÇÃO... (2011). 3.10 ADICIONANDO API Há muitas bibliotecas JavaScript e serviços web que podem ser incluídos em aplicações, adicionando-as atravez de JSNI, assim como códigos GWT (que após compilados são JavaScrits). Na Figura 34, por exemplo, um dos requisitos da aplicação no estudo de caso será informar ao usuário onde fica a UTFPR campus Cornélio Procópio e como chegar ao local. A Google disponibiliza a API para este serviço, bastando fazer a devida chamada ao serviço. 85 Figura 34 – UTFPR no Google Maps Fonte: Autoria própria. O Código 30 lista o JavaScript para acessar o serviço Google Maps passando os parâmetros de latitude e longitude da UTFPR campus Cornélio Procópio, neste caso o mapa ficará confinado em um frame com 300 X 279 pixel. <!-- Google Maps Element Code - UTFPR --> <iframe frameborder=0 marginwidth=0 marginheight=0 border=0 style="border: 0; margin: 0; width: 300px; height: 279px;"src="http://www.google.com/uds/modules/elements/ mapselement/iframe.html ? maptype=terrain &latlng=-23.186483809925903%2C-50.657057762145996 &mlatlng=-23.18587%2C-50.655609 &maddress1= Avenida%20Alberto%20Carazzai%2C%201640%20%20Centro&maddress2=Corn%C3%A9lio%20Proc%C3%B3pio%20-%20PR%2C%2086300000%2C%20Brazil &zoom=15 &mtitle=UTFPR-Universidade%20Tecnol%C3%B3gica%20Federal%20do%20Paran%C3%A1%20 Campus%20Corn%C3%A9lio%20Proc%C3%B3pio&element=true" scrolling="no" allowtransparency="true"> </iframe> Código 30 – Código JavaScript para acessar o serviço Google Maps Fonte: Autoria própria. 86 Outro exemplo é mostrado na Figura 35, onde será desenvolvido uma aplicação GTW que simulará a cotação de ações. Figura 35 – Cotação de ações no <div id=‖stokList‖> Fonte: Autoria própria. <html> <head> <title>Domingos de Carvalho Villela Júnior - Tecnologia Java - UTFPR</title> <!—Chamada da aplicação GWT cotacaoacoes --> <script type="text/javascript" language="javascript" src="cotacaoacoes/cotacaoacoes.nocache.js"></script> </head> <body> … <div id="stockList"></div> … </body> Código 31 – Código JavaScript para acessar o serviço catacaoacoes Fonte: Autoria própria. Com estes recursos e conceitos, o estudo de caso implantará no Google Application Engine, uma pequena aplicação demonstrando como se pode desenvolver um ERP RIA com o GWT 2. 87 4 ESTUDO DE CASO Este estudo de caso foi desenvolvido utilizando-se do conceito de Mashup. Mashup é uma técnica utilizada em desenvolvimento Web onde uma aplicação usa e combinam dados e serviços de duas ou mais fontes para criar um novo serviço. Este novo serviço tem como requisitos funcionais uma página Web em que um usuário de tablet tenha disponível na nuvem os seguintes serviços: Cotação on-line de ações na Bovespa. Notícias da Bloomberg Notícias da Petrobras Calendário e agenda Mapas E-mail Editor de textos Planilha eletrônica Software para apresentações de slides Software para desenho Tradutor entre várias línguas Teclado virtual O diagrama de classes do projeto feito em UML para atender o requisito de cotação on-line de ações na Bovespa é mostrado na Figura 36. Este requisito funcional foi implementado com o uso do GWT, simulando valores aleatórios para as ações escolhidas pelo usuário de segundo em segundo, e os demais serviços foram consumidos da Google. Este diagrama de classes mostra as classes do ―google.gwt.user.client.ui― utilizadas, e a classe CotacaoAcoes. Estes componentes gráficos serão injetados no código HTML através de JavaScript em <div id="stockAdd"></div> e <div id="stockList"></div>. No Apêndice A e B estão as listagens destes códigos e em destaque esta injeção dos dois VertivalPanel com seus componentes visuais na tag <div/> no HTML da aplicação. Depois de testada a aplicação ela foi hospedada no Google App Engine, onde pode ser acessada pela url: < http://www.tccposjavautfpr.appspot.com/ >, a Figura 37 mostra a aplicação sendo acessada pelo navegador Google Chrome. 88 Figura 36 – Diagrama de classes do projeto simulação de cotação de ações Fonte: Autoria própria. Figura 37 – Estudo de caso implantado no app engine Fonte: Autoria própria. 89 5 CONCLUSÃO No Quadro 6 estão algumas manchetes relacionadas à computação em nuvens em sites especializados em TI. Data Manchete Fonte 16/04/2010 Windows Azure é Lançado no Brasil Microsoft 25/03/2011 Sonda IT se une à VCE para explorar mercado de cloud no país. Computer World 29/03/2011 Cisco compra empresa de software para cloud computing TI inside 29/03/2011 Mercado de cloud computing deve crescer 60% ao ano no país. TI inside 29/03/2011 IBM reforça estratégia de outsoursing Segundo a organização, o modelo poderá ainda estabelecer bases para o desenvolvimento de soluções avançadas de cloud computing. Computer World 31/03/2011 HP aposta em cloud computing para impulsionar crescimento no Brasil HP Brasil Mar./Abr. 2011 Plug into the cloud Artigo relatando cases de uso da solução de cloud da Oracle Oracle Magazine 04/04/2011 O cloud computing chaga aos bancos TI inside 04/04/2011 IEEE procura interoperacionalidade no cloud computing Computer World 05/04/2011 Conferência Gartner Data Center destaca ―Cloud‖ como alternativa para infraestrutura de TI Gartner Research 06/04/2011 Cloud deve crescer 7 vezes até 2014, diz IDC INFO On-line 06/04/2011 Operadoras estão apenas no início dos serviços em cloud Teletime 08/04/2011 Dell investe milhões de dólares para abrir 10 centros de armazenamento de dados. ―O investimento será feito para expandir o apoio ao cliente e melhorar a aposta no cloud computing‖ Negócios on-line 12/04/2011 Unisys lança guia para projetos cloud Unisys Corporation 15/04/2011 Dell pretende investir US$ 1 bi. Foco é Cloud Computing itWeb 16/05/2011 Google apresenta o Chromebook versão radical do conceito de netbook Jornal O Estado de S. Paulo 15/06/2011 Vida digial - A nuvem é de tijolos - iCloud Revista VEJA, edição 2221 Quadro 6 – Manchetes sobre computação em nuvens Fonte: Adaptado de Ramos (2011). Pelas manchetes mostradas no Quadro 6, conclui-se que a computação em nuvem com a venda de serviços sob demanda já é uma realidade, todas as grandes empresas de TI estão correndo atrás deste mercado, e os profissionais de desenvolvimento de software também devem se adaptar a este paradigma. Este trabalho foi feito no momento em que está ocorrendo esta transição, e espera ter contribuído para explorar esta possibilidade de desenvolvimento em cloud com as ferramentas da Google, que foi junto com a Amazon uma das primeiras empresas a investir neste conceito. 90 A Google está na frente de seus concorrentes, pois começou a investir em cloud computing a anos atrás, hoje com conta com Chrome OS, Android 3.0, Google Web Toolkit 2.1, Google App Engine, e seus data centers em terra e em alto mar. Tem mostrado que é uma empresa confiável e que seus clientes podem entregar os dados e serviços de processamento de aos seus cuidados. Na Figura 38 é mostrado um tablet da Motorola com Android 3.0, um Chromebook com Chrome OS e um smartfone da Motorola com Android todos prontos para operarem em computação em nuvens como propõe este trabalho. Figura 38 – Equipamentos com software Android e Chrome OS Fonte: Autoria própria. Na Figura 39 são mostrados os prós e contras a tecnologia de computação em nuvem mais comum na literatura, e a projeção de seu crescimento: Prós: alta escalabilidade e baixo custo, muitas opções de escolha e agilidade, mudanças e gerenciamento transparentes, estar em cloud e sempre estar sob arquitetura de última geração. Contras: menor segurança, menor nível de controle, menor confiabilidade, e imposição tecnológica (de API, por exemplo). 91 Figura 39 – Prós, contras e crescimento da computação em nuvens Fonte: Adaptado de Vela (2011). Com o atual preço dos servidores, custos da conta de TI que uma empresa possui como manutenção do hardware, banco de dados, redes, técnicos especializados em TI, problemas de disponibilidade 24 x 7, segurança, resfriamento dos equipamentos de processamento de dados, backup´s e no-breaks, o desenvolvimento em cloud é uma opção que deve ser levada em consideração. Além do valor para uma hospedagem em cloud completa ser baixo, possuir um banco de dados escalado e funcionando juntamente com a aplicação no modelo 24 x 7, mostra que desenvolver em cloud é a nova forma de desenvolver software e que ganha espaço a todo o tempo. Futuramente estará aos redores de todo o mercado de trabalho e de todas as linguagens de programação, a nuvem está em formação há anos e já mostrou ser a inovação que vai definir o mundo digital nesta década. Finalmente, a Figura 39 mostra a projeção de crescimento da computação em nuvem e que o maior crescimento ocorrerá nos padrões para desenvolvimento de software que será ditado pelas empresas que dominarem esta tecnologia, área que abrirá novos caminhos para futuras pesquisas. 92 REFERENCIAS BILLING and Budgeting Resources. Disponível em: <http://code.google.com/appengine/ docs/billing.html>. Acesso em: 20 jan. 2011. BORGES, Alexander. JSONP e o “Ajax Crossdomain”. 14 abr. 2010. Disponível em: <http://afronteirafinal.com/jsonp-e-o-ajax-crossdomain/>. Acesso em: 01 fev. 2011. CAMILO, Lucio. Introdução ao MVP. Jornal Java, 12 dez. 2010. Disponível em: <http://www.jornaljava.com/2010/12/introducao-ao-mvp >. Acesso em: 26 jan. 2011. CARR, Nicholas. Adoção da nuvem depende de segurança, diz Carr. Disponível em: <http://info.abril.com.br/noticias/corporate/adocao-da-nuvem-depende-de-seguranca-diz-carr01122010-6.shl>. Acesso em: 02 dez. 2010. CHONG, Frederick; CARRARO, Gianpaolo. Architecture Strategies for Catching the Long Tail. Microsoft Corporation. abr. 2006. Disponível em:<http://msdn.microsoft.com/enus/library/aa479069.aspx>. Acesso em: 13 jan. 2011. DATA NUCLEUS. Disponível em:<http://www.datanucleus.org/>. Acesso em: 18 jan. 2011. DATE Picker. Disponível em: <http://gwt.google.com/samples/Showcase/Showcase.html#! CwDatePicker>. Acesso em: 20 jan. 2011. DEVELOPER´S Guide. Disponível em: <http://code.google.com/webtoolkit/doc/latest/Dev Guide.html>. Acesso em: 20 jan. 2011. FOSTER, Ian et al. Cloud Computing and Grid Computing 360-Degree Compared. Chicago: Department of Computer Science, University of Chicago, 2008. GOOGLE App Engine. Disponível em: <http://code.google.com/appengine/>. Acesso em: 06 dez. 2010. GOOGLE Data Center revelado ao mundo. 09 abril 2009. Disponível em <http://tek.online.pt/ google-data-center-revelado-ao-mundo/>. Acesso em: 19 jan. 2011. GOOGLE I/O 2009 – Best Practices for Architeting GWT App. Google Developers, 01 jun. 2009. Disponível em: <http://www.youtube.com/watch?v=PDuhR18-EdM>. Acesso em: 20 jan. 2011. GOOGLE trends. Disponível em: <http://www.google.com/trends>. Acesso em: 05 jun. 2011. GOOGLE Web Tool Kit. Disponível em: <http://code.google.com/intl/pt-BR/webtoolkit/>. Acesso em: 24 jan. 2011. 93 GOOGLE´S Periodic Table of APIs. 27 jan. 2011. Disponível em: <http://www.browsermedia.co.uk/2011/01/27/googles-periodic-table-of-apis/>. Acesso em: 27 jan. 2011. HODGSON, Matthew. Beyond Web 2.0. 07 mar. 2008. Disponível em: <http://www.theappgap.com/beyond-web-20.html>. Acesso em: 19 jan. 2001. HTML/Dhtml/Xhtml. Disponível em: <http://www.miguel.ms/tecnologias/web/ htmldhtmlxhtml>. Acesso em: 20 jan. 2011. iGOOGLE. Disponível em: <http://www.google.com/ig>. Acesso em: 06 jun. 2011. INTRODUÇÃO ao JSON. Disponível em <http://www.json.org/>. Acesso em: 31 jan. 2011. JAVA Data Objects. About Apache JDO. Disponível em: <http://db.apache.org/jdo/>. Acesso em: 18 jan. 2011. KEREKI, Federico. Essential GWT Building for the Web with Google Web Toolkit 2. Boston: Addison Wesley, 2010. KOCH, Peter-Paul. The Document Object Model: an Introduction. 14 maio 2001. Disponível em: <http://www.digital-web.com/articles/the_document_object_model/>. Acesso em: 18 jan. 2011. LAST Call: W3C Invites Broad Review of HTML5 and Five Related Specifications. 25 maio 2011. Disponível em: <http://www.w3.org/>. Acesso em: 28 maio 2011. LIMA, Fernando Cesar. Tópicos Avançados em Tecnologia Java – AJAX. Cornélio Procópio: UTFPR, 2010. (apostila). MILLER, Rich. Lonestar 4 Supercomputer Will Boost Research. 20 abr. 2011. Disponível em: <http://www.datacenterknowledge.com/archives/2011/04/20/lonestar-4-supercomputerwill-boost-research/>. Acesso em: 07 jun. 2011. MIRANDA, Fábio. Novidades no GWT 2.1! Novos Widgets e o Framework MVP Oficial da Google. Revista MundoJ, ed. 45, p. 14-24, jan. 2011. MOREIRA, Denis F. Entenda o que é Web 2.0. 19 nov. 2009. Disponível em: <http://fontededados.com/entenda-web-2-0/>. Acesso em: 18 jan. 2011. MÜLLER, Nicolas. O que é cloaking SEO? Disponível em: <http://www.oficinadanet.com.br/ artigo/otimizacao__seo/o-que-e-cloaking-seo>. Acesso em: 13 jan. 2011. MÜLLER, Victor. Desenvolvimento de aplicações sob o paradigma da computação em nuvem com ferramentas Google. Florianópolis: UFSC, 2010. 94 PEREIRA, Felipe Alves Lourenço. Serialização e Desserialização de Objetos em Java. 19 dez. 2010. Disponível em: <http://felipealvesgnu.wordpress.com/2010/12/19/serializacao-edesserializacao-de-objetos/>. Acesso em: 20 jan. 2011. PORTAL GWT. Disponível em: <http://portalgwt.com/>. Acesso em: 07 mar. 2011. RAMOS, José Yoshiriro Ajisaka. Cloud Computing. Revista MundoJ, Ed. 47, p. 6-11, jun. 2011. RMI-IIPO. Disponível em: <http://help.sap.com/saphelp_nw04/helpdata/en/97/71c 99065089b4c9542e0b105f1fcce/content.htm>. Acesso em: 20 jan. 2011. RUN your web application on Googles´s infraestruture. Disponívle em: <https://www.google.com/accounts/ServiceLogin?service=ah&passive=true&continue=https: //appengine.google.com/_ah/conflogin%3Fcontinue%3Dhttps://appengine.google.com/&ltmp l=ae>. Acesso em: 20 jan. 2011. SCHULLER, Sinclair. Demystifying The Cloud: Where Do SaaS, PaaS and Other Acronyms Fit In? 01 dez. 2008. Disponível em: <http://www.saasblogs.com/2008/12/01/ demystifying-the-cloud-where-do-saas-paas-and-other-acronyms-fit-in/>. Acesso em: 13 jan. 2011. SMART GWT Enterprise Edition. Disponível em: <http://www.smartclient.com/product/ sgwtOverview.jsp>. Acesso em: 20 jan. 2011. USO do armazenamento de dados com JDO. Disponível em <http://code.google.com/intl/ptBR/appengine/docs/java/gettingstarted/usingdatastore.html>. Acesso em: 18 jan. 2011. VELA, Lorie. Are companies concerned about cloud computing security? 20 jan. 2011. Disponível em <http://www.collaborationideas.com/2011/01/are-companies-managingproperly-cloud-computing-security/#more-1365>. Acesso em: 29 maio. 2011. WEISER, Mark. Ubiquitous Computing. 17 mar. 1996. Disponível em: <http://sandbox.xerox.com/hypertext/weiser/UbiHome.html>. Acesso em: 18 jan. 2011. WHAT is Cloud Computing? University of Southampton. Disponível em: <http://tecires.ecs.soton.ac.uk/cloud_computing.php>. Acesso em: 06 jun. 2011. WIDGET Gallery. Disponível em: <http://code.google.com/webtoolkit/doc/1.6/RefWidget Gallery.html>. Acesso em: 20 jan. 2011. 95 APÊNDICES 96 APÊNDICE A – class CotacaoAcoes package com.dvillela.gwt.cotacaoacoes.client; import java.util.ArrayList; import java.util.Date; import import import import import import import import import import import import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.event.dom.client.ClickEvent; com.google.gwt.event.dom.client.ClickHandler; com.google.gwt.event.dom.client.KeyCodes; com.google.gwt.event.dom.client.KeyPressEvent; com.google.gwt.event.dom.client.KeyPressHandler; com.google.gwt.i18n.client.DateTimeFormat; com.google.gwt.i18n.client.NumberFormat; com.google.gwt.user.client.Random; com.google.gwt.user.client.Timer; com.google.gwt.user.client.Window; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.FlexTable; com.google.gwt.user.client.ui.HorizontalPanel; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.RootPanel; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel; public class CotacaoAcoes implements EntryPoint { private private private private private private private private private static final int REFRESH_INTERVAL = 5000; VerticalPanel mainPanel = new VerticalPanel(); VerticalPanel mainPanelAdd = new VerticalPanel(); FlexTable stocksFlexTable = new FlexTable(); HorizontalPanel addPanel = new HorizontalPanel(); TextBox newSymbolTextBox = new TextBox(); Button addStockButton = new Button("Adicionar"); Label lastUpdatedLabel = new Label(); ArrayList<String> stocks = new ArrayList<String>(); /** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "C\u00f3digo"); stocksFlexTable.setText(0, 1, "Pre\u00e7o"); stocksFlexTable.setText(0, 2, "Varia\u00e7\u00e3o"); stocksFlexTable.setText(0, 3, "Remove"); // Add styles to elements in the stock list table. stocksFlexTable.setCellPadding(6); stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); addPanel.addStyleName("addPanel"); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanelAdd.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); RootPanel.get("stockAdd").add(mainPanelAdd); 97 // Move cursor focus to the input box. newSymbolTextBox.setFocus(true); // Listen for mouse events on the Add button. addStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { addStock(); } }); // Listen for keyboard events in the input box. newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() { public void onKeyPress(KeyPressEvent event) { if (event.getCharCode() == KeyCodes.KEY_ENTER) { addStock(); } } }); // Setup timer to refresh list automatically. Timer refreshTimer = new Timer() { @Override public void run() { refreshWatchList(); } }; refreshTimer.scheduleRepeating(REFRESH_INTERVAL); } /** * Add stock to FlexTable. Executed when the user clicks the addStockButton * or presses enter in the newSymbolTextBox. */ private void addStock() { // TODO Auto-generated method stub final String symbol = newSymbolTextBox.getText().toUpperCase().trim(); newSymbolTextBox.setFocus(true); // Stock code must be between 1 and 10 chars that are numbers, letters, // or dots. if (!symbol.matches("^[0-9A-Z\\.]{1,10}$")) { Window.alert("'" + symbol + "' is not a valid symbol."); newSymbolTextBox.selectAll(); return; } newSymbolTextBox.setText(""); // TODO Don't add the stock if it's already in the table. if (stocks.contains(symbol)) return; // TODO Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.setWidget(row, 2, new Label()); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn"); // TODO Add a button to remove this stock from the table. Button removeStockButton = new Button("remove"); removeStockButton.addStyleDependentName("remove"); removeStockButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { int removedIndex = stocks.indexOf(symbol); stocks.remove(removedIndex); stocksFlexTable.removeRow(removedIndex + 1); } }); stocksFlexTable.setWidget(row, 3, removeStockButton); 98 // Get the stock price. refreshWatchList(); // TODO Get the stock price. } /** * Generate random stock prices. */ private void refreshWatchList() { final double MAX_PRICE = 100.0; // $100.00 final double MAX_PRICE_CHANGE = 0.02; // +/- 2% StockPrice[] prices = new StockPrice[stocks.size()]; for (int i = 0; i < stocks.size(); i++) { double price = Random.nextDouble() * MAX_PRICE; double change = price * MAX_PRICE_CHANGE * (Random.nextDouble() * 2.0 - 1.0); prices[i] = new StockPrice(stocks.get(i), price, change); } updateTable(prices); } /** * Update the Price and Change fields all the rows in the stock table. * * @param prices * Stock data for all rows. */ @SuppressWarnings("deprecation") private void updateTable(StockPrice[] prices) { for (int i = 0; i < prices.length; i++) { updateTable(prices[i]); } // Display timestamp showing last refresh. lastUpdatedLabel.setText("\u00daltima atualiza\u00e7\u00e3o : " + DateTimeFormat.getMediumDateTimeFormat().format(new Date())); } /** * Update a single row in the stock table. * * @param price * Stock data for a single row. */ private void updateTable(StockPrice price) { // Make sure the stock is still in the stock table. if (!stocks.contains(price.getSymbol())) { return; } int row = stocks.indexOf(price.getSymbol()) + 1; // Format the data in the Price and Change fields. String priceText = NumberFormat.getFormat("#,##0.00").format( price.getPrice()); NumberFormat changeFormat = NumberFormat .getFormat("+#,##0.00;-#,##0.00"); String changeText = changeFormat.format(price.getChange()); String changePercentText = changeFormat .format(price.getChangePercent()); // Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); Label changeWidget = (Label) stocksFlexTable.getWidget(row, 2); changeWidget.setText(changeText + " (" + changePercentText + "%)"); // Change the color of text in the Change field based on its value. String changeStyleName = "noChange"; if (price.getChangePercent() < -0.1f) { changeStyleName = "negativeChange"; 99 } else if (price.getChangePercent() > 0.1f) { changeStyleName = "positiveChange"; } changeWidget.setStyleName(changeStyleName); } } 100 APÊNDICE B – Página CotacaoAcoes.html <!-- ---------------------------------------------------- --> <!-- Desenvolvido por Domingos de Carvalho Villela Júnior --> <!-Google Web ToolKit e Google Application Engine --> <!-Assis - SP - Brazil - Janeiro/2011 --> <!-Estudo de caso, monografia Pós Java - UTFPR --> <!-Contato: [email protected] --> <!-- ---------------------------------------------------- --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> <link type="text/css" rel="stylesheet" href="CotacaoAcoes.css"> <title>Domingos de Carvalho Villela Júnior - Tecnologia Java UTFPR</title> <script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript"> google.load("elements", "1", { packages : "keyboard" }); var kbd; function onLoad() { kbd = new google.elements.keyboard.Keyboard( [ google.elements.keyboard.LayoutCode.PORTUGUESE ]); } google.setOnLoadCallback(onLoad); </script> <script type="text/javascript" language="javascript" src="cotacaoacoes/cotacaoacoes.nocache.js"></script> </head> <body style="background-image: url(images/Fundo.gif);"> <!-- RECOMMENDED if your web app will not function without JavaScript enabled --> <noscript> <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; border: 1px solid red; padding: 4px; font-family: sans-serif"> Your web browser must have JavaScript enabled in order for this application to display correctly.</div> </noscript> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position: absolute; width: 0; height: 0; border: 0"></iframe> <table border="0" bordercolor="000000" width="1230" align="center" bgcolor="#FFFFFF"> <tr> <td bordercolor="FFFFFF"> <table border="2" bordercolor="#2062B8" width="100%" align="center"> <tr align="center"> <td bordercolor="#FFFFFF" align="left" width="20%"><a href="http://code.google.com/intl/ptBR/webtoolkit/overview.html"> <img alt="Projeto GWT 2.1" src="images/TecnoProjWeb.jpg" width="260" border="0"></a></td> <td bordercolor="#2062B8" bgcolor="#B4CDCD"><font face="Times New Roman" size="+4" color="#000000">Computação em Nuvem:</font><br> <font face="Times New Roman" size="+1" color="#000000"> Desenvolvimento de Aplicações Empresariais Ricas na Internet, na Arquitetura Java,<br> 101 Google Web Toolkit e Google Application Engine.</font> <hr width=80% " size="2" noshade color="#2062B8" /> <font face="Times New Roman" size="+1" color="#000000">Estudo de caso - UTFPR / Cornélio Procópio - 2011<br> <a href="docs/MonografiaGWT.pdf"> Monografia apresentada no curso de Especialização em Tecnologia Java</a><br> <a href="mailto:[email protected]">Domingos de Carvalho Villela Júnior</a></font></td> </tr> </table> <table border="1" bordercolor="#2062B8" width="100%" align="center"> <tr> <td align="left" bordercolor="FFFFFF" width="20%"><a href="http://www.bmfbovespa.com.br/home.aspx?idioma=ptbr"><img alt="Bovespa" src="images/bmf.jpg" width="360" border="0"></a></td> <td bgcolor="#E8E8E8" bordercolor="000000" align="center" width="35%"><font face="Times New Roman" size="+3" color="#000000">Cotação de Ações</font><br> <font face="Times New Roman" size="+1" color="#000000">Entre com o código das ações para simulação:</font> <div id="stockAdd"></div> <script src="http://www.gmodules.com/ig/ifr?url=http://hosting.gmodules.com/ig/gadgets/file/ 115450510581205387922/LaunchGoogleService1.xml&amp;synd=open&amp;w=340&amp;h=65&amp;title=&amp ;border=%23ffffff%7C0px%2C1px+solid+%2382CAFA%7C0px%2C2px+solid+%23BDEDFF%7C0px%2C3px+solid+%2 3E0FFFF&amp;output=js"></script></td> <td align="right" bordercolor="#2062B8" bgcolor="#E8E8E8"> <div id="stockList"></div> </td> </tr> </table> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position: absolute; width: 0; height: 0; border: 0"></iframe> <table border="2" bordercolor="#2062B8" width="100%" align="center"> <tr align="center"> <td bordercolor="000000" bgcolor="#B4CDCD"><iframe frameborder=0 marginwidth=0 marginheight=0 border=0 style="border: 0; margin: 0; width: 300px; height: 300px;" src="http://www.google.com/calendar/embed?showTitle=0&showTabs=0&showPrint=0&showCal endars=0&wkst=1&element=true&src=usa__en%40holiday.calendar.google.com" scrolling="no" allowtransparency="true"></iframe></td> <td bordercolor="000000" bgcolor="#B4CDCD"><b>Notícias Bloomberg</b><IFRAME style="BORDER-RIGHT-WIDTH: 0px; MARGIN: 0px; WIDTH: 300px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; HEIGHT: 254px; BORDER-LEFT-WIDTH: 0px" id=youtube_news_element_preview marginHeight=0 border=0 src="http://www.google.com/uds/modules/elements/videonews/iframe.html?channel=Bloomb erg" frameBorder=0 allowTransparency marginWidth=0 scrolling=no></IFRAME> Busca on-line assincrona</td> <td bordercolor="000000" bgcolor="#B4CDCD"><b>Negócios e Petrobras</b> <iframe frameborder=0 marginwidth=0 marginheight=0 border=0 style="border: 0; margin: 0; width: 300px; height: 258px;" src="http://www.google.com/uds/modules/elements/newsshow/iframe.html?rsz=large&forma t=300x250&ned=pt-BR_br&topic=b&q=petrobras&element=true" scrolling="no" allowtransparency="true"></iframe> Busca on-line assincrona</td> <td bordercolor="000000" bgcolor="#B4CDCD"><b>UTFPR/Cornélio Procópio - Brasil</b><br> <!-- Google Maps Element Code - UTFPR --> <iframe frameborder=0 marginwidth=0 marginheight=0 border=0 style="border: 0; margin: 0; width: 300px; height: 279px;" 102 src="http://www.google.com/uds/modules/elements/mapselement/iframe.html?maptype=terrain&latlng =-23.186483809925903%2C-50.657057762145996&mlatlng=-23.18587%2C50.655609&maddress1=Avenida%20Alberto%20Carazzai%2C%201640%20%20Centro&maddress2=Corn%C3%A9lio%20Proc%C3%B3pio%20-%20PR%2C%2086300000%2C%20Brazil&zoom=15&mtitle=UTFPRUniversidade%20Tecnol%C3%B3gica%20Federal%20do%20Paran%C3%A1%20Campus%20Corn%C3%A9lio%20Proc%C 3%B3pio&element=true" scrolling="no" allowtransparency="true"></iframe></td> </tr> </table> <table align="center" border="1" width="100%" bordercolor="#2062B8"> <tr> <td width="25%" bordercolor="#FFFFFF"><a href="http://code.google.com/intl/ptBR/appengine/docs/"> <img border="0" src="http://code.google.com/appengine/images/appenginenoborder-120x30.gif" alt="Powered by Google App Engine" /></a></td> <td align="right" bordercolor="#FFFFFF"><font face="Times New Roman"><a href="mailto:[email protected]">[email protected]</a> &#187; Domingos de Carvalho Villela Júnior, especialização Java &#187; UTFPR/Cornélio Procópio/PR/Brazil &#187; Janeiro/2011</font></td> </tr> </table> </td> </tr> </table> </body> </html>