16
: : www.mundoj.com.br : : Uma aplicação completa passo-a-passo integrando Android + Java EE + Java SE Java de ponta a ponta (6 anos depois) Cristine Tellier ([email protected]): SCJP e SCWCD, trabalha há oito anos com desenvolvimento de projetos Java SE e Java EE para o mercado financeiro. Atualmente, é engenheira de Soluções na BV Sistemas, empresa de tecnologia da holding Votorantim Finanças. Odair Bonin ([email protected]): É formado em Ciência da Computação e trabalha com Java há 9 anos. SCJP, participou de grandes projetos em fábricas de softwares e projetos para mobilidade. Atualmente é analista de engenharia de software da BV Sistemas, empresa de tecnologia da holding Votorantim Finanças. Mais uma vez provamos que o slogan mais famoso do Java é verdadeiro: “Java is Everywhere”. Neste artigo apresentamos, de forma didática, uma aplicação completa passando por edições como Java EE e Java SE. Para o módulo móbile, escolhemos Android. Para integração entre os módulos, escolhemos utilizar webservice RESTful e este por sua vez acessa o EJB central, que contém as operações e regras de negócio da empresa. Além de um módulo central e um móbile, a aplicação é composta de mais dois módulos web e desktop. Este artigo mostrará como essas tecnologias são utilizadas em conjunto para a criação de uma única aplicação. m meados de 2005, a edição número 12 da revista MundoJ nos trouxe artigos mais do que especiais. Sob o título de capa “Java de Ponta a Ponta”, a edição conta com artigos sobre as novidades do Java, novidades da modelagem ágil entre outros temas. A própria edição traz um artigo sobre o 10º aniversário do Java, e uma linha do tempo desde o início até meados de 2005 foi traçada e comentada sobre as novidades que aconteciam com Java. “Revisão do esboço inicial da plataforma J2EE 5.0” e “Disponibilização do Netbeans 4.1” estavam entre as novidades. A versão Java 5.0 (Tiger) tinha 6 meses de vida. Porém, a matéria principal de capa mostrava o desenvolvimento de um sistema que usava em conjunto as plataformas J2ME, J2EE e J2SE. Para mostrar a integração entre as plataformas, foi desenvolvido o sistema Pizza Delivery, que permite ao cliente fazer um pedido de pizza pela internet através de um módulo web. Este módulo web, desenvolvido em JSP sem frameworks adicionais, acessa um mó- dulo central para obter o cardápio disponível. O módulo central 8

: - Faculdades Integradas do Vale do Ivaí · o título de capa “Java de Ponta a Ponta”, a edição conta com artigos sobre as novidades do Java, novidades da modelagem ... um

Embed Size (px)

Citation preview

: : www.mundoj.com.br : :

Uma aplicação completa passo-a-passo integrando Android + Java EE + Java SE

Java de ponta a ponta (6 anos depois)

Cristine Tellier

([email protected]): SCJP e SCWCD, trabalha há oito anos com desenvolvimento de projetos Java SE e Java EE para o mercado financeiro. Atualmente, é engenheira de Soluções na BV Sistemas, empresa de tecnologia da holding Votorantim Finanças.

Odair Bonin

([email protected]): É formado em Ciência da Computação e trabalha com Java há 9 anos. SCJP, participou de grandes projetos em fábricas de softwares e projetos para mobilidade. Atualmente é analista de engenharia de software da BV Sistemas, empresa de tecnologia da holding Votorantim Finanças.

Mais uma vez provamos que o slogan mais famoso do Java é verdadeiro: “Java is Everywhere”. Neste artigo apresentamos, de forma didática, uma aplicação completa passando por edições como Java EE e Java SE. Para o módulo móbile, escolhemos Android. Para integração entre os módulos, escolhemos utilizar webservice RESTful e este por sua vez acessa o EJB central, que contém as operações e regras de negócio da empresa. Além de um módulo central e um móbile, a aplicação é composta de mais dois módulos web e desktop. Este artigo mostrará como essas tecnologias são utilizadas em conjunto para a criação de uma única aplicação.

m meados de 2005, a edição número 12 da revista MundoJ nos trouxe artigos mais do que especiais. Sob o título de capa “Java de Ponta a Ponta”, a edição conta

com artigos sobre as novidades do Java, novidades da modelagem ágil entre outros temas. A própria edição traz um artigo sobre o 10º aniversário do Java, e uma linha do tempo desde o início até meados de 2005 foi traçada e comentada sobre as novidades que aconteciam com Java. “Revisão do esboço inicial da plataforma J2EE 5.0” e “Disponibilização do Netbeans 4.1” estavam entre as novidades. A versão Java 5.0 (Tiger) tinha 6 meses de vida. Porém, a matéria principal de capa mostrava o desenvolvimento de um sistema que usava em conjunto as plataformas J2ME, J2EE e J2SE.

Para mostrar a integração entre as plataformas, foi desenvolvido o sistema Pizza Delivery, que permite ao cliente fazer um pedido de pizza pela internet através de um módulo web. Este módulo web, desenvolvido em JSP sem frameworks adicionais, acessa um mó-dulo central para obter o cardápio disponível. O módulo central

8

9

concentra todas as regras de negócio e operações disponíveis do sistema, e foi desenvolvido utilizando EJB 2.1 e Entity Beans CMP para a camada de persistência. O container J2EE escolhido foi o JBoss 4.0.2. Após fechar o pedido de uma pizza, ele é direcionado a um entregador através do módulo gerenciador, um módulo desktop desenvolvido em Swing. O entregador também possui acesso ao sistema através de um módulo instalado em seu celular. Desenvolvido com J2ME, este permite ao entregador visualizar informações dos pedidos como o endereço do cliente, e também marcar que a entrega foi efetuada. Desta forma, um possível relató-rio de entregas com informações detalhadas poderia ser extraído.

O objetivo deste artigo é explicar passo-a-passo o desenvolvimen-to de um sistema completo incluindo módulos das plataformas Java EE, Java SE e Android. Demonstraremos de forma didática a integração entre as plataformas, combinando recursos atuais das versões do Java e comparando ao artigo escrito em 2005. Para os desenvolvedores iniciantes, o artigo permitirá uma visão ampla do que atualmente é tido como referência nas plataformas abordadas. Veremos como podemos realizar esta integração.

Evolução do Java de 2005 até 2011

Em 2005, a Sun Microsystems, até então detentora da platafor-ma Java, investia pesado em todas as suas edições (J2SE, J2ME e J2EE). O lançamento da versão J2SE 5.0 (Tiger) acabava de ocorrer, e quase que ao mesmo tempo a versão 6.0 (Mustang) era disponibilizada para o desenvolvimento colaborativo no site java.net. O esboço inicial do J2EE 5.0 estava sendo revisado, enquanto que a IDE Netbeans lançava a sua versão 4.1.

A edição J2ME estava em destaque, sendo adotado por diversos segmentos da indústria como empresas de monitores cardíacos, monitoramento de poços de petróleo e gás, e se entendia à se-gurança nacional americana, com o seu sofisticado sistema de monitoração e alerta de emergência contra ataques químicos e biológicos de alto risco.

A TV digital estava sendo idealizada como sendo uma central multimídia, pelo consórcio DVB (Digital Video Broadcasting) que em conjunto com a Sun Microsystems estava especificando a plataforma MHP (Multimedia Home Platform), uma plataforma baseada na tecnologia Java que seria implementada em receptores de TV Digital.

Passados 6 anos, muita coisa mudou, mas sem perder a essência. A mais significante mudança foi a passagem do Java para as mãos da Oracle, que em meados de 2009 comprou a Sun Microsystems por US$ 7,9 bilhões, realizando uma transação de grande impacto no mercado.

Naquele momento, surgiram muitas perguntas a serem respondi-das, como: Java deixará de ser uma plataforma livre? Oracle não investirá em Java na mesma proporção que a Sun, deixando de realizar o JavaOne? Enfim, todas elas foram e ainda estão sendo respondidas ao longo do tempo.

Hoje, a Oracle estampa em seu site sua visão sobre o Java, dita por Steven Harris, vice-presidente Senior Oracle: “Java is critical for our success”, sendo comprovada por seu grande investimento na plata-forma. Uma das novidades da Oracle foi a primeira realização no Bra-sil do maior evento Java mundial, o JavaOne, em dezembro de 2010.

Mas nem toda a mudança feita pela Oracle foi bem-vinda pela comunidade Java. Em relação às certificações, por exemplo, a Oracle aplicou as mesmas regras que exigem em suas certificações em banco de dados: a de exigir um curso como pré-requisito na certificação SCJD e SCEA. A partir de agosto de 2011, para estas duas certificações, pelo menos um curso é obrigatório.

Seguindo a estratégia que já vinha sendo feita pela Sun, a Oracle avançou nas edições do Java, porém com foco maior no mundo corporativo. As próximas seções falam brevemente sobre esses avanços para cada uma das plataformas.

Java SE

A Standard Edition é uma edição que está sempre recebendo atu-alizações por ser o core da plataforma Java. Como estratégia de marca, foi removido o 2 do nome da edição, se tornando apenas Java SE.

Recentemente a versão Java SE 7 Developer Preview foi lançada para a comunidade de desenvolvedores para que estes testassem a versão. A versão 7 tem data de lançamento prevista para o dia 28/07/2011.

