Java de ponta a ponta (6 anos depois)

Propaganda
: : www.mundoj.com.br : :
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.
Java de ponta (6aanos
ponta
depois)
Uma aplicação completa passo-a-passo integrando Android + Java EE + Java SE
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.
8
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
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.
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.
O objetivo deste artigo é explicar passo-a-passo o desenvolvimento 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.
Java SE
Evolução do Java de 2005 até 2011
Em 2005, a Sun Microsystems, até então detentora da plataforma 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 à seguranç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 respondidas, 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 plataforma. Uma das novidades da Oracle foi a primeira realização no Brasil do maior evento Java mundial, o JavaOne, em dezembro de 2010.
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.
A Standard Edition é uma edição que está sempre recebendo atualizaçõ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 exemplo, 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 utilizar componentes AWT (conjunto de componentes nativos para
um determinado sistema operacional) junto com componentes
Swing (ligthweigth) foram resolvidos. Além de melhoria de performance 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 aplicativos, 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 caracterí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
9
: : www.mundoj.com.br : :
especificação JPA foi introduzida junto ao lançamento da especificaçã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 tempo 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 novidades 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 Computing: levando suas aplicações Java nas nuvens) traz informações em todos os aspectos sobre Cloud Computing.
Além de ampliar ainda mais a adequação da plataforma Java EE
para ambientes na nuvem, a especificação Java EE 7 traz també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 aplicativos 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:
t +BWB4FSWMFUT+43
EFTDSFWFBOPWBWFSTÍPEPTTFSWlets. Otimizada para Cloud, conta também com algumas melhorias como IO assíncrono baseado em Java NIO2.
t &YQSFTTJPO -BOHVBHF +43
BUVBMNFOUF &- Ï QBSUF
10
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.
t +BWB.FTTBHF4FSWJDF+43
BWFSTÍPBUVBMEFTUB"1*Ï
1.1, e a última manutenção foi realizada em abril/2002. Extensões para suporte a Cloud, facilidade para o desenvolvimento
e melhoria no relacionamento com outras APIS é o destaque
desta JSR.
t +BWB4FSWFS 'BDFT +43
NBYJNJ[BS B QSPEVUJWJEBEF
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 integraçã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.
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 componentes 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 definidas 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.
CDI
A injeção de dependência e contextos (CDI), especificada pela JSR299 como parte do Java EE 6 fornece uma arquitetura que permite
a injeção de componentes Java EE, tais como session beans e managed 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 contextos 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 funcionalidades 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 meados de 2009, a versão 2.0 foi lançada e trouxe novidades que simplificam 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, consequentemente, 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 DPOmHVSBÎÜFT definem a JVM (Java Virtual Machine) e um
conjunto de APIs básicas:
t $%$ $POOFDUFE %FWJDF $POmHVSBUJPO
QBSB EJTQPTJUJWPT
com maior capacidade computacional.
t $-%$ $POOFDUFE -JNJUFE %FWJDF $POmHVSBUJPO
QBSB EJTpositivos com menor capacidade computacional.
0TQFSmT (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.:
t .PCJMF*OGPSNBUJPO%FWJDF1SPmMF.*%1
CBTFBEPOB$-%$
para dispositivos móveis.
t 'PVOEBUJPO1SPmMF'1
CBTFBEPOB$-%$QBSBEJTQPTJUJWPT
em rede sem GUI.
t 1FSTPOBM1SPmMF11
CBTFBEPOB$%$QBSBEJTQPTJUJWPTRVF
necessitam de um suporte completo para interface ou applet
(PDAs, consoles).
t 1FSTPOBM#BTJT1SPmMF1#1
CBTFBEPOB$%$ÏVNBEJWJTÍPEP11
As "1*TPQDJPOBJT 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 desenvolvimento 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.
"NÈRVJOBWJSUVBMRVFTVQPSUBP+.&ÏB,7.WPMUBEBQBSB
$-%$oDPNBQFOBT,EFDØEJHPFOFDFTTJUBOEPEFQPVDPTLC
QBSBFYFDVUBS.FTNPTFOEPQFRVFOBQFSNJUFQFSTPOBMJ[BÎÍP
QPJT EJWFSTBT GVODJPOBMJEBEFT UPSOBSBNTF PQDJPOBJT QPEFOEP
TFSBEJDJPOBEBTFNBMHVNBDPOmHVSBÎÍPFNQBSUJDVMBS"mN
EFNBOUÐMBQFRVFOBGPSBNDPNQSPNFUJEPTBMHVOTBTQFDUPTJN
QPSUBOUFT",7.OÍPJNQMFNFOUBBFTQFDJmDBÎÍPEB+7.+BWB
7JSUVBM.BDIJOF
NBTBQFOBTQBSUFEFMB$POTFRVFOUFNFOUFB
QPSUBCJMJEBEFmDBQSFKVEJDBEB/BNBJPSJBEBTWF[FTBQMJDBÎÜFT
+BWB.&BQFOBTTÍPQPSUÈWFJTFOUSFEJTQPTJUJWPTDPNPNFTNP
QSPmMF 0 RVF TJHOJmDB RVF VNB BQMJDBÎÍP EFTFOWPMWJEB QBSB
.*%1OÍPTFSÍPTVQPSUBEBTQPSEJTQPTJUJWPTRVFOÍPJNQMF
NFOUBNFTTFQSPmMF
$PN P TVSHJNFOUP EF TNBSUQIPOFT F P BVNFOUP EP QPEFS EF
QSPDFTTBNFOUPEPTDFMVMBSFTBTBQMJDBÎÜFTQBSBEJTQPTJUJWPTNØ
WFJTmDBSBNDBEBWF[NBJTTPmTUJDBEBTFWJTVBMNFOUFBUSBUJWBT
*TTPDSJPVDFSUBEFTWBOUBHFNEP+BWB.&RVFKVTUBNFOUFQPS
TFSJOEFQFOEFOUFEFQMBUBGPSNBOÍPHFSBWBJOUFSGBDFTHSÈmDBT
UÍPCPOJUBT4FOEPBTTJNP+BWB.&BQFTBSEFBJOEBTFSVNB
BMUFSOBUJWBQBSBBJOEÞTUSJBBDBCPVQFSEFOEPVNBCPBQBSUFEF
TFVNFSDBEPQBSBPEFTFOWPMWJNFOUPEFBQMJDBÎÜFTVTBOEPQMBUB
GPSNBTOBUJWBTEPTDFMVMBSFTDPNPQBSB*1IPOFFQBSB"OESPJE
11
: : www.mundoj.com.br : :
Android
Android não poderia ser uma alternativa de plataforma operacional 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 projeto 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 dispositivos móveis, adquire Android Inc com todos os seus engenheiros (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 dispositivos 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 opensource. 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:
t "OESPJEMBOÎBEPFNGFWFSFJSPEF
t "OESPJE$VQDBLFMBOÎBEPFNNBJPEF
t "OESPJE%POVUMBOÎBEPFNTFUFNCSPEF
t "OESPJE&DMBJSMBOÎBEPFNUFNQPSFDPSEFPVUVCSP
de 2009)
t "OESPJE'SP:PMBOÎBEPFNNBJPEF
t "OESPJE(JOHFSCSFBEMBOÎBEPFNEF[FNCSPEF
t "OESPJE)POFZDPNCNPTUSBEPOB$&4
xFYDMVTJWP
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 runtime. A camada seguinte é o framework de aplicação. E no topo da
pilha estão as aplicações propriamente ditas. Em termos de arquitetura, 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.
Em meados de 2010, a Oracle acionou o Google na justiça americana 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 à imprensa: “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 infiringe o Copyright do Java da Oracle America e a Google não está
licenciada para isso.”
12
Figura 1. Pilha de softwares da plataforma Android (retirada de http://developer.android.com/
guide/basics/what-is-android.html)
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 importante para a comunidade, e diz que é uma das melhores formas de
integração e aprendizado. Este episódio causou impacto na comunidade 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
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ódulo 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.
1SPKFUP&DMJQTF
0CKFUJWP
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 requisiçõ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.
TaxiGOAndroid
Projeto Android, para o dispositivo móvel.
Persistência de dados
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, contendo o módulo para desktop.
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.
Tabela 1. Projetos Eclipse.
Por isto, esta parte do módulo poderia ser implementada 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 “objetoexemplo”. A API adiciona nós á query na medida em
que atributos do objeto forem sendo preenchidos.
Figura 2. Sistema Táxi GO.
Para identificar as partes do sistema, descrevemos os módulos
como:
t .ØEVMP$FOUSBMBQMJDBÎÍPRVFDPOUÏNUPEBTBTSFHSBTEFOFgócio e persistência.
t .ØEVMP.ØCJMFBQMJDBÎÍPNØCJMFQBSBPDMJFOUFTPMJDJUBSVNB
corrida.
t .ØEVMP#BDL0GmDF8FCBQMJDBÎÍPXFCQBSBWJTVBMJ[BSBTDPSridas pendentes.
t .ØEVMP#BDL0GmDF%FTLUPQBQMJDBÎÍPEFTLUPQQBSBHFSFODJBmento das corridas.
O EntityManager será injetado nos EJBs que fornecem 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.
13
: : www.mundoj.com.br : :
1FSTJTUÐODJBEFEBEPTFN
1FSTJTUÐODJBEFEBEPTFN
Em 2005, a versão para a API JDBC era a 3.0. Já existiam Em 2006 a Sun lançou uma API oficial, junto com a especificaframeworks de mapeamento objeto-relacional, mas, po- ção do EJB3.0 (JSR-220) chamada JPA. Esta API viria substituir
rém os Entity Beans eram o mais próximo que se tinha de os Entity Beans da versão do EJB2.
mapeamento em uma API padrão.
A partir do lançamento da API, muitos outros frameworks adeAs opções de frameworks para persistência mais elabora- rentes a mesma foram lançados, como OpenJPA e o Toplink,
dos eram Hibernate (versão 2), OJB, os próprios Entity por exemplo. Com o uso de anotações, muitas das configuBeans da especificação EJB 2, entre outros.
rações feitas por XML se tornaram opcionais, aumentando a
produtividade.
Na matéria de 2005, foi escolhido Entity Beans CMP, que
eram Entity Beans gerenciados pelo container. Os Entity Hoje, a API JPA está na versão 2.0 e foi lançada em dezemBeans apresentavam sérios problemas de escalabilidade bro/2009. Muitas funcionalidades como Criteria e Validation
e não suportavam diversos tipos de mapeamento, como foram adicionadas. Criteria permite a construção dinâmica
herança e certos tipos de composição.
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 exemplos 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
Listagem 1. Entidade Corrida.
Para o cenário proposto, foram levantadas apenas três entidades:
Passageiro, Unidade e Corrida. O modelo de dados para o armazenamento 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.
@Entity
@Table(name=”Corrida”)
@XmlRootElement
public 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
}
Figura 3. Modelo de dados para o TaxiGO.
14
Um exemplo de entidade está apresentada na Listagem 1. Analisando 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 é necessária para que a classe seja reconhecida pelo EntityManager como
uma classe de entidade persistente.
Listagem 2. Classe CorridaEJB.
@Stateless
public class CorridaEJB {
@PersistenceContext(unitName=”taxiPU”)
private EntityManager em;
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.
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;
}
}
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.
public void persist(Corrida t){
try{
em.persist(t);
em.flush();
}catch(Exception e){
e.printStackTrace();
}
}
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 Muitospara-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.
public void merge(Corrida t){
try{
em.merge(t);
em.flush();
}catch(Exception e){
e.printStackTrace();
}
}
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 estrutura web (arquivos WAR), e por isto unimos todas as partes do
módulo central em um único projeto web.
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;
}
}
Além disto, a especificação conta com novas anotações, como @
Singleton que faz com que o container garanta apenas uma instâ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.
um pool de objetos que o container gerencia. Nesta classe, anotamos 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
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.
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 objetoexemplo. 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.
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
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"),
15
: : 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 buscados 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.
&+#FN
&+#FN
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.
A evolução dos EJBs se deu em todos os aspectos, desde suas
configurações até o padrão de estruturas de pastas.
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 interface, a EJBHome. Para acesso remoto, deveria extender
EJBObject.
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.
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.
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.
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).
Para ajudar nessa tarefa de configuração, era muito comum o uso da ferramenta o XDoclet. A ferramenta lia tags A criação de uma interface local ou remota passou a ser opdescrita em comentários JavaDoc gerava o código-fonte cional, tornando o session bean praticamente um POJO com
das interfaces local e/ou remota, seguindo um template anotações EJB.
de código definido. Na versão de 2005, esta ferramenta
facilitou na geração das interfaces Local e Remota.
webservices baseados em SOAP, apresentando maior flexibilidade
e facilidade no desenvolvimento. Na arquitetura REST, funcionalidades 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.
Figura 4. Combinando JPA + JAXB + REST.
Poderíamos ter criado uma camada DAO com classes convencionais 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 operaçõ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 Transfer (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
16
'VODJPOBMJEBEF
63*
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
Tabela 2. URIs definidas para os serviços do TaxiGO.
Na Listagem 3 é mostrada a classe CorridaResource, que é responsá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-
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 CorridaEJB 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 chamado pelo verbo PUT, indicado pela anotação @PUT.
Listagem 3. Classe CorridaResource.
@Path(“/corrida”)
@Stateless
public 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”);
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.
}
@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);
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.
O método consultar() foi desenvolvido com o objetivo de possibilitar 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 diretamente 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
corridaservice.persist(corrida);
}catch(Exception e){
e.printStackTrace();
return Response.serverError().build();
}
return Response.ok(corrida).build();
return Response.ok(corrida).build();
}catch(Exception e){
e.printStackTrace();
return Response.serverError().build();
}
}
}
//Outros métodos omitidos
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 parâmetro e passa para o método.
*OUFHSBÎÍPFN
*OUFHSBÎÍPFN
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 informação.
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 realizar o tratamento no XML. E, por isto, escolhemos realizar esta
integração com webservices REST, uma vez que este retorna um
Ao receber essa informação, o método realizava um lookup XML comum ao dispositivo.
para o EJB responsável pela operação, e este convertia em
Desta forma, os clientes do módulo central acessarão todos da
byte array para responder ao cliente.
mesma forma, sem exceção.
Esta conversão para byte[] é direcionada ao cliente móbile. Um XML ou string delimitada poderia ser retornada, Também não é necessário o lookup explícito aos EJBs, pois este
porém algum tratamento da informação seria necessária é injetado diretamente ao recurso REST através da anotação
no cliente. Por exemplo, se retornasse um XML, um parse @EJB. Todo este trabalho, que antes era feito manualmente,
deveria ser realizado, e para isto provavelmente um API passou a ser feito pelo container.
seria utilizada, aumentando assim o tamanho da aplicação
O XML gerado pelo servidor não é mais manipulado pelo
MIDP.
desenvolvedor. A API que implementa a especificação REST
O XML gerado como resposta pelo servidor era monta- converte automaticamente para a classe desejada aumentando
do manualmente, de forma que se formasse uma string a produtividade e reduzindo a complexidade inerente ao tratar
concatenada contendo as tags do XML e os valores das dados em XML.
informações.
Alguns métodos HTTP são “idempotentes” e outros não. Um método é dito idempotente quando
uma requisição causa o mesmo
efeito que várias requisições sucessivas. 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 recurso (consultas).
17
: : 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, escolhemos 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 componentes 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 primefaces 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”)
@RequestScoped
public 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();
}
}
18
Como podemos ver na Listagem 6, a classe é anotada pelas anotações @ManagedBean e @RequestScoped. Estas anotações são
novidades do JSF 2, pois nas versões anteriores do JSF as configurações eram feitas em arquivos XML.
A anotação @ManagedBean indica que a classe é um Bean Gerenciador 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 injetar 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 dataTable 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 header 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 pasTBEBT0QBSÉNFUSPUZQFw):#3*%wJOGPSNBRVFQPEFNPTVUJMJ[BS
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 segundos, é necessário o parâmetro intervalo. Precisamos informar també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.
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 atraentes para uma aplicação direcionada a dispositivos móveis.
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 aplicação do celular contém apenas uma tela de interface para o usuário onde são realizadas todas as funcionalidades. Uma das funções é comunicar-se com a central,
A comunicação é realizada através do protocolo HTTP, enviando
informações no formato XML para o WebService RestFul disponibilizado no sistema central.
19
: : www.mundoj.com.br : :
Listagem 7. XML recebido pelo sistema central.
<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>
Listagem 6. Classe TaxiGOService, resposável por tratar o
envio e retorno de informações.
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);
Como podemos ver na classe TaxiGOService representada na
Listagem 6, no envio da informação o XML é “montado” concatenando-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 solicitar() 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.
}
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;
}
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 respectiva, 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.
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();
}
O resultado esperado é a resposta do serviço do sistema central.
Como informamos lá no sistema central que os métodos produzem 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.
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>”;
}
20
return parseXML(result);
} catch (Exception e) {
e.printStackTrace();
Log.d(“ErroTaxiGOService”, e.getLocalizedMessage());
}
return null;
}
return ret;
Desenhando a interface
O desenvolvimento de interfaces gráficas no Android é feito através de um padrão XML. Com este XML, o compilador gera uma
classe de onde é possível acessar os componentes da tela. Utilizamos 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 <AbsoluteLayout>. 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 somente 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 !” é desabilitado. 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 informar 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ç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>
1SJODJQBJTEJGFSFOÎBTFOUSFBTBQMJDBÎÜFTNØCJMF
+.&FN
"OESPJEFN
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 é muito bonita.
A classe Activity é a principal da
aplicação e representa uma interface gráfica. Ela é indicada no arquivo
AndroidManifest.xml. A aplicação
funciona apenas em celulares com
sistema operacional Android e posPara a transferência de dados, é sui uma interface mais rica.
acessado um Servlet através da API
Conector, e array de bytes é trafega- Para transferência de dados, é acesdo sob o protocolo http.
sado um web service REST que direciona a requisição para o método
de um EJB.
21
: : www.mundoj.com.br : :
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.
Na Listagem 9, podemos analisar o método onLocationChanged(). 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 quantos 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.
Listagem 9. Método onLocationChanged() da classe Listener, 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);
}
}
Módulo gerencial
O módulo gerencial é composto por uma aplicação Swing,
cujo objetivo é gerenciar as corridas solicitadas pelos clientes. 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 passageiro recebe a informação de que a unidade escolhida pelo
atendente o atenderá.
Inicialmente, o módulo deve acessar o sistema central, solicitando 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 ar22
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 é transferida 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 atualizada.
A Listagem 10 mostra o código que recupera as informações de
corridas pendentes. Para acessar o módulo central, utilizamos classes que pertencem a lib jersey-client.jar, criada para encapsular a
conexão a um Resource REST. A classe WebResource, do pacote
Listagem 10. Arquivo JNLP para o módulo desktop.
<?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>
Listagem 11. Listando as corridas pendentes.
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 (Corrida[]), no caso do método get, devemos informar para que tipo será
convertida as informações do XML no parâmetro da chamada.
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 melhor 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 JavaFX 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 dispositivos 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 complexidade. Essas complexidades são absorvidas pela própria plataforma, e isto a torna uma tecnologia completa, robusta e confiável.
Referências
t
t
t
t
t
t
Figura 7. Gerenciador de corridas desktop.
t
t
t
t
IUUQ
IUUQCMPHTPSBDMFDPNUIFBRVBSJVNFOUSZNPSF@KBWB@FF@@DPOUFOU
IUUQCMPHTPSBDMFDPNUIFBRVBSJVNFOUSZKBWB@FF@@IBT@CFFO
IUUQXXXIJCFSOBUFPSHBCPVUIJTUPSZIUNM
IUUQEFWFMPQFSBOESPJEDPNHVJEFJOEFYIUNM
IUUQNFJPCJUDPNPSBDMFQSPDFTTBHPPHMFQPSDBVTBEFBO
ESPJEFKBWB
IUUQEPDTKCPTTPSHIJCFSOBUFFOUJUZNBOBHFSSFGFSFODFFOIUNM
DPOmHVSBUJPOIUNM
IUUQXXXHSPLMBXOFUQEG0SB(PPHMFQEG
IUUQKBWBGSFFVPMDPNCSXJLJKBWBGY
IUUQXXXHVKDPNCSKBWBKBWBBTBMUFSBDPFTBQSPWBEBT
IUUQFOXJLJQFEJBPSHXJLJ+BWB@8FC@4UBSU
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.
23
Download