A lista de features desta versão está disponível no site http://openjdk.java.net/projects/jdk7/features/ mas podemos destacar melhorias na linguagem Java (JSR334: Project Coin), suporte a linguagens tipadas dinamicamente, com melhoria nos níveis de performance próximas à própria linguagem Java (JSR 292), JDBC 4.1, e suporte total ao Windows Vista.

Para o Java SE 8, já estão sendo aprovadas JSRs, como, por exem-plo, o Projeto Lambda (JSR 335), que permitirá ao Java suportar expressões Lambda (closures). Porém ainda é muito cedo para previsões, visto que para o próprio Java SE 7 as funcionalidades previstas foram alteradas diversas vezes.

A API destinada ao desenvolvimento de aplicações Desktop, Java Swing, é parte integrante do core Java SE e também evoluiu nas últimas versões. Alguns problemas de incompatibilidade ao uti-lizar componentes AWT (conjunto de componentes nativos para um determinado sistema operacional) junto com componentes Swing (ligthweigth) foram resolvidos. Além de melhoria de per-formance na renderização dos componentes, houve também uma concentração no desenvolvimento de Look-And-Feel para Swing.

Um grande diferencial nas aplicações Java para desktop é que ela pode ser executada independente do sistema operacional. A tecnologia Java Web Start permite, além de executar o aplicativo, obter sempre a sua última versão a partir do servidor de aplicati-vos, contornando assim o problema de ter que atualizar todas as aplicações a cada nova versão.

Java EE

Mesmo antes de a Oracle adquirir a Sun Microsystems, a edição Java EE era uma das edições mais revistas e atualizadas entre todas as edições. Por ser voltada ao ambiente corporativo, suas caracte-rísticas devem acompanhar as necessidades das empresas.

Desde as versões antigas dos Beans Java EE, a parte de persistência tem grande importância e destaque nas evoluções que seguiram. A

10

: : www.mundoj.com.br : :

especificação JPA foi introduzida junto ao lançamento da especifi-cação EJB 3, com a clara intenção de substituir os EntityBeans da versão anterior. Juntamente com esta especificação, as anotações substituíram as extensas configurações por XML, que se tornaram opcionais e são mais usadas para permitir customizações em tem-po de deploy.

Com isto, a praticidade das anotações é introduzida a cada nova API ou framework que surge, como é o caso do JSF. Apesar de suas primeiras versões também utilizar de XML para suas configura-ções, a evolução natural para anotações é vista em suas últimas versões.

A mais recente notícia, até a escrita desta matéria, é a apresentação da especificação Java EE 7 como JSR-342. Com unanimidade de votos do comitê executivo, a especificação Java EE 7, JSR-342 foi aprovada e traz muitas novidades para o mundo corporativo.

O líder da especificação, Roberto Chinnici (Oracle), destaca as no-vidades da edição e, segundo ele mesmo, o foco principal para este release é o suporte a Cloud Computing. Este é um assunto muito interessante às empresas, pois permite que grandes sistemas sejam processados em plataformas compartilhadas, reduzindo o custo de hardware e infraestrutura. Conceitos como PAAS (Platform as a Service) são tidos como modelos de negócios graças ao Cloud. Porém, há ainda algumas preocupações a este modelo. Uma delas é a portabilidade das aplicações entre os provedores Cloud, pois ainda não há uma norma capaz de garantir essa portabilidade. Com isto, alguns provedores podem, de certa forma, evitar que uma aplicação migre para outro provedor, o chamado vendor Lock-In. Esperamos que esta nova JSR-342 consiga resolver esse tipo de problema, fazendo com que as aplicações não dependam de APIs proprietárias.

A edição número 47 da revista MundoJ (Cloud Compu-ting: levando suas aplicações Java nas nuvens) traz infor-mações em todos os aspectos sobre Cloud Computing.

Injeção de dependência (DI – Dependency Injection) é um design pattern utilizado quando é necessário manter o menor nível de acoplamento possível entre os compo-nentes de uma aplicação. As instâncias dos componentes são construídas externamente à classe, e controladas por um gerenciador. Assim como num passatempo de ligar pontos, baseado numa configuração esse gerenciador (container) liga os componentes entre si de modo a construir a aplicação. Assim, as dependências não são de-finidas programaticamente. O container fica responsável por “injetar” em cada componente suas dependências. Entenda-se por “injetar” passar uma classe que será usada para a classe que irá consumi-la, sem a necessidade de instanciá-la programaticamente.

Basicamente, a implementação da injeção de dependência pode ser feita de três formas:

Por construtor (constructor injection): as dependências são injetadas direto no seu construtor.

Por propriedade (setter injection): as dependências são injetadas via setter em alguma propriedade.

Por interface (interface injection): o objeto a ser injetado fornece uma abstração (interface ou classe abstrata) e a injeção é realizada via instância da abstração.

Apesar de a injeção de dependência por construtor ser o mais comumente usado, não existe regra que defina qual das três abordagens é a melhor. Assim como quase tudo nas aplicações, depende da situação-problema.

Além de ampliar ainda mais a adequação da plataforma Java EE para ambientes na nuvem, a especificação Java EE 7 traz tam-bém novidades que acompanham os padrões web mais recentes, como suporte a HTML 5. Também contará com uma moderna API Client para JAX-RS 2.0 (muito pedida pela comunidade). Tendo em vista a facilidade de desenvolvimento, a API JMS 2.0 será revisitada, trazendo a adição de uma API para configuração de Injeção de Dependência.

Apesar de a edição Java EE ser dependente da edição Java SE 7, muitos desenvolvimentos já serão feitos tendo em vista o Java 8. Desta forma, muitas empresas já poderão desenvolver seus apli-cativos e tirar proveito de novos recursos da linguagem, logo que ela for lançada.

Algumas JSRs aguardam votação para se unir à especificação Java EE 7:

-lets. Otimizada para Cloud, conta também com algumas me-lhorias como IO assíncrono baseado em Java NIO2.

da especificação JSP 2.0. Mas foi sugerida a separação, para que sejam focadas suas melhorias. Facilidade de uso é um dos principais temas.

1.1, e a última manutenção foi realizada em abril/2002. Exten-sões para suporte a Cloud, facilidade para o desenvolvimento e melhoria no relacionamento com outras APIS é o destaque desta JSR.

de desenvolvimento, tanto na parte gráfica quanto em linha de código, é o foco desta JSR. Introdução a URLs abreviadas (shorthands URL), suporte de features HTML 5, melhor inte-gração com portlets, melhorias no ciclo de vida e segurança além de alguns fixes são os destaques.

Ainda existem duas JSRs candidatas à inclusão na edição Java EE 7: Concurrency Utilities for Java EE (JSR-236) e JCache (JSR-107). Até a escrita desta edição, ambas estavam com status “Inativo” no JCP, o que significa que o líder de cada especificação não publicou um milestone, ou draft para a especificação em 18 meses. Caso atinja 24 meses, o JCP pode retirar as JSRs dos processos.

Um dos principais avanços (e benefícios) da plataforma Java EE foi o desenvolvimento da JSR-299, que especifica uma API para injeção de dependência nativa de qualquer recurso Java.

11

CDI

A injeção de dependência e contextos (CDI), especificada pela JSR-299 como parte do Java EE 6 fornece uma arquitetura que permite a injeção de componentes Java EE, tais como session beans e mana-ged beans do JSF (Java Server Faces). Alguns outros componentes também podem ter beans injetados via CDI: interceptors, servlets (filters e listeners inclusive), message-driven beans.

As classes gerenciadas pelo CDI (os beans) são associadas a con-textos para que seu ciclo de vida seja gerenciado automaticamente. Além disso, o CDI oferece várias funcionalidades: fornecedores, qualificadores, decoradores, interceptadores, alternativas e eventos, que flexibilizam e agilizam o desenvolvimento. Todas essas funcio-nalidades melhoram o baixo acoplamento inerente ao modelo do CDI. E o melhor de tudo é que essas facilidades são oferecidas de modo typesafe. Sem confiar em identificadores baseados em strings, o CDI usa a informação de tipagem do próprio Java, incrementada como um novo padrão denominado “anotações qualicadoras”, para interligar os componentes – beans, dependências, interceptors e decorators, e consumidores de eventos.

A injeção de dependência já existia a partir da especificação do EJB 3, porém ela era muito mais restrita e só podia ser usada em EJBs. A anotação @EJB, por exemplo, permite que o container faça a injeção de qualquer session bean. Outra anotação de injeção de dependência é @PersistentContext, que permite ao container injetar uma instância do EntityManager.

Como vemos, as anotações trazidas na especificação EJB 3 são mais específicas e restritas a cada tipo de objeto, o que não é a intenção de CDI que permite a injeção de praticamente qualquer objeto em vários tipos de objetos gerenciados pelo container. Mais detalhes sobre CDI podem ser obtidos no artigo “CDI – Injeção de Dependência e Gerenciamento de Contextos no Java EE 6” na edição 40 da revista.

Com o lançamento de sua primeira versão, em 2004, o JSF chegou com um paradigma interessante: a orientação por componentes. Este modelo de desenvolvimento atraiu muitos desenvolvedores acostumados com desenvolvimento Swing para desktop. Em mea-dos de 2009, a versão 2.0 foi lançada e trouxe novidades que sim-plificam a vida e aumenta a produtividade inerente a um sistema.

Java ME

Diferente do que a sigla possa levar a interpretar, Java ME não quer dizer Java Mobile Edition, mas sim Java Micro Edition. Java ME é a plataforma Java voltada ao desenvolvimento de aplicações para dispositivos com recursos limitados de hardware. E, consequente-mente, inclui o desenvolvimento para dispositivos móveis. Assim como as demais versões, a plataforma J2ME é uma coleção de APIs do JAVA definidas através da JCP (Java Community Proccess).

Em 1999, numa Conferência Java, a plataforma foi subdividida em J2EE (Java 2 Enterprise Edition), J2SE (Java 2 Standard Edition) e J2ME (Java 2 Micro Edition). Em 2000, começaram a surgir os primeiros celulares com suporte ao JME. Em 2002, foi lançada a segunda versão da MIDP (Mobile Information Device Profile), utilizada até hoje. Como parte de uma estratégia de marketing, na mudança da versão do Java 1.4 para 1.5, algumas siglas foram

alteradas. Na ocasião, foi retirado o “2” da sigla, alterando de J2ME para Java ME, apresentando uma sigla mais moderna para a plataforma.

A arquitetura Java ME é dividida em máquina virtual, configura-ções, perfis e pacotes (APIs) opcionais.

As definem a JVM (Java Virtual Machine) e um conjunto de APIs básicas:

com maior capacidade computacional.-

positivos com menor capacidade computacional.

(profiles) são um conjunto de APIs que complementam uma configuração, provendo funcionalidades para cada categoria de dispositivos, definindo interface do usuário, ciclo de vida as aplicações etc.:

para dispositivos móveis.

em rede sem GUI.

necessitam de um suporte completo para interface ou applet (PDAs, consoles).

As estendem as funcionalidades básicas provendo padrões para tecnologias específicas, tais como bluetooth, web services e multimídia.

A Sun Microsystems desenvolveu a API LWUIT (Ligthweigth UI Toolkit), uma API inspirada em Swing, porém, direcionada para dispositivos móveis. A API permite maior agilidade no desenvolvi-mento de aplicações móveis, uma vez que é construída da mesma forma como se constrói aplicações Swing para Desktop. A API teve lançamento oficial no JavaOne de 2008, e resolveu alguns problemas de incompatibilidade do Java ME entre os fabricantes de celulares.

12

: : www.mundoj.com.br : :

Android

Android não poderia ser uma alternativa de plataforma operacio-nal para o projeto de 2005 pelo simples fato de ainda não existir em 2005! A história de Android inicia em 2006, através do proje-to de uma empresa startup americana: a Android Inc, que surgiu com o seu projeto de uma nova plataforma operacional para o mundo dos dispositivos móveis.

Google, seguindo com sua estratégia de incorporar startups com projetos inovadores e almejando participar do mercado de dispo-sitivos móveis, adquire Android Inc com todos os seus engenhei-ros (Andy Rubin, integrante desta equipe, tornou-se recentemente VP do Google e comanda atualmente o time de desenvolvimento do negócio Android).

Em novembro de 2007, a Google anuncia o lançamento do Android, um sistema operacional baseado em Linux para dis-positivos móveis. Esse evento foi resultado da ação colaborativa das empresas sob a OHA (Open Handset Alliance) – junção do Google e mais 33 parceiros. Uma semana depois, o Android SDK foi apresentado aos desenvolvedores, mas ainda não era open-source. Quase um ano mais tarde, em outubro de 2008, o Android tornou-se open source, tendo seu código publicado como AOSP (Android Open Source Project).

Logo em seguida, foi lançado o primeiro aparelho celular com Android, o HTC G1 que incluía funções do GPS, uma câmera de 3.1MP, e uma variedade de aplicativos do Google. A seguir, estão listadas as versões já lançadas do Android:

de 2009)

para tablets

A Google costuma se referir ao Android OS como uma pilha de softwares (figura 1). A base da pilha é o kernel. O próximo nível de software inclui as bibliotecas do Android e a camada de runti-me. A camada seguinte é o framework de aplicação. E no topo da pilha estão as aplicações propriamente ditas. Em termos de arqui-tetura, o android incorpora uma jvm chamada dalvik. Porém, este é parte do sistema operacional, o que evita que fabricantes possam customizar para o seu hardware próprio.

Figura 1. Pilha de softwares da plataforma Android (retirada de http://developer.android.com/

guide/basics/what-is-android.html)

Em meados de 2010, a Oracle acionou o Google na justiça ame-ricana alegando que houve violação de patentes relacionadas ao Java no lançamento da plataforma Android, pelo fato do Google escrever uma JVM do zero, a Dalvik, e da plataforma ser focada no Java. Na ocasião, Larry Ellison, presidente da Oracle, disse à im-prensa: “Sem consentimento, autorização, aprovação ou licença, o Google conscientemente, propositalmente e ilegalmente copiou, preparou, publicou e distribuiu material com copyright da Oracle America, partes e trabalhos derivados. O Android da Google infi-ringe o Copyright do Java da Oracle America e a Google não está licenciada para isso.”

Contestando a acusação da Oracle, o Google diz que não infringe qualquer patente e alega certa hipocrisia por parte da Oracle. O efeito deste episódio causou o cancelamento, por parte do Google, das participações nas conferências JavaOne, a conferência mais famosa patrocinada pela Oracle. Em nota, o Google lamenta não poder participar, mas enfatiza que é uma conferência importan-te para a comunidade, e diz que é uma das melhores formas de integração e aprendizado. Este episódio causou impacto na co-munidade Java, provocando revolta em muitos desenvolvedores e entusiastas. O rumo dado à plataforma Java também causou um desconforto por certo período de tempo, pois a empresa não se pronunciou tão rapidamente. Atualmente, o processo encontra-se em andamento e ainda não teve um desfecho favorável a nenhuma das partes.

Aplicação Taxi GO

Essa seção tem o objetivo de apresentar a aplicação que mostrará o desenvolvimento e integração de aplicações Java desenvolvidas para diferentes plataformas. Optamos por um cenário simples, onde o foco principal é mostrar a integração das diferentes tecnologias contidas em Java. Não abordaremos aspectos como segurança, desempenho e controle de transações, que em uma aplicação real é essencial.

Imaginamos uma empresa de táxi que necessita de um sistema que possibilite a solicitação de uma corrida realizada por um cliente via celular, um sistema de BackOffice que verifica as filas de pedido de corrida e um outro, também de BackOffice, que gerencia as corridas, selecionando a Unidade que atenderá cada corrida.

Para este cenário, foi idealizada uma aplicação móbile destinada à plataforma Android, onde se é possível encontrar o local de origem via GPS. Um módulo de BackOffice verifica como andam as solicitações de corridas realizadas pelos clientes, incluindo o local de onde a solicitação foi realizada. Em um módulo Desktop, é possível visualizar as corridas, assim como indicar a unidade de atendimento.

Como vemos na figura 2, o sistema central é composto por uma

13

camada de EJBs, responsável por implementar as regras de negó-cio e operações tratadas pelo sistema. Para distribuir o acesso a estas operações, uma camada de WebServices REST foi constru-ída. Na figura, CorridaResource e UnidadeResource são recursos REST, e possuem uma URI única, o que torna possível o acesso através de um endereço como “http://localhost/rest/corrida” ou “http://localhost/rest/unidade”, por exemplo.

O acesso externo é feito pelos módulos móbile e swing. Ambos acessam recursos REST para executar as operações. Já o módu-lo web, por estar no mesmo contexto e, consequentemente, no mesmo container web, pode acessar diretamente os EJBs. Como container Java EE, utilizamos o GlassFish na versão 3.1. Em 2005, este container não poderia ser uma opção, pois o lançamento de sua primeira versão foi em 2006. O GlassFish foi desenvolvido pela Sun Microsystems, e agora é continuado pela Oracle. A aplicação foi desenvolvida utilizando o Eclipse como IDE, e foi dividida em três projetos, conforme descritos na tabela 1. O código-fonte pode ser baixado a partir do site da revista.

TaxiGOAndroid Projeto Android, para o dispo-sitivo móvel.

TaxiGOServices Projeto do tipo Dynamic Web, e engloba os módulos central e web. Inclui os EJBs, resources REST, assim como toda a parte de persistência.

TaxiGOManager Projeto Java SE swing, conten-do o módulo para desktop.

Tabela 1. Projetos Eclipse.

Figura 2. Sistema Táxi GO.

Para identificar as partes do sistema, descrevemos os módulos como:

-gócio e persistência.

corrida.-

ridas pendentes.-

mento das corridas.

Módulo central

O módulo central é o módulo que concentra todas as regras de negócio e persistência. Por esse módulo ser responsável por processar um grande número de re-quisições de diversos tipos de cliente, serão utilizadas tecnologias da plataforma Java EE.

O módulo deve permitir que os módulos-clientes acessem operações como: inclusão de um pedido de uma corrida, listagem das corridas pendentes (que aguardam um motorista para atendê-la) e a finaliza-ção de uma corrida, marcando assim o tempo total do trajeto realizado por uma unidade.

Persistência de dados

Persistência de dados é um tema sempre em destaque, por se tratar de uma das partes mais importantes dos sistemas. Sempre vemos novidades relacionadas a este tema, com objetivo de melhorias em performance e facilidade para o desenvolvimento.

Por isto, esta parte do módulo poderia ser implemen-tada de diferentes maneiras utilizando diferentes solu-ções. Para este projeto, optamos pelo uso do JPA 2.0, com a implementação do Hibernate. Atualmente, JPA é uma API padrão do Java EE no que se diz respeito à persistência de dados. Nesta última versão, algumas features interessantes foram liberadas na linguagem JPQL (Java Persistence Query Language). É possível realizar um select com formatação de datas e incluir Collections nos parâmetros IN das queries.

O suporte a Criteria (baseado no Hibernate) foi uma das grandes novidades. Com esta API, é possível construir queries dinâmicas baseadas em um “objeto-exemplo”. A API adiciona nós á query na medida em que atributos do objeto forem sendo preenchidos.

O EntityManager será injetado nos EJBs que forne-cem os serviços para aplicação e o utiliza para fazer o acesso aos dados. As anotações foram utilizadas nas entidades para mapear como cada uma deveria ser persistida. As próximas seções apresentam com mais detalhe como esses recursos foram implementados.

14

: : www.mundoj.com.br : :

Em 2005, a versão para a API JDBC era a 3.0. Já existiam frameworks de mapeamento objeto-relacional, mas, po-rém os Entity Beans eram o mais próximo que se tinha de mapeamento em uma API padrão.

As opções de frameworks para persistência mais elabora-dos eram Hibernate (versão 2), OJB, os próprios Entity Beans da especificação EJB 2, entre outros.

Na matéria de 2005, foi escolhido Entity Beans CMP, que eram Entity Beans gerenciados pelo container. Os Entity Beans apresentavam sérios problemas de escalabilidade e não suportavam diversos tipos de mapeamento, como herança e certos tipos de composição.

Em 2006 a Sun lançou uma API oficial, junto com a especifica-ção do EJB3.0 (JSR-220) chamada JPA. Esta API viria substituir os Entity Beans da versão do EJB2.

A partir do lançamento da API, muitos outros frameworks ade-rentes a mesma foram lançados, como OpenJPA e o Toplink, por exemplo. Com o uso de anotações, muitas das configu-rações feitas por XML se tornaram opcionais, aumentando a produtividade.

Hoje, a API JPA está na versão 2.0 e foi lançada em dezem-bro/2009. Muitas funcionalidades como Criteria e Validation foram adicionadas. Criteria permite a construção dinâmica de uma querie JP QL, baseada em um objeto de exemplo. À medida que valores são preenchidos em seus atributos, sem intervenção programática, a API consegue selecionar os objetos “parecidos” com o de exemplo. A API validation traz uma série de anotações que permite validar os dados contidos nas classes, geralmente as que serão persistidas. @Min e @Size são exem-plos de anotações desta API.

Ao optar por JPA, economizou-se esforço de desenvolvimento, como com construção de queries para o CRUD e preocupações comuns no acesso ao banco de dados.

Entidades

Para o cenário proposto, foram levantadas apenas três entidades: Passageiro, Unidade e Corrida. O modelo de dados para o arma-zenamento dessas entidades está representado na figura 3. Em uma aplicação real haveria provavelmente mais entidades, porém o artigo irá focar em um exemplo mais simples para poder focar nas tecnologias utilizadas.

A entidade Passageiro representa o cliente, este que solicitará um táxi. A entidade Unidade representa o próprio táxi com os seus respectivos atributos, como nome do motorista, placa ou ID. A entidade Corrida, por sua vez, representa o trajeto realizado pelo táxi para o cliente em questão. Esta entidade guarda informações tanto do passageiro quanto da unidade (motorista), portanto o seu relacionamento de n-para-um é feito para essas duas outras entidades. Não precisamos mapear os relacionamentos como bidirecional, pois não será interessante para o sistema saber em quais corridas o cliente já esteve presente, e quais corridas uma determinada unidade um dia já atendeu.

Figura 3. Modelo de dados para o TaxiGO.

Listagem 1. Entidade Corrida.

@Entity@Table(name=”Corrida”)@XmlRootElementpublic class Corrida implements Serializable { private static final long serialVersionUID = 1L;

@Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id;

@Temporal( TemporalType.TIMESTAMP) @Column(name=”hora_solicitacao”) private Date horaSolicitacao;

@Temporal( TemporalType.TIMESTAMP) @Column(name=”hora_finalizacao”) private Date horaFinalizacao; @Column(name=”lat_origem”) private double latOrigem;

@Column(name=”lon_origem”) private double lonOrigem;

private String qru;

private String status;

private String logradouro;

@ManyToOne @JoinColumn(name=”Passageiro_email”) private Passageiro passageiro;

@ManyToOne @JoinColumn(name=”Unidade_id”) private Unidade unidade;

//construtor, getters e setters omitidos}

15

Listagem 2. Classe CorridaEJB.

@Statelesspublic class CorridaEJB {

@PersistenceContext(unitName=”taxiPU”) private EntityManager em; public Corrida find(Integer pk){ try { Object o = (Corrida) em.find(Corrida.class, pk); em.refresh(o); detach(o); return o; } catch (Exception e) { e.printStackTrace(); return null; } } public void persist(Corrida t){ try{ em.persist(t); em.flush(); }catch(Exception e){ e.printStackTrace(); } } public void merge(Corrida t){ try{ em.merge(t); em.flush(); }catch(Exception e){ e.printStackTrace(); } }

public List<Corrida> getByStatus(String status){ CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Corrida> cq = cb.createQuery(Corrida.class); Root<Corrida> root = cq.from(Corrida.class); Predicate byStatus = cb.equal(root.get(“status”), status); cq.where(byStatus); List<Corrida> corridas = em.createQuery(cq).getResultList(); return corridas; }}

Um exemplo de entidade está apresentada na Listagem 1. Anali-sando a classe Corrida, vemos que ela possui duas anotações: @Entity e @XmlRootElement. Como optamos por utilizar JPA para gerenciar a camada de persistência, a anotação @Entity é neces-sária para que a classe seja reconhecida pelo EntityManager como uma classe de entidade persistente.

Já a anotação @XmlRootElement indica qual é o elemento raiz do XML que será gerado. A anotação está contida no pacote javax.xml.bind.anotação, e é parte da API JAXB. A API de referência foi desenvolvida sob a JSR 222, e sua última versão até o momento desta matéria é 2.2.4. Com esta API, faremos a transformação da Classe para o XML que é transferido entre os sistemas clientes e o sistema central.

Com essas anotações, as classes de entidade podem ser mapeadas para o banco de dados sendo gerenciadas pelo EntitManager, e pode ser, de forma fácil, transformadas para o formato XML.

Para se relacionar com as outras entidades, a classe Corrida utiliza as anotações de mapeamento JPA @ManyToOne e @JoinColumn. Como vemos na classe, a anotação @ManyToOne fica acima do atributos que corresponde ao lado “Um” quando se diz Muitos-para-um. Por sua vez, a anotação @JoinColumn indica por qual atributos o EntityManager deverá selecionar os dados na hora de realizar o join entre as tabelas no banco de dados.

Todas as classes de entidade são desenvolvidas da mesma forma e podem ser acessadas no código-fonte disponível para download no site da revista.

EJB

Para concentrar as operações principais do sistema e suas regras de negócio, criamos uma camada de negócios onde se encontram os EJBs do sistema. Esse tipo de componente é utilizado para conter serviços que representam processo de negócio. Os EJBs utilizados, que no caso são Session Beans, fazem parte da especificação EJB 3.1, que é parte integrante da versão Java EE 6.

Nesta versão, EJBs podem estar contidos em um projeto de estru-tura web (arquivos WAR), e por isto unimos todas as partes do módulo central em um único projeto web.

Além disto, a especificação conta com novas anotações, como @Singleton que faz com que o container garanta apenas uma ins-tância do EJB. Chamadas assíncronas, timer service integrado, e um EJB mais leve (EJB Lite) são itens importantes que fazem parte desta atualização e que não foram utilizados no exemplo.

Uma novidade do EJB 3.1 que foi usada no projeto, é que para EJBs que serão chamados apenas localmente, não é preciso mais ter uma interface anotada por @Local. como este é o caso de nossa aplicação, pode-se observar que os EJBs não implementam nenhuma interface. Os acessos externos serão feitos no sistema a partir de uma camada adicional que disponibilizará os serviços via WebServices Restful.

Como podemos ver, a classe CorridaEJB apresentada na Listagem 2 é anotada por @Stateless. Esta anotação indica ao container que deve ser tratada como um EJB do tipo Stateless. Seu ciclo de vida é gerenciado pelo container e suas instâncias poderão “viver” em

um pool de objetos que o container gerencia. Nesta classe, anota-mos também a instância do EntityManager, que será injetada pelo container. Indicamos isto ao container adicionando a anotação @PersistentContext, seguida no nome da unidade de persistência configurada no arquivo persistence.xml

Analisando o método getByStatus(), podemos ver que este utiliza de uma feature nova da versão JPA 2.0. Criteria é uma API que permite a construção de queries dinâmicas, utilizando um objeto-exemplo. Para demonstrar o uso da API, fizemos a execução de uma consulta simples, obtendo todos os registros de Corrida que contém um determinado status.

A primeira linha CriteriaBuilder cb = em.getCriteriaBuilder();, obtém do EntityManager o construtor de queries dinâmicas. Na linha Root<Corrida> root = cq.from(Corrida.class); indicamos qual é o elemento principal na consulta, no caso a classe Corrida. Em seguida, em Predicate byStatus = cb.equal(root.get("status"),

16

: : www.mundoj.com.br : :

status); informamos que o atributo “status” de nossa classe deve ser levado em consideração na consulta, e que devem ser bus-cados valores iguais (equal) ao informado na variável status. Ao final, adicionamos esse critério a consulta através do comando

cq.where(byStatus);

Podemos ver mais detalhes sobre as novidades do EJB 3.1 na edi-ção número 31 da revista.

No artigo em 2005, os EJBs estavam na versão 2.1. Uma série de passos deveriam ser seguidos ao implementar um EJB, o que incomodava muita gente. Qualquer EJB Session Bean deveria implementar a interface ServiceBean, que obrigava o desenvolvedor a escrever métodos relacionado ao ciclo de vida do EJB, como ejbCreate(), ejbActivate() e ejbRemove(), muitas vezes sem necessidade.

O Session Bean deveria possuir também uma interface representando os métodos disponíveis. Para o acesso no mesmo container, a interface deveria extender outra in-terface, a EJBHome. Para acesso remoto, deveria extender EJBObject.

A configuração era realizada por XML, já que ainda não existiam as annotations. O XML (ejb-jar.xml) descrevia os EJBs da aplicação, assim como suas interfaces local e remota.

Para ajudar nessa tarefa de configuração, era muito co-mum o uso da ferramenta o XDoclet. A ferramenta lia tags descrita em comentários JavaDoc gerava o código-fonte das interfaces local e/ou remota, seguindo um template de código definido. Na versão de 2005, esta ferramenta facilitou na geração das interfaces Local e Remota.

A evolução dos EJBs se deu em todos os aspectos, desde suas configurações até o padrão de estruturas de pastas.

Hoje, em sua versão 3.1, não é mais necessária uma estrutura de pastas específicas para um projeto EJB. Podemos colocar EJBs em arquivos WAR (web-archive), o que antes era possível apenas em arquivos JAR (contidos ou não em um arquivo EAR).

O uso de anotações e convenções de código eliminou quase por completo as configurações XML, que agora são opcionais. Para informar ao container um session bean stateful, basta utilizar a anotação @Stateful acima da classe, assim como stateless utilizando a anotação @Stateless.

Na versão 3.0 já deixou de ser obrigatório escrever métodos que não dizem respeito a regras de negócio e operações. Para interceptar o ciclo de vida, foram disponibilizada anotações para serem utilizadas em métodos como @PrePassivate, @PostActivate e @PreDestroy, por exemplo.

A criação de uma interface local ou remota passou a ser op-cional, tornando o session bean praticamente um POJO com anotações EJB.

Cadastrar Unidade /unidade/cadastrar

Atualizar Unidade /unidade/atualizar

Selecionar Corrida /corrida/selecionar

Finalizar Corrida /corrida/finalizar

Consultar Corridas Pendentes /corrida/consultarPendentes

Consultar Corrida /corrida/consultar/{idCorrida}

Solicitar Corrida /corrida/solicitar

Figura 4. Combinando JPA + JAXB + REST.

Poderíamos ter criado uma camada DAO com classes conven-cionais e ter separado todas as responsabilidades de operações em banco de dados nesta camada. Outra opção seria a utilização de DAOs genéricos, fazendo com que operações de CRUD em comum a todas as entidades ficassem em apenas uma classe DAO.

Na aplicação-exemplo optamos por utilizar o próprio EJB como implementação dos DAOs. O container injeta uma instância do EntityManager, realizando trabalhos como a criação da conexão e o controle de transações. Desta forma, cada entidade de domínio no sistema deve ter o seu EJB com os métodos de todas as ope-rações possíveis. Por exemplo, temos o EJB CorridaEJB, que trata qualquer operação relacionada a corridas. Suas regras de negócio estão explícitas neste ponto, e quando o método precisa de uma operação no banco de dados, o EntityManager é utilizado.

RESTFul

Em 2000, Roy Fielding, um dos principais autores da especificação do protocolo HTTP, escreveu sua tese de doutorado baseada em uma técnica de engenharia de software para sistemas distribuídos na web. Em sua tese, ele descreve o Representational State Trans-fer (REST), um conjunto de princípios arquiteturais que permite troca de mensagens entre sistemas heterogêneos. Para o REST, os verbos HTTP (GET, POST, PUT, DELETE) definem a ação que será realizada. Hoje em dia, webservices REST são uma alternativa aos

Tabela 2. URIs definidas para os serviços do TaxiGO.

Na Listagem 3 é mostrada a classe CorridaResource, que é res-ponsável por oferecer os métodos disponíveis relacionados a uma corrida. A anotação @Path indica qual será a URI raiz do recurso representado pela classe. Através desta anotação, indicamos que qualquer URI acessada após “/corrida”, será de responsabilidade desta classe. Em cada método da classe, devemos indicar por qual verbo HTTP será acessado, como no exemplo a anotação @PUT, e que tipo de informação este método produz e consome, através das anotações @Produces e @Consumes. Note que a anotação @Path é usada novamente para configurar a URI específica do método.

Um EJB pode ser facilmente utilizado como um recurso REST, e por isto adicionamos a anotação @Stateless A classe. Com isto, além de ser uma interface de serviços aos outros módulos do sistema, fornecendo uma forma de ser acessado por uma URL, poderia ser chamado através de RMI por algum outro sistema interessado em consumir EJBs. Dessa forma, temos duas camadas EJB, uma respon-

webservices baseados em SOAP, apresentando maior flexibilidade e facilidade no desenvolvimento. Na arquitetura REST, funciona-lidades são consideradas Recursos (Resources), que são acessadas através de URIs únicas. Para facilitar o entendimento, os recursos do sistema com suas respectivas URIs estão representadas na tabela 2. Note que a URI, no geral, é formada pelo nome da entidade relacionada à ação correspondente.

17

Listagem 3. Classe CorridaResource.

@Path(“/corrida”)@Statelesspublic class CorridaResource { @EJB private CorridaEJB corridaservice; @PUT @Produces(MediaType.APPLICATION_XML) @Consumes(MediaType.APPLICATION_XML) @Path(“/solicitar”) public Response solicitar(Corrida corrida){ try{ Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(System.currentTimeMillis()); corrida.setHoraSolicitacao(cal.getTime()); corrida.setStatus(“Pendente”);

corridaservice.persist(corrida); }catch(Exception e){ e.printStackTrace(); return Response.serverError().build(); } return Response.ok(corrida).build(); }

@GET @Produces(MediaType.APPLICATION_XML) @Consumes(MediaType.APPLICATION_XML) @Path(“/consultar/{idCorrida}”) public Response consultar(@PathParam(“idCorrida”) Integer idCorrida){ try{ Corrida corrida = corridaservice.find(idCorrida); return Response.ok(corrida).build(); }catch(Exception e){ e.printStackTrace(); return Response.serverError().build(); } }

//Outros métodos omitidos}

O método consultar() foi desenvolvido com o objetivo de pos-sibilitar a consulta de uma corrida através de seu ID, portanto sendo um método “idempotente” (ver quadro para detalhes) deve ser anotado como método @GET. Vemos que o método recebe um parâmetro do tipo Integer idCorrida, mas com uma diferença de possuir a anotação @PathParam. Esta anotação faz com que, ao ser chamado, o servlet do REST forneça essa informação di-retamente ao método. A informação é parametrizada no atributo da anotação @Path, que nesse caso é "/consultar/{idCorrida}". Os atributos entre chaves {}, indicam que o valor será passado para

algum parâmetro do método. No exemplo, o atributo da anotação {idCorrida} está ligada ao parâmetro @PathParam com o mesmo nome. Por exemplo, para consultar a corrida de ID 13, chamamos a URI corrida/consultar/13. Internamente, o REST extrai esse pa-râmetro e passa para o método.

Alguns métodos HTTP são “idem-potentes” e outros não. Um mé-todo é dito idempotente quando uma requisição causa o mesmo efeito que várias requisições suces-sivas. O método GET é um método idempotente, portanto espera-se que as regras de negócio sob este método não cause nenhum efeito colateral se chamado sucessivas vezes. Como próprio nome do método (GET), subentende-se que este apenas irá obter algum recur-so (consultas).

Em 2005, os módulos conversavam através de um módulo central, da mesma forma que hoje. Porém, este módulo central era composto por servlets e EJB 2.1. Para o envio de uma informação entre o módulo cliente móbile, por exemplo, strings eram esperadas no request, para que o método doGet() do servlet capturasse e tratasse a infor-mação.

Ao receber essa informação, o método realizava um lookup para o EJB responsável pela operação, e este convertia em byte array para responder ao cliente.

Esta conversão para byte[] é direcionada ao cliente móbi-le. Um XML ou string delimitada poderia ser retornada, porém algum tratamento da informação seria necessária no cliente. Por exemplo, se retornasse um XML, um parse deveria ser realizado, e para isto provavelmente um API seria utilizada, aumentando assim o tamanho da aplicação MIDP.

O XML gerado como resposta pelo servidor era monta-do manualmente, de forma que se formasse uma string concatenada contendo as tags do XML e os valores das informações.

Atualmente, com o avanço no processamento dos dispositivos móveis, assim como a sua capacidade de armazenamento, não é mais necessária uma solução direcionada a estes dispositivos.

Android, por exemplo, possui um parser nativo de XML entre as suas APIs, não sendo necessárias APIs de terceiros para reali-zar o tratamento no XML. E, por isto, escolhemos realizar esta integração com webservices REST, uma vez que este retorna um XML comum ao dispositivo.

Desta forma, os clientes do módulo central acessarão todos da mesma forma, sem exceção.

Também não é necessário o lookup explícito aos EJBs, pois este é injetado diretamente ao recurso REST através da anotação @EJB. Todo este trabalho, que antes era feito manualmente, passou a ser feito pelo container.

O XML gerado pelo servidor não é mais manipulado pelo desenvolvedor. A API que implementa a especificação REST converte automaticamente para a classe desejada aumentando a produtividade e reduzindo a complexidade inerente ao tratar dados em XML.

sável pelas regras de negócio e suas operações, tratando de forma específica assuntos como persistência de dados, e outra responsável pela interface entre os módulos clientes e as operações do sistema em si.

Como podemos ver, essa classe possui um atributo do tipo Corri-daEJB que é injetado pelo container, como indica a anotação @EJB. A Listagem 3 mostra como exemplo o método solicitar(). Este é um dos principais métodos deste sistema, uma vez que é responsável por reservar uma corrida para um cliente. Foi configurada a URI “/solicitar” para este método. Ele será acessado somente se for chama-do pelo verbo PUT, indicado pela anotação @PUT.

O método espera por um objeto do tipo Corrida como parâmetro. A API JAXB converte, a partir do XML recebido no request, para uma instância da classe Corrida, com os atributos preenchidos. Este método não tem efetivamente um retorno, mas podemos informar ao cliente que a operação foi executada com sucesso. O retorno do método é uma classe do tipo Response, onde podemos responder qualquer status esperado pelo protocolo HTTP. No caso de alguma exceção ocorrer, este método responde ao cliente com um erro do tipo Internal Server Error (Erro 500 do protocolo HTTP). O Enum Response.Status contém todos os status do protocolo HTTP.

Para este método, é esperado um objeto do tipo Corrida com as informações sobre o cliente preenchidas, inclusive as coordenadas geográficas que serão extraídas do GPS do celular. O servlet REST receberá um XML, e a API JAXB irá converter para a classe Corrida que é recebida como parâmetro. O método precisa adicionar as informações sobre o momento da solicitação, o que é feito obtendo a data e hora corrente do sistema (System.currentTimeInMillis()). O método também marca a corrida como pendente, uma vez que em primeiro momento aguardará por um motorista disponível.

18

: : www.mundoj.com.br : :

Módulo web

Em 2005, o mais popular framework web era o Struts. Sua popularidade era maior do que qualquer outro framework, e possuía a maior comunidade de desenvolvedores. Muitas empresas até hoje utilizam este framework, inclusive a sua primeira versão lançada em 2001. No artigo anterior, não foi utilizado nenhum framework no desenvolvimento da solução.

Neste artigo, vamos falar um pouco além da integração entre as plataformas, demonstrando a escolha de uma opção atual para o front-end web. Para o módulo web do TaxiGO, esco-lhemos o JSF em sua versão 2.0, que é uma API que faz parte da especificação Java EE 6. A implementação de referência usada neste artigo é a Mojarra e é apoiada pela JBoss.

O front-end web tem como objetivo mostrar as corridas que estão sendo solicitadas em tempo real. Como é um front-end web, pode ser acessado por navegadores tanto pelo desktop como pelo celular.

Juntamente com o JSF, escolhemos uma biblioteca de com-ponentes visuais para deixar as páginas mais atraentes: o PrimeFaces. O PrimeFaces vem sendo muito utilizado por sua diversidade de componentes e sua facilidade no momento da configuração. Para se ter uma ideia, basta ter o jar do prime-faces no class-path da aplicação que já é possível declarar e utilizar os seus componentes. Como o objetivo aqui é mostrar a integração entre o módulo web e os EJBs da aplicação, não vamos nos aprofundar nos assuntos JSF e Primefaces.

O artigo “Frameworks RIA para JSF Lado a Lado”, da edição número 42 da revista, compara os frameworks para JSF, entre eles o primefaces.

Listagem 4. Classe CorridaBean (Managed Bean JSF).

@ManagedBean(name=”corridaBean”)@RequestScopedpublic class CorridaBean { private List<Corrida> corridasList; @EJB private CorridaEJB corridaService; public List<Corrida> getCorridasList() { corridasList = corridaService.getByStatus(“Pendente”); return corridasList; }

public void setCorridasList(List<Corrida> corridasList) { this.corridasList = corridasList; } public void atualizaCorridas(){ getCorridasList(); }}

Como podemos ver na Listagem 6, a classe é anotada pelas ano-tações @ManagedBean e @RequestScoped. Estas anotações são novidades do JSF 2, pois nas versões anteriores do JSF as configu-rações eram feitas em arquivos XML.

A anotação @ManagedBean indica que a classe é um Bean Ge-renciador do JSF. Esta anotação pertence ao pacote do jsf, mas poderíamos utilizar outras anotações da especificação CDI como @Model, por exemplo, fazendo com que o Bean se tornasse um Bean gerenciado por alguma implementação CDI.

Este Bean é responsável por intermediar a comunicação entre a página web e o módulo central, que contém as regras de negócio e operações do sistema. Neste Bean é possível ter métodos Listeners (métodos que “escutam” eventos dos componentes da página), métodos que acessam dados para mostrar nos componentes, entre outros.

Nesta mesma classe, vemos que a anotação @EJB é utilizada acima do atributo CorridaEJB. Com isto, o container Java EE pode inje-tar uma instância do EJB diretamente no atributo, e gerenciando o seu ciclo de vida. Desta forma, temos um ManagedBean mais “clean”, delegando tarefas para o EJB.

Lembrando que o EJB está na mesma estrutura deste módulo web. Está permitida pela plataforma Java EE 6, e nas versões anteriores o EJB teria a sua própria estrutura e não funcionaria desta forma.

Na Listagem 5, vemos a página index.xhtml do módulo web. Esta é a página responsável por mostrar as corridas pendentes que estão sendo solicitadas pelos clientes. Ela basicamente contém um data-Table listando as informações das corridas.

O dataTable utilizado é uma taglib do framework Primefaces, pois apresenta uma table interessante e atraente para mostrar informa-ções. Além de fornecer parâmetros para ordenação, paginação hea-der e footer, também já vem com meios para obter informações com Ajax. Um parâmetro interessante é o Lazy Loading, que permite carregar as informações à medida que vê avanço nas páginas da listagem.

Além da taglib <p:dataTable>, utilizando também a <p:gmap>, responsável por renderizar um mapa GoogleMaps. Basta informar latitude e longitude no parâmetro Center, que será renderizado um mapa GoogleMaps onde o ponto central será as informações pas-

tanto a visão Satélite quanto o desenho do mapa.

Para que as informações sejam atualizadas sem nenhuma interven-ção, utilizamos a taglib <p:poll>. Este é um dos padrões de Ajax Reverso, onde a página fica solicitando, de tempos em tempos, os dados do servidor. Para informar o intervalo de tempo em segun-dos, é necessário o parâmetro intervalo. Precisamos informar tam-bém qual método será chamado no bean, e este é feito no parâmetro listener. O parâmetro update informa qual o componente da página será atualizado após a chamada receber o retorno do server.

19

Listagem 5. Página index.xhtml.

<?xml version=’1.0’ encoding=’UTF-8’ ?><!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”><html xmlns=”http://www.w3.org/1999/xhtml” xmlns:p=”http://primefaces.prime.com.tr/ui” xmlns:h=”http://java.sun.com/jsf/html” xmlns:f=”http://java.sun.com/jsf/core”> <h:head> <title>TaxiGO - Corridas pendentes</title> <script type=”text/javascript” src=”http://maps.google.com/maps/api/js?sensor=false”></script> </h:head> <h:body> <p align=”center”> <p:graphicImage url=”images/logo_web.png” alt=”TaxiGO Web” /> </p> <h:form> <p:dataTable var=”corrida” value=”#{corridaBean.corridasList}” id=”gridCorridas”> <p:column> <f:facet name=”header”> Id </f:facet> <h:outputText value=”#{corrida.id}” /> </p:column> <p:column> <f:facet name=”header”> Hora Solicitacao </f:facet> <h:outputText value=”#{corrida.horaSolicitacao}”> <f:convertDateTime pattern=”dd/MM/yyyy HH:mm” /> </h:outputText> </p:column>

<p:column> <f:facet name=”header”> Passageiro </f:facet> <h:outputText value=”#{corrida.passageiro.email}” /> </p:column> <p:column> <f:facet name=”header”> Mostrar no mapa </f:facet> <p:commandButton type=”button” image=”ui-icon ui-icon-pin-s” value=”Mostrar no mapa” onclick=”dlg.show()” /> <p:dialog widgetVar=”dlg” width=”625” height=”450” modal=”true”> <p:gmap center=”corrida.latOrigem, corrida.lonOrigem” zoom=”17” type=”HYBRID” style=”width:825px;height:450px” widgetVar=”mymap” /> </p:dialog> </p:column> </p:dataTable> <p:poll interval=”10” listener=”#{corridaBean.atualizaCorridas}” update=”gridCorridas” /> </h:form> </h:body></html>

Figura 5. Módulo web mostrando as corridas pendentes em um dataTable.

Módulo cliente móbile

Para o módulo cliente móbile, escolhemos a plataforma Android por esta plataforma oferecer componentes atraen-tes para uma aplicação direcionada a dispositivos móveis.

A aplicação do celular contém apenas uma tela de inter-face para o usuário onde são realizadas todas as funciona-lidades. Uma das funções é comunicar-se com a central,

enviando a informação sobre a localização do usuário (latitude e longitude) obtida através do GPS ou da rede da operadora, e a conta Google que o usuário está utilizando no dispositivo.

A comunicação é realizada através do protocolo HTTP, enviando informações no formato XML para o WebService RestFul disponibi-lizado no sistema central.

20

: : www.mundoj.com.br : :

Listagem 6. Classe TaxiGOService, resposável por tratar o envio e retorno de informações.

Listagem 7. XML recebido pelo sistema central.

public class TaxiGOService { private HttpClient httpclient = new DefaultHttpClient(); private String urlService; public TaxiGOService(String urlService) { this.urlService = urlService; } public Corrida solicitar(Corrida corrida) throws Exception{ String xml = getXML(corrida); try { HttpPut put = new HttpPut(urlService + “/corrida/solicitar”); ResponseHandler<String> handler = new BasicResponseHandler(); StringEntity myEntity;

myEntity = new StringEntity(xml, “UTF-8”); put.addHeader(“Content-Type”, “application/xml; charset=UTF-8”); myEntity.setContentType(put.getFirstHeader(“Content-Type”)); put.setEntity(myEntity); String result = httpclient.execute(put, handler); Log.d(“result”, result); return parseXML(result); } catch (Exception e) { e.printStackTrace(); Log.d(“ErroTaxiGOService”, e.getLocalizedMessage()); } return null; } public Corrida consultar(Integer idCorrida){ HttpGet get = new HttpGet(urlService + “/corrida/consultar/” + idCorrida); ResponseHandler<String> handler = new BasicResponseHandler(); String result; try { result = httpclient.execute(get, handler); Log.d(“result”, result); return parseXML(result); }catch (Exception e) { e.printStackTrace(); Log.d(“Erro ao consultar corrida”, e.getLocalizedMessage()); } return null; } private Corrida parseXML(String xml) throws Exception { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); CorridaHandler passageiroHandler = new CorridaHandler(); xr.setContentHandler(passageiroHandler); sp.parse(new ByteArrayInputStream(xml.getBytes()), passageiroHandler); Log.d(“handler”, passageiroHandler.getCorrida().getId() + “”); return passageiroHandler.getCorrida(); } private String getXML(Corrida corrida){ String ret = “<corrida>” + “<latOrigem>” + Location.convert(corrida.getLatOrigem(), Location.FORMAT_DEGREES).replace(“,”,”.”)+ “</latOrigem> “ + “<lonOrigem>” + Location.convert(corrida.getLonOrigem(), Location.FORMAT_DEGREES).replace(“,”,”.”) + “</lonOrigem> “ + “<logradouro>” + corrida.getLogradouro() + “</logradouro> “ + “<passageiro>” + “ <celular>” + corrida.getPassageiro().getCelular().trim() + “</celular> “ + “ <email>”+ corrida.getPassageiro().getEmail().trim() + “</email> “ + “</passageiro>” + “</corrida>”; return ret; }}

<corrida> <horaSolicitacao>2011-06-18T16:38:23-03:00</horaSolicitacao> <id>1</id> <latOrigem>-23.67537</latOrigem> <logradouro> R. Cotoxó : 427-555 - São Paulo, Santo André - Brasil </logradouro> <lonOrigem>-46.51504</lonOrigem> <passageiro> <celular/> <email>[email protected]</email> </passageiro> <status>Confirmada</status> <unidade> <id>2</id> <nomeMotorista>Benedito Ruy</nomeMotorista> <numero>137</numero> <placa>DLP-2913</placa> </unidade></corrida>

Como podemos ver na classe TaxiGOService representada na Listagem 6, no envio da informação o XML é “montado” concate-nando-se os dados necessários. A comunicação é feita através da classe HttpClient, uma API nativa do Android que permite uma conexão a um servidor através do protocolo HTTP. O método so-licitar() recebe como parâmetro um objeto do tipo Corrida, usado para concatenar as informações com o XML. Este método chama o método solicitar() do sistema central, exposto sob a URI /corrida/solicitar. Como o método espera que o acesso seja feito através do método HTTP PUT, deve-se utilizar a classe HttpPut para enviar o XML.

Para realizar este envio, é necessário adequar o seu conteúdo a um tipo de classe Entity. Como estamos enviando informações do tipo String (XML) então setamos o conteúdo em uma classe do tipo StringEntity. Para cada tipo de conteúdo há uma classe respecti-va, como, por exemplo, o ByteArrayEntity para dados binários. O conteúdo do XML será enviado no corpo da requisição HTTP. Precisamos também setar informações adicionais como chartset e content-type ao cabeçalho PUT, e isto se faz adicionando o valor application/xml; charset=UTF-8 para a propriedade Content-Type do Header.

O resultado esperado é a resposta do serviço do sistema central. Como informamos lá no sistema central que os métodos produ-zem informação do tipo XML, então devemos esperar um XML na resposta. Este XML precisa ser transformado em uma instância de um objeto, e para isto utilizamos a API SAX, também nativa. O método privado parseXML() é responsável por receber o XML e devolvê-lo em forma de uma classe, porém a lógica de parsing do XML está na classe CorridaHandler usada no método. Um dos benefícios de se utilizar SAX como parse XML é a capacidade de poder analisar um XML sob demanda, sem a necessidade de ter que construir a árvore inteira em memória. O código-fonte dessa classe está disponibilizado com o resto da aplicação no site da revista MundoJ.

21

Desenhando a interface

O desenvolvimento de interfaces gráficas no Android é feito atra-vés de um padrão XML. Com este XML, o compilador gera uma classe de onde é possível acessar os componentes da tela. Utili-zamos o site http://www.droiddraw.org para desenhar a interface principal. O site permite arrastar-e-soltar os componentes gráficos em uma área predefinida, e ao final gerar o XML.

A Listagem 8 mostra o XML gerado para a interface do módulo móbile. A interface contém apenas labels, botões e um progress bar.

Escolhemos usar o layout absoluto, representado na tag <Absolu-teLayout>. Para este tipo de layout, informações posicionais x e y são informadas em pixels, pois são com estas informações que os componentes são posicionados na tela. Pode parecer complicado desenvolver um layout assim, mas utilizando uma ferramenta que facilita o desenho da tela (droiddraw), esta dificuldade fica em segundo plano.

Os labels são representados pelas tags <TextView> e permite so-mente a visualização do texto, sem edições. Para edições, é usado o EditText.

Todos os componentes precisam ter um ID, para que este seja manipulado via código. O padrão de nomeação dos componentes é descrito como "@+id/nome_componente”. Automaticamente, o sdk relacionará um id inteiro a este componente, e este poderá ser acessado pela classe R como R.id.nome_componente, por exemplo.

Figura 6. TaxiGO Android.

Na figura 6, vemos a interface visual do módulo Android.Bem simples, ela apenas conta com o botão novo endereço, que solicita o sinal do GPS, e espera pelas informações de latitude e longitude. Quando essas informações chegam, o botão “Chamar taxi !” é de-sabilitado. Quando acionado, envia as informações para o módulo central, e mostra o resultado da requisição no label “Solicitacao”.

Localizando a posição via GPS

Para realizar a solicitação de um táxi à central, é necessário infor-mar o local de origem do passageiro. A aplicação pode utilizar um dispositivo GPS, muito encontrado em smartphones, ou a rede da operadora para realizar esta localização. A classe responsável

Listagem 8. Arquivo main.xml, representando interface principal.

<?xml version=”1.0” encoding=”utf-8”?><AbsoluteLayout android:id=”@+id/widget0” android:layout_width=”fill_parent” android:layout_height=”fill_parent” xmlns:android=”http://schemas.android.com/apk/res/android”> <TextView android:id=”@+id/txtLog” android:layout_width=”286px” android:layout_height=”26px” android:text=”Iniciando ...” android:layout_x=”1px” android:layout_y=”2px”> </TextView> <ProgressBar android:id=”@+id/pgBar” android:layout_width=”15px” android:layout_height=”17px” android:visibility=”invisible” android:layout_x=”297px” android:layout_y=”10px”> </ProgressBar> <TextView android:id=”@+id/txtLatitude” android:layout_width=”286px” android:layout_height=”26px” android:text=”Longitude: aguarde ...” android:layout_x=”20px” android:layout_y=”64px”> </TextView> <TextView android:id=”@+id/txtLongitude” android:layout_width=”286px” android:layout_height=”26px” android:text=”Longitude: aguarde ...” android:layout_x=”19px” android:layout_y=”102px”> </TextView> <Button android:id=”@+id/btnLocalizar” android:layout_width=”132px” android:layout_height=”39px” android:text=”Novo endere&#231;o” android:layout_x=”4px” android:layout_y=”380px”> </Button> <TextView android:id=”@+id/txtEndereco” android:layout_width=”288px” android:layout_height=”97px” android:text=” aguarde ...” android:layout_x=”22px” android:layout_y=”158px”> </TextView> <TextView android:id=”@+id/lblEndereco” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”Endereco” android:layout_x=”20px” android:layout_y=”137px”> </TextView> <Button android:id=”@+id/btnChamarTaxi” android:layout_width=”137px” android:layout_height=”40px” android:text=”Chamar taxi !” android:layout_x=”178px” android:layout_y=”379px” android:enabled=”false”> </Button> <TextView android:id=”@+id/lblSolicitacao” android:layout_width=”288px” android:layout_height=”60px” android:text=”Solicitacao” android:layout_x=”18px” android:layout_y=”277px”> </TextView></AbsoluteLayout>

A classe principal é o Midlet, que é a que inicia a aplicação. A aplicação é portável para vários dispositivos, porém a interface gráfica não é mui-to bonita.

Para a transferência de dados, é acessado um Servlet através da API Conector, e array de bytes é trafega-do sob o protocolo http.

A classe Activity é a principal da aplicação e representa uma interfa-ce gráfica. Ela é indicada no arquivo AndroidManifest.xml. A aplicação funciona apenas em celulares com sistema operacional Android e pos-sui uma interface mais rica.

Para transferência de dados, é aces-sado um web service REST que di-reciona a requisição para o método de um EJB.

22

: : www.mundoj.com.br : :

Listagem 9. Método onLocationChanged() da classe Liste-ner, demonstrando como obter a posição por GPS.

public void onLocationChanged(Location location) {

this.location = location;

txtLog.setText(“Pesquisando local ... “);

double lat = location.getLatitude();

double lng = location.getLongitude();

txtLat.setText(“Latitude: “ + lat);

txtLon.setText(“Longitude: “ + lng);

locationManager.removeUpdates(this);

try {

List<Address> addresses = geoCoder.getFromLocation(

location.getLatitude(), location.getLongitude(), 1);

Address a = addresses.get(0);

txtLog.setText(“Endereço encontrado !”);

txtEndereco.setText(a.getThoroughfare() + “ : “ + a.getFeatureName()

+ “ - “ + a.getAdminArea() + “, “ + a.getLocality() + “ - “ +

a.getCountryName());

btnChamarTaxi.setEnabled(true);

} catch (Exception e) {

e.printStackTrace();

}finally{

pgBar.setVisibility(ProgressBar.GONE);

}

}

Na Listagem 9, podemos analisar o método onLocationChan-ged(). Este método é responsável por obter a posição do GPS com informações de latitude e longitude. O método também obtém o endereço, com informação de logradouro, range de números que o dispositivo possa estar (pois a localização não é tão precisa).

Quando o GPS encontra nova localização, este método é chamado e recebe um parâmetro do tipo Location. Esta classe fornece as informações de latitude e longitude.

A classe GeoCoder, do pacote android.location, fornece uma maneira de saber o logradouro, chamando o método getFromLocation(location.getLatitude(), location.getLongitude(), 1). O último parâmetro é um número inteiro, que informa quan-tos endereços na volta do local informado o método pode trazer. Ele retorna um array de classes do tipo Address. O recomendado é recuperar entre um e cinco endereços.

por gerenciar a localização é a LocationManager, classe nativa do Android. Através dela, a API nos fornece informações do status do GPS ou rede, entre outras informações.

Para saber onde está o usuário precisamos de um listener para o GPS que implemente a interface LocationListener. A cada atualiza-ção de informação trazida do dispositivo GPS ou rede, o método onLocationChanged() é chamado. Ele recebe uma classe do tipo Location, que fornece informações importantes, como latitude e longitude.

Módulo gerencial

O módulo gerencial é composto por uma aplicação Swing, cujo objetivo é gerenciar as corridas solicitadas pelos clien-tes. Ao solicitar uma corrida, esta fica com status pendente aguardando uma unidade livre para atendê-la. Uma tela lista as corridas neste status para que o atendente possa atribuir uma unidade à solicitação. Ao atribuir uma unidade, o pas-sageiro recebe a informação de que a unidade escolhida pelo atendente o atenderá.

Inicialmente, o módulo deve acessar o sistema central, soli-citando as corridas pendentes. Em cada corrida pendente, o operador deve indicar qual unidade atenderá esta corrida e, neste momento, o sistema móbile receberá a informação que será atendida.

Para realizar o deploy da aplicação, não precisamos instalar em cada estação. Para isto, usamos a tecnologia Java Web Start, que permite que as aplicações sejam transferidas ao desktop e executadas automaticamente. Ela possibilita, inclusive, baixar e instalar o próprio JRE na estação, caso não tenha instalado.

Para utilizar Java Web Start, é necessário criar um arquivo JNLP (Java Networking Launching Protocol), que é um ar-

A Listagem 10 mostra o código que recupera as informações de corridas pendentes. Para acessar o módulo central, utilizamos clas-ses que pertencem a lib jersey-client.jar, criada para encapsular a conexão a um Resource REST. A classe WebResource, do pacote

quivo onde informamos as configurações de nossa aplicação. Os arquivos do aplicativo, assim como as suas dependências, ficam em uma pasta acessível no container web. Ao acessar o arquivo .jnlp, a JRE local da estação interpreta as informações do arquivo e solicita a transferência dos arquivos. Por padrão, aplicativos Java Web Start rodam no modo "restrito", o que significa que eles não têm acesso a alguns recursos do sistema, como arquivos locais. Mas os editores podem eliminar essas restrições, assinando suas aplicações Web Start com o jarsigner ferramenta que vem com o JDK .

Ao acessarmos a URL http://localhost:8080/TaxiGOServices/desktop/taxigodesktop.jnlp, por exemplo, a aplicação é transfe-rida do servidor para a estação, e inicia a aplicação. Uma grande vantagem de se usar esta tecnologia é que se atualizarmos a versão do aplicativo e deixarmos disponível no servidor, na próxima vez que a estação acessar a mesma URL receberá a aplicação atuali-zada.

23

Listagem 10. Arquivo JNLP para o módulo desktop.

Listagem 11. Listando as corridas pendentes.

<?xml version=”1.0” encoding=”utf-8”?><jnlp codebase=”http://localhost:8080/TaxiGOServices/desktop”><information><title>TaxiGOManager</title><vendor>MundoJ</vendor><description>Modulo desktop para o TaxiGO</description></information> <resources> <j2se version=”1.5+”/> <jar href=”TaxiGOManager.jar”/> <jar href=”lib/jersey-client-1.5.jar”/> <jar href=”lib/jersey-core-1.5.jar”/> </resources> <application-desc main-class=”br.com.mundoj.manager.view.Main” /> <security> <all-permissions /> </security> </jnlp>

public List<Corrida> getCorridas(){ List<Corrida> corridasList = null; try { Corrida[] corridas = corridaResource.path(“corrida”). path(“pendentes”).accept(MediaType.APPLICATION_XML). get(Corrida[].class); corridasList = Arrays.asList(corridas); } catch (Exception e) { e.printStackTrace(); } return corridasList;}

com.sun.jersey.api.client, fornece métodos como get e put, para enviar ou recuperar informações. A API cliente REST recupera as informações e converte o XML recebido em uma instância de uma classe. Como estamos recuperando um array de Corrida (Corri-da[]), no caso do método get, devemos informar para que tipo será convertida as informações do XML no parâmetro da chamada.

Figura 7. Gerenciador de corridas desktop.

Não houve grandes mudanças na forma com que uma aplicação desktop é desenvolvida com Java. Como vimos, tirando a parte que acessa o WebService REST, esta aplicação poderia ter sido escrita da mesma forma em 2005.

E o JavaFX?

JavaFX é um plataforma de software multimídia, baseada em Java, para a criação e disponibilização de RIA (Rich Internet Applications), que pode ser executada em vários dispositivos diferentes – qualquer dispositivo que rode JRE ou JME pode rodar aplicativos criados com JavaFX. Para o desenvolvimento das aplicações utiliza-se uma linguagem tipada estática, o JavaFX Script, orientada a objetos e com uma sintaxe simples. Através do JFX é possível acessar as APIs do Swing e do AWT de forma fácil para construir interfaces ricas.

Apesar de parecer uma evolução natural, utilizar JavaFX para a aplicação desktop ou móvel não pareceu a me-lhor alternativa. O JavaFX hoje ainda é pouco utilizado, mesmo se mostrando tão promissor. Após a compra da Sun pela Oracle, teve-se a impressão de que a “morte” do JavaFX era apenas questão de tempo. Algumas notas no site do JavaFX dão a entender que a linguagem será toda reestruturada, e o que vir a ser feito em uma possível versão do JavaFX 2.0 não será compatível com o Java-FX Script atual. Em vista dessa indecisão sobre o futuro da plataforma, não utilizar o JavaFX tanto na aplicação desktop quanto na aplicação móbile mostrou-se a opção mais coerente.

Considerações finais

Neste artigo, passamos pelas atuais plataformas do Java, desde o pioneiro Desktop até a plataforma Android, destinada aos disposi-tivos smartphones, passando pela plataforma web que hoje em dia é o foco de muitas tecnologias. Detalhes de cada plataforma foram abordados a fim de mostrar suas particularidades.

A tecnologia Java evolui cada vez mais ao longo do tempo desde o seu lançamento, e hoje em dia vimos que é mais fácil e prático construir aplicações mesmo que possuam detalhes de certa com-plexidade. Essas complexidades são absorvidas pela própria plata-forma, e isto a torna uma tecnologia completa, robusta e confiável.

Referências