Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Feedback
Artigo no estilo Soluo Completa eu
s
D
sobre e
[ Alexandre Arcanjo de Queiroz e Felipe Pierin ]
s
ta
edio
Artigo no estilo Soluo Completa, Artigo no estilo Curso
48 Java EE 7: desenvolvendo aplicaes batch Parte 2 D seu feedback sobre esta edio!
[ Jefferson S. de Araujo ]
A Java Magazine tem que ser feita ao seu gosto.
Para isso, precisamos saber o que voc, leitor, acha
da revista!
Contedo sobre Boas Prticas D seu voto sobre esta edio, artigo por artigo, atra-
vs do link:
64 Introduo a linguagem Clojure
www.devmedia.com.br/javamagazine/feedback
[ Plnio Balduino ]
Em Java, esta caracterstica somente est presente a partir da instncias diferentes e at certo ponto com verses diferentes do
verso 5.0. mesmo SGBD. O mesmo tambm acontece com classes de interao
Analogamente, o princpio da contravarincia diz que os par- com o usurio. Uma classe de Janela no Windows diferente de
metros dos mtodos em A devem ter limites iguais ou maiores uma classe de Janela no Linux.
que os de B, ou seja, supondo que o mtodo m1() em B possua Uma das grandes vantagens da linguagem Java nos distanciar
um parmetro com valores variando entre 0 e 10, o mtodo m1() destas peculiaridades, dando um grau de reutilizao para estas
em A pode funcionar recebendo valores entre -5 e 15 (intervalo classes prximo das classes do domnio de base.
de m1() em A contm o intervalo de m1() em B), mas no pode- O domnio de negcio compreende as classes de um negcio
ria deixar de funcionar para valores dentro do intervalo de 0 a especificamente. So classes do contexto do software sendo desen-
10 (se o intervalo de m1() em A fosse entre 5 e 9 por exemplo, ao volvido. Por exemplo, em um sistema hospitalar, temos as classes
substituir uma instncia de B, uma instncia de A falharia ao Medico e Paciente. Em um sistema de trfego areo, Aeronave
receber o valor 3). e Pista. Estas classes tm bastante utilidade em aplicaes dife-
Tendo os conceitos bsicos mais aprofundados, possvel de- rentes, contanto que no mesmo domnio. Podem ser de atributo,
senvolver classes de forma mais confivel, melhorando significa- quando existem para representar um dado, como Matrcula, que
tivamente a estabilidade do sistema como um todo. representaria o nmero de matrcula do Aluno, de papel, como
Entretanto, para que o design geral do sistema conserve caracte- Aluno e Professor, ou de relacionamento, como Inscricao, que
rsticas prprias para facilitar a manutenibilidade e o reuso, uma define o relacionamento de um Aluno inscrito em uma Turma.
anlise mais detalhada sobre domnios de classes deve ser levada As classes compreendidas no domnio de aplicao so es-
em considerao, o que feito no prximo tpico. pecficas para cada aplicao. Sua reutilizao baixa, ficando
restrita a aplicao sendo construda. So classes reconhecedoras
Domnios de classes de objetos de eventos, como para monitorar colises entre aeronaves, e ge-
Agora que foram vistos os aspectos que permeiam a definio renciadoras de eventos, que tomam aes como modificar a rota
de uma classe, importante examin-las do ponto de vista de sua de uma aeronave no caso de rotas que levem a uma coliso. Em
finalidade, ou seja, qual o papel que elas desempenharo no sis- um software de monitorao de espao areo, Aeronave poderia
tema. Sem o correto entendimento do papel a ser desempenhado, ser uma classe do domnio de negcio e poderia ser reutilizada
poderemos incorrer em erros comuns, que podem prejudicar o em um software de manuteno de aeronaves, mas neste caso as
entendimento, a manutenibilidade e principalmente comprometer classes do domnio de aplicao no fariam sentido.
o reuso. Alguns erros comuns sero apresentados mais adiante.
As classes, de acordo com sua finalidade, podem ser categori- Coeso
zadas em domnios diferentes. Os chamados domnios de classes Muitas vezes ouve-se dizer que as classes devem ter alta coeso
so: base, arquitetura, negcio e aplicao, e sero apresentados e baixo acoplamento (assunto explorado mais adiante). Uma classe
a seguir. com baixa coeso apresenta mtodos e atributos dispersos, que
As classes no domnio de base so aquelas que, em geral, encon- no so caractersticos especificamente da abstrao sendo defi-
tramos na linguagem de programao. So classes fundamentais, nida. Por exemplo, no faz sentido colocar na classe Matricula o
como Boolean e Integer, classes estruturais como ArrayList e TreeMap mtodo criarTurma().
ou classes mais ricas semanticamente, como Calendar e Locale, Neste tpico so abordados problemas decorrentes de um design
que apesar disso so altamente reutilizveis e independentes com baixa coeso, gerando, muitas vezes, um alto acoplamento.
da arquitetura, negcio ou aplicao. Podem estar presentes na Geralmente estes problemas so de fcil percepo, no entanto
linguagem de programao, ser incorporadas atravs de biblio- h casos sutis que merecem ateno para ilustrar como a busca
tecas externas, como a Commons Collections, ou produzidas por uma alta coeso pode ser traioeira se no for prestada a
pelos prprios desenvolvedores de software, para auxili-los no devida ateno. Um exemplo o caso de um desenvolvedor que
desenvolvimento. recebe por hora trabalhada e um desenvolvedor que recebe um
As classes no domnio de arquitetura tm tambm alta reu- salrio fixo. Se for colocada na classe Desenvolvedor o mtodo
tilizao, mas esto restritas para uma arquitetura especfica. getSalario(double horas), o desenvolvedor com salrio fixo ter
Por exemplo, as classes de comunicao entre mquinas podem um mtodo que no lhe serve. Para este, um mtodo mais cab-
operar sobre caractersticas fsicas das mquinas para as quais vel seria getSalario(), que por sua vez no teria utilidade para o
foram destinadas. Dentro de uma mesma srie de mquinas, estas desenvolvedor com salrio varivel.
classes so reutilizveis, mas podem ser incompatveis com outra Esta coeso chamada de coeso de instncia mista, onde a
srie de mquinas. classe tem algumas caractersticas que so indefinidas para alguns
Assim tambm pode acontecer com as classes de manipulao objetos. Neste caso, geralmente a soluo refinar melhor a hierar-
de banco de dados, visto que as classes destinadas para trabalhar quia, retirando os provveis ifs na classe afetada. Criar subclas-
diretamente com Oracle so diferentes das classes destinadas a ses (DesenvolvedorSalarioFixo e DesenvolvedorSalarioVariavel,
trabalhar com MySQL, mas ambas podem ser reutilizadas com neste caso) pode solucionar o problema. Uma soluo mais flexvel
A alta coeso leva a interfaces bem definidas. Um exemplo comum o nome diz, utilizada quando a pessoa que deseja contrair um
de uma baixa coeso a famosa classe Util (ou Utilitario ou Utils) emprstimo uma pessoa fsica. A regra do banco nesta situao
presente em vrios sistemas. Estas classes normalmente agrupam diz que o emprstimo aceito se o rendimento em conta for maior
mtodos que no tm a ver um com o outro e esto juntos ape- que 10.000 Reais. Para AvaliacaoEmprestimoPessoaJuridica, a
nas porque no se sabia onde deveriam estar. Como j foi dito, regra do banco diz que necessrio ter um rendimento de, no
a interface de uma classe deve definir um comportamento e, no mnimo, 50.000 Reais. Esta herana soluciona o problema at o
caso destas classes, no se tem mtodos compatveis em termos momento em que a estratgia do banco determine que pessoas
de funcionalidade e finalidade. jurdicas com menos de dois anos devem passar pela mesma
Ao criar esta classe, a princpio inofensiva, o desenhista acopla avaliao que uma pessoa fsica. Neste ponto, h duas solues
diversas partes do sistema. Assim, uma mudana nesta classe atravs de herana:
pode acabar levando inconsistncias a outros mdulos. Conse- 1- Criar duas subclasses de AvaliacaoEmprestimoPessoaJuridica,
quentemente, em pouco tempo no se sabe mais se um mtodo uma para pessoas jurdicas com menos de dois anos e outra para
pode ser modificado, pois no se sabe mais em que partes do pessoas jurdicas com mais de dois anos. O problema desta soluo
cdigo ele est sendo utilizado. a duplicao de cdigo entre AvaliacaoEmprestimoPessoaFisica
O alto acoplamento tambm pode ser entendido atravs deste e a subclasse para pessoas jurdicas com menos de dois anos;
exemplo: O mdulo X modificado, levando a uma modificao 2- Criar uma subclasse de AvaliacaoEmprestimoPessoaFisica
na classe Util, que leva a uma modificao no mdulo Y ou causa para empresas iniciantes, com menos de dois anos. O problema
um erro no mesmo. Alm deste tipo de problema, classes altamente aqui que empresas iniciantes no se comportam como pessoas
acopladas tendem a alterar o estado de partes diferentes do sistema, fsicas. Alm disso, espera-se que uma modificao em Avalia-
podendo causar modificaes imprevisveis primeira vista. So caoEmprestimoPessoaJuridica impacte em todas as avaliaes
aqueles famosos efeitos colaterais que aparecem em uma parte do de pessoas jurdicas.
sistema que a princpio no tem relao com o que foi alterado.
Quando isto acontece, os mdulos X e Y esto acoplados. Pelo princpio do reuso por composio, a soluo simples e
O acoplamento facilmente identificvel quando h um atributo bastante flexvel. Criar uma interface Avaliacao com o mtodo
de uma classe do mdulo Y em X ou vice-versa. Porm, um objeto avaliar(). Classes que implementam esta interface so respons-
tambm pode estar acoplado por necessitar de dados ou alterar veis por uma avaliao, independentemente da pessoa avaliada
dados em outros. Este ltimo caso costuma ser mais prejudicial, ser fsica ou jurdica. Seguindo o princpio do reuso por compo-
pois a execuo de um mtodo no modifica unicamente aquela sio, uma classe AvaliacaoBaixoRendimento implementaria a
instncia, mas altera outras partes do sistema, podendo gerar os concesso do emprstimo com rendimento acima de 10.000 Reais
indesejados efeitos colaterais. Um princpio que trata especifica- e a classe AvaliacaoAltoRendimento implementaria a concesso
mente deste problema a Lei de Demeter (veja a seo Links). com rendimento acima de 50.000 Reais.
Segundo este princpio, um mtodo m() de um objeto O deve Assim, todas as subclasses continuam herdando de Avaliacao-
modificar primariamente: Emprestimo e cada subclasse referencia a implementao da
1. Atributos de O; interface Avaliacao que faz a avaliao correta no seu contexto.
2. Parmetros de m(); Com isso, pouco impacto haveria no caso de novas frmulas de
3. Objetos criados em m(); avaliao e estratgias de fornecimento de emprstimos serem
4. Componentes diretos de O. definidas pelo banco, alm da vantagem de permitir a troca da
frmula de avaliao em tempo de execuo.
Desta forma, o impacto da chamada de um mtodo fica restrito A questo da conformidade de tipo sempre uma das mais
a um escopo esperado. importantes a ser observada. Definir novas classes significa, alm
O princpio do reuso por composio (veja a seo Links) de abstraes e comportamento, a definio de novos tipos no
provavelmente um dos mais debatidos dentre os princpios de sistema. Observar esta questo torna os sistemas mais robustos e
design mais importantes. Heranas no sistema surgem das mais confiveis e produz classes com maior capacidade de reuso, que
variadas formas. O principal problema da herana a falta de uma das grandes vantagens da orientao a objetos.
flexibilidade (vide discusso sobre conformidade de tipo). Uma Um princpio muito importante nesta questo o princpio da
herana entre duas classes implica em dizer que uma se comporta substituibilidade, tambm conhecido como princpio da substi-
como outra. Portanto, criar subclasses com o intuito de reutilizar tuio de Liskov (veja a seo Links). O enunciado deste princpio
cdigo muitas vezes no o aconselhvel. Para ilustrar o pro- simples. Se para cada instncia o1 do tipo S existe uma instncia
blema, suponha que em um sistema bancrio haja uma classe o2 do tipo T tal que para todos os sistemas P definidos em termos
AvaliacaoEmprestimo responsvel por avaliar se uma pessoa de T o comportamento de P se mantm inalterado quando o1
pode contrair um emprstimo. Esta classe tem duas subclasses: trocado por o2, ento S subtipo de T.
AvaliacaoEmprestimoPessoaFisica e AvaliacaoEmprestimoPes- As implicaes deste princpio so diversas. A mais simples
soaJuridica. A classe AvaliacaoEmprestimoPessoaFisica, como de ser detectada se imaginarmos o que acontece quando este
Peter P. Lupo Artigo original no qual Barbara Liskov apresentou o princpio que herdou seu
peter@pplupo.com http://www.pplupo.com nome.
analista de sistemas (nfase em Engenharia de Software) na http://www.cs.iastate.edu/~hridesh/teaching/362/07/01/papers/p50-liskov.pdf
Petrobras, bacharel em Cincia da Computao pela UFRJ, mes-
trando em Engenharia de Software na rea de processos e qualidade de Livros
software na COPPE/UFRJ, Oracle Certified Associate Java SE 5/SE 6, Certified Fundamentals of Object-Oriented Design in UML, Meilir Page-Jones, Addison-
ScrumMaster, implementador credenciado de processos de engenharia de software segundo Wesley / Prentice Hall, 1999
o modelo de referncia MPS.BR, membro da instituio implementadora de melhoria de Livro que introduz UML e apresenta, em seguida, conceitos fundamentais de design orientado
processos de software Implementum. Possui experincia com desenvolvimento, anlise, a objetos de forma simples e direta.
projeto orientado a objetos utilizando Java e UML entre outras tecnologias, gerncia de
projetos, processos e metodologias de desenvolvimento de software, mtodos geis
e tecnologias Java. Fornece consultoria e treinamento em desenvolvimento utilizando Voc gostou deste artigo?
tecnologias Java e frameworks relacionados, UML, engenharia de requisitos e outras reas
da engenharia de software j tendo lecionado para vrias turmas incluindo alunos de gra-
duao, mestrado, doutorado e profissionais do mercado desde 2004 alm de consultoria D seu voto em www.devmedia.com.br/javamagazine/feedback
para melhoria de processos de software. Mantm um blog de Engenharia de Software em Ajude-nos a manter a qualidade da revista!
http://craftnicely.pplupo.com.
O
Apache Hadoop vem sendo, nos ltimos anos, Fique por dentro
o grande nome na computao moderna. Dis-
ponibilizando solues para tratar dados que Este artigo ir abordar a ferramenta Apache Hive, um Data Warehouse
antes, devido sua complexidade e escala, eram sim- criado com base no Apache Hadoop, demonstrando exemplos de seu
plesmente descartados, essa ferramenta da Apache j uso para manipular dados atravs da linguagem HiveQL e, tambm, da
foi adotada por diversos gigantes da informtica, como sua utilizao dentro de uma aplicao Java.
Yahoo, eBay e Facebook. Esse tema til para desenvolvedores que tenham interesse em ferra-
Com o avano dos requisitos e o amadurecimento das mentas para manipulao e tratamento de informaes em grande escala,
implementaes do Hadoop nessas empresas, surgiu, de visando uma melhor performance e facilidade no manuseio de dados.
dentro de uma delas, a primeira verso do Apache Hive. Alm disso, programadores que tenham interesse em conhecer solues
Introduzido pelo Facebook em 2009, o Apache Hive foi para diminuir a complexidade das tarefas dentro do Apache Hadoop,
concebido com a ideia de construir uma aplicao de sem perder as vantagens da utilizao do Map/Reduce, encontraro uma
Data Warehouse open source, que utilizasse conceitos alternativa fcil e eficiente na ferramenta Apache Hive.
do Hadoop, como Map/Reduce e HDFS, para manipular
e armazenar dados.
Explicando um pouco o conceito dessa categoria de Esses pontos, por sua vez, foram as principais preocupaes
aplicaes, softwares de Data Warehouse so respon- na implementao do Hive que, alm disso, buscou diminuir a
sveis por armazenar dados de diversos sistemas em complexidade e a curva de aprendizado da utilizao das funcio-
um repositrio nico onde, atravs de transformaes nalidades do Hadoop atravs da linguagem HiveQL, permitindo
das informaes que so enviadas por suas interfaces seu uso por desenvolvedores que no possuem conhecimento
de acesso, esse contedo formatado de acordo com extenso da plataforma de Map/Reduce, com um cdigo intuitivo
um padro especfico de armazenagem definido para e mais prximo do SQL.
utilizao no sistema em questo. O objetivo de nosso artigo ser, portanto, demonstrar as prin-
Como exemplo dessas aplicaes, temos os bancos de cipais caractersticas dessa linguagem e ferramenta, sua relao
dados relacionais, como o MySQL, sistemas de indexa- com o Apache Hadoop e criar um exemplo de aplicao em Java
o, como o Apache Solr, bancos de dados no relacio- capaz de se comunicar com a base de dados do Hive e manipular
nais, como o MongoDB, entre outros. Cada um desses seu contedo.
sistemas apresenta solues mais customizadas para
determinadas situaes, porm tentam sempre manter Principais conceitos do Hadoop
o foco em alguns pontos principais como escalabilidade, Antes de iniciarmos nossa discusso sobre o Apache Hive, ne-
performance, usabilidade e confiabilidade. cessrio entendermos alguns conceitos bsicos do Apache Hadoop.
Nota
Tanto o Apache Hive como o Apache Hadoop, que utilizaremos em nosso exemplo, no possuem Com essas modificaes feitas, podemos iniciar o Apache
compatibilidade com a plataforma Windows. Isto se deve, principalmente, ao fato de tanto os Hive. Para garantir que a instalao ocorreu com sucesso, va-
processos de Map/Reduce como o prprio princpio do HDFS se basearem na plataforma UNIX e mos, em primeiro lugar, acessar o mesmo pela linha de coman-
no terem sido desenvolvidos para outros ambientes. Devido a isso, todos os comandos e exemplos do e verificar se o Hive Console est funcionando corretamente
demonstrados a seguir foram baseados em um ambiente Linux. e se nenhum erro de configurao aconteceu.
Esse processo composto pela criao das tabelas dentro do de clusters computacionais, e ORC, tipo de arquivo otimizado
Apache Hive, metadados que relacionam os arquivos armazena- para armazenamento de dados dentro do Hive. Cada um desses
dos no Hadoop com uma organizao semelhante de uma tabela tipos apresenta vantagens e desvantagens na sua utilizao, sendo
relacional, e a leitura das informaes, que sero armazenadas cada um mais adequado para situaes especficas. Fica a critrio
dentro dos diretrios do Hive num formato que definiremos do leitor experimentar esses diferentes tipos de armazenamento
adiante. de dados na tabela, sendo somente necessrio modificar o tre-
A Listagem 5 apresenta a classe HiveCreate, responsvel por cho STORED AS TEXTFILE para o tipo de dados que deseja
criar e armazenar os dados conforme descrevemos anterior- utilizar.
mente e por apresentar algumas variaes das funcionalidades Uma vez criada nossa tabela ratings, temos que carregar os
disponibilizadas pela HiveQL para a criao das tabelas dentro dados do arquivo ratings.dat para o Hive. Isto feito no segundo
de nosso Hive. comando executado, LOAD DATA LOCAL INPATH, onde
Vamos agora entender os mtodos descritos na classe Hive- passamos o caminho local de nosso arquivo para que ele seja
Create. O primeiro deles, denominado createRatingsTable(), carregado e escrito, ou sobrescrito, caso j existam dados, em
ser responsvel por, a partir de nosso arquivo ratings.dat que nossa tabela. necessrio, antes da execuo do mtodo, que
baixamos anteriormente, criar a tabela ratings, com os campos esse local de armazenamento do arquivo seja alterado de acordo
userid, itemid, rating e timestamp. A sintaxe de criao dessa tabela com o caminho em que o arquivo ratings.dat foi descompactado
bastante similar sintaxe de criao de uma tabela relacional em sua mquina.
utilizando a linguagem SQL tradicional, com a diferena que, em Nosso segundo mtodo, createRatingsBucketed(), ter a funo
nossa tabela do Hive, definimos que nosso delimitador de campos de criar uma segunda tabela, denominada ratings_bucketed.
o smbolo : e, tambm, especificamos o modo que os dados A definio de seus campos bastante semelhante da tabela
de nossas tabelas sero armazenados no HDFS. No nosso caso, ratings, porm utilizamos duas novas funcionalidades do Hive
definimos o armazenamento em formato de TEXTFILE, ou seja, em sua criao: PARTITION e BUCKETING.
um arquivo texto padro. O comando PARTITIONED BY (ds STRING), utilizado em
O Apache Hive tambm disponibiliza, para o armazenamento nossa HiveQL, tem a funo de criar um campo String que
de suas informaes, outros formatos, como o SEQUENCEFILE, servir para indicar os nomes (ou valores) das parties de
arquivo especfico do Hadoop em forma de chaves e valores, o nossa tabela e, consequentemente, dividir os dados inseridos
RCFILE, formato de arquivo que define tabelas relacionais dentro nessas parties.
armazenado no HDFS e administrado pelo Hive, mostrando Iniciamos esse select definindo que nossa partio ter o valor
algumas funcionalidades teis que o Hive nos proporciona e do campo ds = 1, ou seja, a partio que especificamos na cria-
apresentando a sintaxe necessria para poder filtrar e visualizar o da tabela, e continuamos com a consulta normalmente. Uma
as informaes do HDFS. consulta em uma tabela clusterizada apresenta vrias vantagens
Iniciamos nossa classe HiveSelect declarando um mtodo sim- em relao a uma tabela normal, principalmente quando partimos
ples, que ir criar uma consulta para verificar a quantidade de de uma configurao do Hive de forma distribuda. Isto se deve
dados dentro de nossa tabela ratings. A sintaxe nessa primeira porque, em um ambiente distribudo, o Apache Hive distribui suas
query idntica de um SQL tradicional utilizado em bancos tarefas de Map/Reduce pelos buckets configurados, ficando mais
de dados relacionais, fazendo um SELECT com a contagem de eficiente a consulta paralelizada. Outro ponto que tambm vale
dados de retorno. Como resultado de nossa consulta, o mtodo destacar que, em consultas onde o campo de filtro o mesmo da
retorna um ResultSet igual ao retornado por qualquer consulta clusterizao da tabela, no nosso caso o campo userid, o tempo
JDBC, podendo esse ser manipulado da mesma maneira que um de processamento bem menor, uma vez que o Hive j sabe em
ResultSet de um banco de dados tradicional. qual cluster deve procurar.
O nosso segundo mtodo, simpleExplainSelect(), j utiliza a Por ltimo, utilizamos o mtodo selectWithJoin() para demons-
funcionalidade do Hive denominada explain. Sua funo de, trar como aplicar uma operao de join em duas tabelas do Hive.
a partir de uma query em HiveQL, mostrar quais as aes que o Neste caso, utilizamos a tabela ratings e ratings_bucketed, fina-
Hive executou dentro do Hadoop para fazer a consulta, retornando lizando assim a nossa aplicao de exemplo. Para executarmos as
em seu ResultSet uma explicao de todas as tarefas de Map/ consultas criadas na classe HiveSelect podemos rodar o mtodo
Reduce executadas sobre nossos arquivos. Em nosso exemplo, main() implementado no final da Listagem 6.
usamos a query do primeiro mtodo, simpleSelect(), e colocamos
o comando explain no incio da mesma, indicando que esperamos Limitaes e consideraes importantes
a explicao dos comandos executados. Uma vez apresentadas as principais funcionalidades do Apache
No prximo mtodo, selectWithBucketedTable(), criamos um Hive e seu funcionamento em geral, precisamos ressaltar alguns
select na tabela particionada e clusterizada ratings_bucketed. pontos para que os desenvolvedores e leitores possam melhor
src/main/webapp/WEB-INF, conforme apresentado na Listagem 2. aguardar alguns milissegundos e logar outra mensagem. O cdigo
Essa configurao responsvel por fazer a inicializao do dessa classe pode ser visto na Listagem 4.
servlet do Spring. Alm disso, vamos criar uma classe anotada com @Controller
Esse arquivo de configurao define um servlet com o nome no Spring MVC, para que possamos acess-la via uma URL.
mvc-dispatcher, cuja classe a DispatcherServlet, e que deve ser O cdigo dessa classe mostrado na Listagem 5.
inicializado juntamente com a aplicao. O spring-mvc segue um
padro de nomenclatura em que seu arquivo de configurao Listagem 4. Cdigo da classe SimpleTask.
deve se chamar <servletname>-servlet.xml, o que no nosso caso
package br.com.javamagazine.spring4demo.concurrency;
mvc-dispatcher-servlet.xml. Sendo assim, crie um arquivo com esse
nome na mesma pasta WEB-INF e com o contedo apresentado import java.util.logging.Logger;
na Listagem 3.
public class SimpleTask implements Runnable {
<web-app xmlns=http://xmlns.jcp.org/xml/ns/javaee
private Logger logger = Logger.getLogger(SimpleTask.class.getName());
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd public SimpleTask(int index) {
version=3.1> this.index = index;
}
<servlet>
<servlet-name>mvc-dispatcher</servlet-name> @Override
<servlet-class>org.springframework.web.servlet.DispatcherServlet public void run() {
</servlet-class> logger.info(Starting task + index);
<load-on-startup>1</load-on-startup> try {
</servlet>
Thread.sleep(50);
} catch (InterruptedException e) {
<servlet-mapping>
e.printStackTrace();
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/*</url-pattern> }
</servlet-mapping> logger.info(Finalizing task + index);
}
</web-app>
}
Listagem 3. Configurao do arquivo mvc-dispatcher-servlet.xml.
Listagem 5. Cdigo da classe TaskStarter.
<?xml version=1.0 encoding=UTF-8?>
<beans //schemas omitidos> package br.com.javamagazine.spring4demo.concurrency;
O que foi definido nesse arquivo que iremos trabalhar com @Controller
anotaes e que o pacote base no qual o Spring deve procurar por public class TaskStarter {
seus beans o br.com.javamagazine.spring4demo.
@Autowired
private DefaultManagedTaskExecutor taskExecutor;
Concurrency Utilities
O primeiro recurso do Spring 4 que vamos analisar a sua private Logger logger = Logger.getLogger(TaskStarter.class.getName());
integrao com a JSR-236 (Concurrency Utilities). O Spring j
@RequestMapping(value = /startTask, method = RequestMethod.GET)
oferecia recursos de agendamento e execuo de tarefas assn-
public @ResponseBody void start() {
cronas atravs da integrao com o framework Quartz e com as logger.info(Starting tasks);
classes do pacote java.util.concurrent, tais como ExecutorService for(int i = 1; i <= 5; i++) {
e ScheduledExecutorService. Uma vez que as classes da especi- taskExecutor.execute(new SimpleTask(i));
ficao da Java EE estendem essas do Java SE, a estrutura entre }
}
elas bem parecida.
Para exemplificar essa funcionalidade, vamos fazer um demo }
que tem uma tarefa cujo nico papel logar uma mensagem,
Isso demonstra que o Spring realmente est usando o pool cria- Agora que temos um dataSource e um script usado para po-
do pelo WildFly e a especificao de Concurrency Utilities. Essa pular a tabela customer, podemos criar uma classe DAO para
abordagem traz duas grandes vantagens em relao forma como prover servios de acesso a esses dados, conforme apresentado
o pool de threads era configurado anteriormente no Spring: na Listagem 12.
1. A configurao agora fica no servidor de aplicao, facilitando
o dimensionamento do pool em tempo de deployment. Para efeito Listagem 10. Contedo a ser adicionado no arquivo mvc-dispatcher-servlet.xml.
comparativo, at ento essa configurao era feita diretamente no
<bean id=dataSource class=org.springframework.jndi.JndiObjectFactoryBean>
arquivo de configurao do Spring, conforme apresenta o cdigo: <property name=jndiName value=java:jboss/datasources/ExampleDS />
</bean>
<bean id=taskExecutor class=org.springframework.scheduling.concurrent.
<jdbc:initialize-database data-source=dataSource>
Thread-PoolTaskExecutor>
<jdbc:script location=classpath:/initDB.sql/>
<property name=corePoolSize value=5 /> </jdbc:initialize-database>
<property name=queueCapacity value=10 />
Listagem 11. Cdigo do script initDB.sql.
</bean>
DROP TABLE customer IF EXISTS;
2. A criao e gerenciamento das Threads passa a ser de respon-
CREATE TABLE customer (
sabilidade do container, o que o grande propsito da especifi- id INT PRIMARY KEY,
cao. name VARCHAR(60)
);
Apesar dessas vantagens, vale ressaltar que o Spring ainda
INSERT INTO customer VALUES(1, John);
pode ser configurado da maneira antiga, o que til em ambien- INSERT INTO customer VALUES(2, Mary);
tes em que um servidor compatvel com a Java EE 7 no esteja INSERT INTO customer VALUES(3, Peter);
disponvel.
Listagem 12. Cdigo da classe CustomerDAO.
bendo requisies HTTP e @ResponseBody indica que o retorno public List<Customer> findAll() {
do mtodo deve ser usado diretamente no response do HTTP. Essa return jdbcTemplate.query(Select id, name from customer,
ltima anotao requerida porque por padro os mtodos de um new CustomerMapper());
}
Controller retornam o nome da pgina que ser exibida.
Antes de prosseguirmos com a criao dos servios REST, vamos public Customer findById(int id) {
try {
criar uma tabela no banco de dados e usar o Spring para acess-la,
return jdbcTemplate.queryForObject(Select id, name from
atravs de uma simples classe DAO. Esta classe, alm de ser usada customer where id = ?, new CustomerMapper(), id);
pelos servios REST para que estes possam acessar o banco de da- } catch (EmptyResultDataAccessException e) {
return null;
dos, tambm servir de base para o exemplo de suporte do Spring 4 }
ao Java 8. Dito isso, o primeiro passo adicionar o contedo da }
Listagem 10 no arquivo mvc-dispatcher-servlet.xml.
private static final class CustomerMapper implements RowMapper<Customer> {
Ao invs de criarmos um DataSource, no exemplo utilizamos
um que provido por padro pelo WildFly. Ele usa um banco @Override
de dados embarcado, que apesar de no ser recomendado para public Customer mapRow(ResultSet rs, int pos) throws SQLException {
return new Customer(rs.getInt(id), rs.getString(name));
ambientes de produo, atende perfeitamente o nosso cenrio }
de teste. Continuando com a configurao do Spring, a tag
jdbc:initialize-database executa o script initDB.sql (Listagem 11), }
@RequestMapping(/customer)
Listagem 13. Cdigo da classe Customer. public List<Customer> findAll() {
return customerDAO.findAll();
package br.com.javamagazine.spring4demo.rest; }
package br.com.javamagazine.spring4demo.rest;
Com nossa camada de acesso a dados pronta, podemos prosse-
import java.util.List;
guir com a criao dos web services. Considerando a verso 3.x
do Spring, o cdigo apresentado na Listagem 14 necessrio para import org.springframework.beans.factory.annotation.Autowired;
a criao de um web service REST. import org.springframework.web.bind.annotation.*;
Repare que fizemos uso das anotaes @Controller e @Respon-
@RestController
seBody. Porm, ao invs usarmos elas, com o Spring 4 podemos
@RequestMapping(/rest)
aplicar a @RestController, que nada mais que uma anotao public class CustomerWS {
de convenincia, conforme podemos verificar no cdigo exposto
na Listagem 15. @Autowired
private CustomerDAO customerDAO;
Ela anotada com ambas as anotaes que citamos anteriormen-
te, @Controller e @ResponseBody, o que significa que ao anotar @RequestMapping(/customer)
uma classe com ela, no necessrio informar nenhuma dessas public List<Customer> findAll() {
outras duas anotaes. Com isso, podemos refatorar o web service return customerDAO.findAll();
criado na Listagem 14 para usar a anotao @RestController. }
Acessando web services REST Veremos a seguir exemplos abordando os dois cenrios, comean-
As melhorias introduzidas no Spring 4, no que diz respeito a web do pelo uso da classe Future, conforme apresenta a Listagem 19.
services REST, no so somente para criao dos mesmos, mas A assinatura do mtodo getForEntity() a mesma do mtodo
tambm para acess-los. Mesmo nas verses anteriores, o Spring j getForObject() do exemplo da Listagem 17, recebendo a URL
fornecia uma classe de convenincia bastante til, chamada Rest- do servio, o objeto para o qual a resposta deve ser convertida e
Template, que abstrai toda a parte de comunicao e converso da os parmetros da invocao do web service. Quando o mtodo
resposta para o objeto desejado. Podemos ver um exemplo dessa get() invocado no objeto futureCostumer, a Thread corrente
classe sendo utilizada no cdigo exibido na Listagem 17. fica aguardando at que a resposta esteja pronta, j que ela est
sendo processada assincronamente. O objeto retornado pelo
mtodo get() do tipo ResponseEntity<Customer>, que possui
Listagem 17. CustomerWSClientSync Exemplo de uso da classe RestTemplate.
um conjunto de mtodos para obter informaes da resposta
package br.com.javamagazine.spring4demo.rest; da invocao do web service, tais como getStatusCode(), que
devolve o cdigo HTTP associado, e getBody(), que devolve a
import java.util.logging.Logger;
resposta propriamente dita j convertida para o objeto desejado.
import org.springframework.beans.factory.annotation.Autowired; Para que esse cdigo funcione, precisamos declarar um bean do
import org.springframework.web.bind.annotation.*; tipo AsyncRestTemplate no arquivo mvc-dispatcher-servlet.xml,
import org.springframework.web.client.RestTemplate;
como demonstra a Listagem 20.
@RestController
public class CustomerWSClientSync { Listagem 19. CustomerWSClientAsyncFuture Exemplo de uso da classe Async-
RestTemplate com Future.
@Autowired
private RestTemplate restTemplate; package br.com.javamagazine.spring4demo.rest;
}
O exemplo mostrado na Listagem 17 no nenhuma novidade,
Listagem 20. Contedo a ser adicionado no arquivo mvc-dispatcher-servlet.xml.
j que a forma sncrona e tradicional que o Spring oferece para
acessar web services REST. A novidade fica por conta da adio <bean id=asyncRestTemplate
da classe AsyncRestTemplate, que fornece o recurso de acessar class=org.springframework.web.client.AsyncRestTemplate />
inegvel que o cdigo fica bem mais enxuto, tornando desne- como parmetros o ResultSet e o rowNumber. Com isso, basta
cessria toda a verbosidade de declarao da classe annima e passarmos this::mapCustomer nos parmetros que necessitam
de seus parmetros. Porm, essa abordagem de criao de classe de uma implementao de RowMapper e o Method References
annima nesse cenrio traz a desvantagem de no podermos cuida do resto.
reutiliz-la em outros mtodos. Por isso, no cdigo original da O Java 8 tem essas e vrias outras novidades que visam tornar a
CustomerDAO definimos a classe interna CustomerMapper e a linguagem mais poderosa e com sintaxe mais enxuta. O leitor que
utilizamos nos mtodos findAll() e finById(). tiver interesse em conhecer as novidades do Java 8 pode buscar
No entanto, mesmo nesse tipo de abordagem o Java 8 oferece mais detalhes na documentao e em outros materiais disponveis
benefcios, atravs do recurso Method References. Um detalhamento na internet e na prpria Java Magazine.
mais profundo desse recurso foge do escopo desse artigo, mas inegvel que o Spring foi e continua sendo um dos frameworks
basicamente ele permite passar um mtodo por parmetro para mais populares da histria do Java. Toda essa popularidade
outro mtodo, no sendo necessrio criar uma classe somente para resultado de um trabalho muito bem feito sempre visando facilitar
esse propsito. O cdigo final da classe CustomerDAO pode ser a vida dos desenvolvedores, atravs de recursos funcionais
visto na Listagem 25. e prticos e da integrao com o restante do ecossistema,
Repare que agora, ao invs de termos a classe interna Customer- como outros frameworks, servidores de aplicao e a prpria
Mapper, temos apenas um mtodo mapCustomer(), que recebe especificao Java EE.
Essa verso 4 mais um importante passo na histria do Spring,
trazendo novas funcionalidades e mantendo o cenrio de se
Listagem 25. Cdigo final da classe CustomerDAO.
integrar facilmente plataforma Java, como por exemplo, ao Java 8
package br.com.javamagazine.spring4demo.rest; e Java EE 7.
import java.sql.ResultSet;
import java.sql.SQLException; Autor
import java.util.List;
Luciano Davoglio Molinari
import javax.sql.DataSource; lucmolinari@gmail.com | @LucMolinari
formado em Processamento de Dados pela Fatec Taquaritinga
import org.springframework.beans.factory.annotation.Autowired; e Ps-Graduado em Engenharia de Software com SOA pelo
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.*;
IBTA/Campinas. Trabalha com Java h sete anos e atualmente atua como
import org.springframework.stereotype.Repository; arquiteto de sistemas no CPqD. Possui as certificaes SCJP, SCWCD, SCBCD
e SCEA e mantm o blog http://lucianomolinari.wordpress.com.
@Repository
public class CustomerDAO {
Links:
private JdbcTemplate jdbcTemplate;
mesmo servidor de aplicao, fica mais rpido identificar qual nosso cdigo. Em seguida adicione o Log4j, que usaremos para
projeto gerou uma exceo ou um erro sistmico atravs do log. imprimir as mensagens de log do sistema, e o Slf4j (Simple Logging
Por isso, o nome do pacote ser br.com.devmedia.pastelaria_on- Facade for Java), que uma fachada para importantes bibliotecas de
line, conforme demonstra a Figura 3. Em seguida clique em Finish Logging, como o java.util.Logging e o Logback (que considera-
para terminar a criao do projeto. do por muitos como uma ferramenta superior ao famoso Log4j).
Assim, ao trmino desses passos, teremos as linhas ilustradas na
Listagem 3 adicionadas no arquivo de configurao do projeto.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
Figura 2. Escolhendo o archetype Maven
</dependency>
Listagem 7.Definio do persistence.xml JNDI jdbc/MySQL. Alm disso, inclumos propriedades referen-
tes ao gerenciamento do nvel de log do EclipseLink e a gerao
<?xml version=1.0 encoding=UTF-8?>
<persistence version=2.1 xmlns=http://xmlns.jcp.org/xml/ns/persistence
e/ou atualizao automtica de tabelas durante a inicializao
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance da unidade de persistncia (embora no seja uma boa prtica em
xsi:schemaLocation=http://xmlns.jcp.org/xml/ns/persistence ambientes de homologao/produo).
http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/
persistence_2_1.xsd>
A criao do datasource no GlassFish outro processo que no
<persistence-unit name=default transaction-type=JTA> complicado, de modo que possvel realiz-lo diretamente no
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> console de administrao oferecido pelo prprio servidor de
<jta-data-source>jdbc/MySQL</jta-data-source>
<properties> aplicao. Assim, para criar o Connection Pool e um JDBC Resource
<property name=eclipselink.logging.level value=FINE/> basta acessar o endereo localhost:4848 a partir do seu navegador
<property name=eclipselink.logging.logger value=org.eclipse.persistence. e realizar a autenticao com o usurio admin e a senha definida
logging.DefaultSessionLog/>
<property name=eclipselink.ddl-generation value=create-or-extend-tables /> nos passos anteriores. Apesar dessa facilidade, imprescindvel
<property name=eclipselink.deploy-on-startup value=true/> que o driver do MySQL tenha sido copiado para o diretrio lib do
</properties>
GlassFish, uma vez que o pacote inicial de instalao do Applica-
</persistence-unit>
</persistence> tion Server no inclui o driver JDBC desse SGBD. Assim, preciso
copiar o JAR do driver do MySQL no diretrio $GLASSFISH_
HOME/glassfish/domains/<seu domain>/lib e
reiniciar o GlassFish, para ento o driver ser
reconhecido pelo console de administrao.
Como estamos utilizando JTA para o ge-
renciamento de transaes do JPA, precisa-
remos de um tipo especfico de DataSource
no GlassFish capaz de lidar com transaes
distribudas, o XA Data Source. Para us-lo,
no entanto, devemos primeiramente criar
um JDBC Connection Pool. Deste modo,
clique em JDBC > JDBC Connection Pools e,
em seguida, no boto New..., como mostra
a Figura 4.
Como voc pode observar na Figura 5, de-
fina o nome do Connection Pool no campo
Pool Name como MySQLConnection Pool,
selecione javax.sql.XADataSource em Re-
source Type, MySql no campo Database Driver
Figura 4. Criando um JDBC Connection Pool Vendor e clique em Next. Optamos por um
XA DataSource pelo simples fato de delegar
o gerenciamento das transaes de banco
de dados para o JTA (Java Transaction API).
Alm disso, esse tipo de Data Source permite
utilizar todas as funcionalidades referentes a
transaes do Application Server, como por
exemplo, englobar uma transao com dois
ou mais recursos diferentes, como um banco
de dados e uma fila MQ.
Nesse momento voc dever configurar os
parmetros para a conexo com o MySQL em
Additional Properties. O GlassFish apresenta
de incio todas as propriedades configurveis
para um Data Source. Em um ambiente local,
no entanto, voc pode utilizar somente as
propriedades ServerName, Port, DatabaseNa-
me, User e Password. Portanto, configure-as
Figura 5. Primeiro passo da configurao de um JDBC Connection Pool conforme o seu ambiente.
Configurando o Log4j
Para encerrarmos o processo de confi-
gurao do projeto, devemos configurar
as propriedades do Log4j para as men-
sagens de log de nossa aplicao. Sendo Figura 6. Segundo passo da configurao de um JDBC Connection Pool
assim, crie o arquivo log4j.properties dentro
de src/main/resources com o contedo da
Listagem 8.
log4j.appender.stdout=org.apache.log4j.Console-
Appender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j
.PatternLayout
log4j.appender.stdout.layout.
ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L
- %m%n
log4j.rootLogger=DEBUG, stdout
Para isso usaremos a tecnologia WebSockets (no vale utilizar o Listagem 11. A entidade Pedido.
setTimeout do JavaScript!). A terceira funcionalidade diz respeito
import java.io.Serializable;
ao registro de atendimento de um pedido por uma filial. Essa import java.util.*;
funcionalidade dever alterar o status para em atendimento e import javax.persistence.*;
@Entity
notificar todas as filiais que aquele pedido j est em processo @Table(name=pedido)
de atendimento. @NamedQueries(value={@NamedQuery(name=Pedido.buscarNovosEemAten-
dimento,
query= Select p From Pedido p inner join fetch p.itens
Elaborando a modelagem de domnio da aplicao Where p.status = :novo or p.status = :atendimento Order By
Antes de partirmos para as tecnologias aplicadas camada de p.id desc, p.status desc)})
public class Pedido implements Serializable {
apresentao do nosso sistema, precisamos desenvolver alguns
artefatos importantes que sero utilizados no decorrer do pro- private static final long serialVersionUID = 2753252136140066761L;
jeto. Dessa maneira, iniciaremos pela criao das classes que @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
definem o domnio do nosso projeto: as Entidades e os Objetos @Column(name=id, nullable=false)
de Valor. Seguindo as definies de Eric Evans, autor do livro private Long id;
//getters e setters }
}
public Resultado(boolean success, String message) { public void registrar(final Pedido pedido) {
this.success = success; entityManager.persist(pedido);
this.message = message; }
}
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public boolean isSuccess() { public Pedidos pendentes() {
return success; final TypedQuery<Pedido> namedQuery = entityManager.createNamedQuery(
} Pedido.buscarNovosEemAtendimento, Pedido.class);
namedQuery.setParameter(novo, Status.N);
public void setSuccess(boolean success) { namedQuery.setParameter(atendimento, Status.A);
this.success = success; final List<Pedido> pedidos = namedQuery.getResultList();
return new Pedidos(pedidos);
}
}
public String getMessage() { public void atender(final Long id, final String atendente) {
return message; final Pedido p = entityManager.find(Pedido.class, id);
} Preconditions.checkState(p.getStatus() == Status.N,
Pedido ja em atendimento);
public void setMessage(String message) { p.setStatus(Status.A);
this.message = message; p.setDataAtendimento(new Date());
} p.setAtendente(atendente);
}
} }
chegam ao HttpServlet elas ainda esto representadas como Elaborando as telas da aplicao
uma simples cadeia de bytes. Portanto, ao receber a requisio, A fim de permitir que um cliente efetue o pedido, elaboramos um
devemos obter o corpo da mensagem HTTP, o chamado payload, formulrio simples que conter os campos nome, e-mail, telefone,
atravs de um objeto InputStream obtido pela invocao do m- o sabor e a quantidade dos pastis dentro de um arquivo JSP que
todo HttpServletRequest.getInputStream(), realizar a converso chamaremos de efetuarPedido.jsp, conforme mostra a Listagem 16.
para JSON e ento para a classe que representa o mesmo JSON. S
assim poderemos delegar o processamento dos dados do payload Listagem 16. Formulrio de envio de um pedido.
para o servio que sabe lidar com a regra de negcio associada <%@ page language=java contentType=text/html; charset=UTF-8
ao mtodo doPost. pageEncoding=UTF-8%>
<%@ taglib prefix=c uri=http://java.sun.com/jstl/core_rt%>
<html>
Listagem 15. O servlet EfetuarPedidoServlet que atender os pedidos. <head>
<meta http-equiv=Content-Type content=text/html; charset=UTF-8>
@WebServlet(urlPatterns=/pedido, loadOnStartup=1) <title>Efetuar Pedido</title>
public class EfetuarPedidoServlet extends HttpServlet { <link rel=stylesheet type=text/css href=<c:url value=css/style.css />
media=all>
private static final long serialVersionUID = -3309626245848149687L; </head>
<body>
@EJB <div id=container>
private PedidoService pedidoService; <p align=center>
<table>
<thead>
@Override
<tr>
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
<th>Nome</th>
throws ServletException, IOException {
<th>E-mail</th>
resp.setContentType(application/json);
<th>Telefone</th>
resp.setCharacterEncoding(UTF-8);
<th>Sabor</th>
final Gson gson = new Gson();
<th>Quantidade</th>
try {
<th></th>
final InputStreamReader inputStreamReader = new InputStreamReader(
</tr>
req.getInputStream());
</thead>
final Pedido pedido = gson.fromJson(inputStreamReader, Pedido.class);
<tbody>
pedidoService.registrar(pedido);
<tr>
resp.setStatus(200);
<td>
resp.getWriter().write(gson.toJson(new Resultado(true,
<input type=text id=cliente maxlength=100 size=35>
Pedido realizado com exito)));
</td>
} catch (final RuntimeException e) {
<td>
resp.sendError(500, e.getMessage());
<input type=text id=email maxlength=100 size=40>
}
</td>
}
<td>
} <input type=text id=telefone maxlength=18 size=18>
</td>
<td>
<select id=sabor>
a que entra o Google GSON, uma biblioteca capaz de converter <option value=Carne>Carne</option>
JSON em uma classe Java. Na Listagem 15 utilizamos o mtodo <option value=Queijo>Queijo</option>
fromJson() passando como primeiro argumento um InputStre- <option value=Pizza>Pizza</option>
<option value=Quatro Queijos>Quatro Queijos</option>
amReader obtido a partir do InputStream encapsulado dentro </select>
do HttpServletRequest (parmetro req do mtodo doPost) e, </td>
<td>
como segundo argumento, a classe do objeto a ser mapeado que,
<input type=text id=quantidade maxlength=3 size=3>
no nosso caso, a classe Pedido. O resultado disso um objeto </td>
Pedido, preenchido com os valores do JSON recebido. <td>
<input type=button value=Enviar id=enviar>
O servlet EfetuarPedidoServlet ainda possui a anotao </td>
@WebServlet. Esta registra o servlet no contexto da aplicao e </tr>
define, por meio da propriedade urlPatterns, o padro de URL </tbody>
</table>
em que ele ir atender. Por exemplo, na Listagem 15, o parmetro </p>
urlPatterns define que o servlet atende no endereo /pedido. </div>
Tambm definimos a ordem de carregamento do Servlet como <script type=text/javascript src=<c:url
value=js/resources/jquery/jquery-2.0.3.min.js />>
1 por meio da propriedade loadOnStartup, para que ele seja </script>
carregado com maior prioridade pela aplicao em relao a outros <script type=text/javascript src=<c:url value=js/app/efetuarPedido.js>
</c:url>>
servlets. Observe que fizemos atravs de anotaes o que poderia
</script>
ter sido feito atravs das tags <servlet/> e <servlet-mapping/>, </body>
no web.xml. </html>
Portanto, crie o arquivo pedidosPendentes.jsp em src/main/webapp, tabela dentro da pgina que criamos. Acontece que se aplicarmos
conforme definido na Listagem 19. apenas essa biblioteca, vamos acabar misturando muito do cdigo
A pgina apresentada na Listagem 19 ainda no capaz de HTML com o JavaScript e isso degrada a organizao do cdigo, di-
mostrar a lista dos pedidos uma vez que o elemento div iden- minuindo a elegncia e manutenibilidade uma vez que essa mistura
tificado por container est em branco. Alm disso, levando tende a deix-lo mais confuso. Assim, para evitar que isso acontea,
em considerao que a listagem dos pedidos um contedo empregaremos a biblioteca underscore.js, que nos auxiliar, a partir
dinmico, precisamos de uma tabela capaz no somente de da criao de templates, a separar trechos de cdigo da linguagem
listar as pendncias, mas tambm de se auto atualizar conforme de marcao da linguagem de programao.
as novas solicitaes ocorrerem. E justamente por esse motivo
que utilizaremos JavaScript para manipular dinamicamente o Templating com underscore.js
contedo da pgina. Uma das grandes vantagens de se adotar o undescore.js que
os templates usados com ele podem receber como parmetro
Listagem 18. O servlet de busca de pedidos. um JSON. Essa capacidade nos fornece uma possibilidade muito
simples e inteligente de resolver o problema da aplicao de
@WebServlet(urlPatterns=/pedidos, loadOnStartup = 1)
public class BuscarPedidosServlet extends HttpServlet { cdigos HTML dentro de fontes JavaScript, solucionando com
elegncia o problema exposto anteriormente. Portanto, usare-
private static final long serialVersionUID = -5883823536178568608L;
mos no apenas funes bsicas da biblioteca, como tambm
@EJB estenderemos algumas delas a fim de disponibilizar mtodos
private PedidoService pedidoService; auxiliares que sero teis para a criao e formatao dos
@Override
valores. Dessa forma, comeando pela criao do JavaScript
protected void doGet(HttpServletRequest req, HttpServletResponse resp) que ser usado na apresentao dos pedidos pendentes, pre-
throws ServletException, IOException { encha o arquivo pedidosPendentes.js conforme apresentado na
resp.setContentType(application/json);
resp.setCharacterEncoding(UTF-8);
Listagem 20.
try { Aplicar o recurso de templates do underscore.js no nada
resp.setStatus(200); complicado e seu funcionamento bastante similar a scriptlets,
resp.getWriter().write(pedidoService.pendentes().asJson());
} catch (final RuntimeException e) { embora as tags lembrem um pouco as do ASP. Para us-lo, ne-
resp.sendError(500, e.getMessage()); cessrio criar uma String que representa o modelo e ento aplicar
} as tags e funes do underscore.js que preenchero essa estrutura
}
} conforme os valores, geralmente em forma de JSON, passados
a elas. Observe pela Listagem 20 que o template, representado
Listagem 19. Contedo do JSP que apresenta os pedidos pendentes.
pela varivel tabelaTemplate, usa as tags <%= e %> para definir
<%@ page language=java contentType=text/html; charset=UTF-8 os locais de incluso de valores de algum campo do JSON. Por
pageEncoding=UTF-8%> outro lado, o trecho com os elementos <% e %> tem uma caracte-
<%@ taglib prefix=c uri=http://java.sun.com/jstl/core_rt%>
<html>
rstica diferente e faz chamada para funes auxiliares como, por
<head> exemplo, o mtodo _.each(), que itera sobre elementos dentro do
<meta http-equiv=Content-Type content=text/html; charset=UTF-8> template. Em virtude disso, criaremos o JavaScript util.js, que con-
<title>Pedidos Pendentes</title>
<link rel=stylesheet type=text/css href=<c:url value=css/style.css /> ter a definio desses mtodo, conforme mostra a Listagem 21.
media=all> Com isso, o resultado final esperado para a tela dos pedidos
</head> pendentes dever ser semelhante ao apresentado na Figura 9.
<body>
<div id=container></div>
<script type=text/javascript
src=<c:url value=js/resources/jquery/jquery-2.0.3.min.js />></script>
<script type=text/javascript
src=<c:url value=js/resources/underscore/underscore.js />></script>
<script type=text/javascript src=<c:url value=js/app/util.js></c:url>>
</ script>
<script type=text/javascript
src=<c:url value=js/app/pedidosPendentes.js></c:url>></script>
</body>
Figura 9. Tela de pedidos pendentes
</html>
Listagem 21. Mtodos auxiliares de formatao e preenchimento de valores. Listagem 22. Gerando HTML atravs do template do underscore.js.
que as pastelarias conveniadas saibam de antemo quando uma A alterao no template proporciona a criao de um boto que
solicitao j foi atendida. Para viabilizar isto, desenvolveremos dispara o atendimento. A Figura 10 apresenta a nova verso da tela
mais um servlet, apresentado na Listagem 23, que chamamos de pedidos pendentes. Ao passo em que o atendimento se inicia,
de AtendimentoServlet e que ser responsvel por registrar o o status do pedido alterado de Novo para Em atendimento
atendimento de um pedido. e o boto que foi clicado desabilitado atravs do atributo disa-
O AtendimentoServlet encarregado de receber um identifica- bled, que acrescentado ao input e que nos auxilia a evitar que
dor nico de pedido e, com isso, atualizar a nossa base de dados um segundo clique acontea. J a ao do clique est vinculada
para que o pedido fique registrado como em atendimento. ao mtodo JavaScript atender(), codificado na Listagem 25 e que
Guardaremos ainda a informao de data/hora da requisio, deve ser adicionado no arquivo js/app/pedidosPendentes.js. Esse
bem como quem o atendente que tem a responsabilidade sobre mtodo recebe como parmetros um nmero inteiro que define
a solicitao. Para no prolongarmos ainda mais este artigo, va- o identificador nico e o status do pedido.
mos considerar a identificao do atendente como sendo o ID da
prpria sesso do usurio na aplicao, uma vez que esse valor Comunicao web bidirecional com WebSockets
fcil de ser obtido de um objeto HttpSession. Um dos problemas mais frequentes durante a implementao
Com o servlet de alterao de status do pedido pronto, traba- da camada de apresentao de um sistema a maneira pela qual
lharemos agora na camada de apresentao, que ir interagir com conseguimos realizar a atualizao da informao em tempo
ele e que ser utilizada pelo usurio final. Para isso, realizaremos real para os nossos clientes. Atualmente, j existem inmeras
uma alterao simples no template da tabela dinmica que foi tcnicas, como por exemplo, o Ajax Reverso (tambm conhecido
construda durante a apresentao das Listagens 19, 20 e 21. como Ajax Push ou Comet), o uso de Applets Java, ou at Flash,
Portanto, abra o arquivo pedidosPendentes.js e o atualize, conforme que conseguem atender a esse objetivo de forma satisfatria, no
o contedo apresentado na Listagem 24. entanto, uma das maneiras mais elegantes com a implementao
de um WebSocket.
Listagem 23. O servlet de atendimento. A JSR-356, especificao da Java API for WebSocket, trata-se de
uma tecnologia capaz de permitir comunicao bidirecional entre
@WebServlet(urlPatterns=/atendimento, loadOnStartup = 1)
servidor e cliente, o que algo extremamente valioso quando
public class AtendimentoServlet extends HttpServlet {
o assunto aplicaes web. Contudo, essa caracterstica no
private static final long serialVersionUID = 7479025501206838360L; necessariamente um fruto da Java EE, visto que, antes mesmo
@EJB
do lanamento oficial da verso enterprise da linguagem, o Web
private PedidoService pedidoService; Container Jetty j possua uma implementao prpria dessa fun-
cionalidade. Nessa especificao, o JavaScript fundamental e a
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
implementao da API JavaScript essencial para o funcionamen-
throws ServletException, IOException { to dela. Em decorrncia disso, uma tecnologia que depende que
resp.setContentType(application/json); seu uso ocorra nos navegadores de Internet que a suportem.
resp.setCharacterEncoding(UTF-8);
final Gson gson = new Gson(); Voltando ao nosso projeto, vamos construir agora a classe
try { NotificacaoWebSocket, cujo cdigo apresentado na Listagem 26,
final Long id = Long.parseLong(req.getParameter(id)); dentro do pacote br.com.dev media.pastelar ia _online.
pedidoService.atender(id, req.getSession().getId());
resp.setStatus(200); present at ion.websocket. Nela aplicaremos a a notao
resp.getWriter().write(gson.toJson(new Resultado(true, @ServerEndpoint que representa o endpoint do nosso WebSo-
Atendimento registrado com sucesso)));
cket. Com isso seremos capazes de notificar todos os clientes que
} catch (final RuntimeException e) {
resp.sendError(500, e.getMessage()); esto conectados ao nosso sistema sobre qualquer mudana que
} acontea com um pedido.
}
}
Repare na classe que acabamos de criar e nas anotaes que
ela carrega. Indicamos que
ela se comporta como um
servidor WebSocket quan-
do atribumos a anotao
@ServerEndpoint, e ao in-
cluir a string /notificacao
como um parmetro dela,
definimos em qual ende-
reo ela atender as requi-
sies HTTP. Alm disso,
Figura 10. Nova verso da tela de pedidos pendentes com a anotao @Singleton
capaz de interpretar as informaes em tempo real provenientes Atribuindo notificaes com WebSocket
do servidor. Vamos ento criar a instncia de um objeto do tipo Agora temos todo o arcabouo do nosso projeto montado e esta-
WebSocket, similar ao que j que expusemos anteriormente, no mos aptos para enviar notificaes para os nossos clientes. Para
carregamento da pgina. Para isso, abra o arquivo js/app/pedidos- finalizar o projeto, nos resta apenas alterar as funcionalidades
Pendentes.js e adicione o cdigo da Listagem 27. de efetuar pedido e atender pedido para que elas notifiquem
por meio do WebSocket as mudanas nos pedidos. Assim, as
Listagem 27. Instanciao do WebSocket no JavaScript. Listagens 30 e 31 apresentam as novas verses dos Servlets Efetuar-
PedidoServlet e AtendimentoServlet, que agora so capazes de
function init(endpoint, onMessage) { transmitir alteraes de estado para os nossos usurios utilizando
ws = new WebSocket(endpoint);
ws.onopen = function() {
o ServerEndpoint.
console.log(Conexo aberta com sucesso);
}; Listagem 30. Nova verso do servlet EdetuarPedidoServlet.
if (onMessage) {
ws.onmessage = onMessage; @WebServlet(urlPatterns=/pedido, loadOnStartup=1)
} public class EfetuarPedidoServlet extends HttpServlet {
ws.onclose = function() {
console.log(Conexo fechada com sucesso); private static final long serialVersionUID = -3309626245848149687L;
};
ws.onerror = function(evt) { @EJB
console.log(Ocorreu um erro no WebSocket + evt.data); private PedidoService pedidoService;
};
} @EJB
private NotificacaoWebSocket notificacaoWebSocket;
@Override
A funo init() recebe como argumentos o endereo do end-
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
point do WebSocket e a funo de callback que ser executada throws ServletException, IOException {
sempre que uma nova notificao for transmitida pelo servidor. resp.setContentType(application/json);
Por sua vez, o callback est definido na Listagem 28 pela funo resp.setCharacterEncoding(UTF-8);
atualizarTabela(), que recebe como parmetro a notificao do final Gson gson = new Gson();
try {
servidor. J a Listagem 29 apresenta a funo annima que
final InputStreamReader inputStreamReader = new
executada aps o carregamento da pgina e que adiciona o Event- InputStreamReader(req.getInputStream());
Listener load com o cdigo que inicia o WebSocket. Adicione final Pedido pedido = gson.fromJson(inputStreamReader, Pedido.class);
o cdigo das Listagens 28 e 29 no mesmo arquivo usado pela pedidoService.registrar(pedido);
Listagem 27, o pedidosPendentes,js. notificacaoWebSocket.notificar();
resp.setStatus(200);
Listagem 28. Funo de callback executada aps nova notificao. resp.getWriter().write(gson.toJson(new Resultado(true,
Pedido realizado com exito)));
function atualizarTabela(evt) { } catch (final RuntimeException e) {
if (evt.data) { resp.sendError(500, e.getMessage());
var json = $.parseJSON(evt.data); }
montarTabela(json); }
} else { }
console.log(WebSocket no retornou dados);
}
}
Listagem 29. Funo annima executada aps o carregamento da pgina de Implantando a aplicao
pedidos pendentes.
Com a primeira verso da aplicao desenvolvida, resta agora
$(document).ready(function() { implant-la no GlassFish 4 por meio do maven-glassfish-plugin.
(function(){ Para isso, utilize o Maven Goal glassfish:deploy. J para a instalao
window.addEventListener(load, init( de novas verses da nossa aplicao, podemos utilizar o Goal
ws://localhost:8080/pastelaria-online/notificacao, atualizarTabela), false);
glassfish:redeploy, que se encarrega do undeploy da verso antiga
})(); do WAR e do deploy da nova verso dele. A Listagem 32 apresenta
a instalao da nossa aplicao via linha de comando utilizando o
// cdigo apresentado nas listagens 16 e 19 omitido Maven, sendo que esse comando deve ser executado no diretrio
raiz da aplicao, onde se encontra o arquivo pom.xml. Certifique-
}
se tambm do GlassFish 4 estar em execuo.
facilidade de manuteno e tolerncia a falhas. Em outras palavras, notificao, como foi o caso do projeto apresentado neste artigo e
quanto mais complexo o sistema, maior a necessidade que ele at mesmo jogos-online!
demanda para a adoo de padres, cdigo mais limpo e escolha Por fim, esperamos que o leitor tenha aproveitado ao mxi-
de frameworks aplicveis. Neste artigo, tivemos a oportunidade mo todo o contedo abordado neste artigo, proporcionando
de propor e produzir um projeto amplo que envolveu a escolha assim o conhecimento de novas tecnologias e tcnicas para o
de diferentes bibliotecas, frameworks, softwares e metodologias para desenvolvimento de aplicaes web mais robustas utilizando
atender o propsito final de desenvolver uma aplicao web capaz a plataforma Java.
de realizar atualizaes em tempo real para usurios conectados
a ela. Alm disso, destacamos em nosso estudo as vantagens que Autor
a tecnologia WebSockets, definida pela especificao da Java EE 7,
Alexandre Arcanjo de Queiroz
proporciona para os sistemas web.
alexandre.queiroz@live.com
tecnlogo em Anlise e Desenvolvimento de Sistemas pela Fa-
culdade de Tecnologia de So Paulo (FATEC-SP). Atua como revisor
tcnico em publicaes internacionais relacionadas ao desenvolvimento de
software. Tambm um usurio GNU/Linux.
Autor
Felipe Pierin
felipe.pierin@gmail.com
bacharel em Sistemas de Informao pela EACH/USP e futuro
mestre em Cincia da Computao pelo IME/USP. Analista De-
senvolvedor Java com considervel experincia no desenho e construo
de sistemas complexos e distribudos.
Links e Referncias:
N
o artigo anterior estudamos toda a parte partir do desenvolvimento de um estudo de caso simples, abordaremos
conceitual da JSR 352, disponibilizada em desde o monitoramento da execuo do processo batch at a visualizao
abril de 2013, pouco antes do lanamento da do resultado produzido pela sequncia dos passos desenvolvidos. Desta
nova verso da plataforma Java EE (a Java EE 7). Alm forma, ao final o leitor ter o conhecimento prtico necessrio para imple-
disso, foram apresentados conceitos genricos sobre os mentao de processos batch adotando este novo e importante recurso
dois principais tipos de processamento utilizados nas que a API Batch, lanada com a plataforma Java EE 7.
organizaes, Batch e On-Line. Neste artigo, aborda- Este tema til em situaes nas quais se faz necessrio o desenvol-
remos de uma forma mais tcnica a JSR 352, visando vimento de aplicaes batch visando automatizao de processos
complementar o contedo discutido no artigo anterior recorrentes e que no necessitam de intervenes manuais para serem
e tambm colocar em prtica as definies referentes ao realizados.
processamento batch, como Job e Step, por exemplo, j
analisadas na primeira parte desta srie.
Para isso, implementaremos um simples estudo de Viso geral da soluo Processos e Classes
caso para que possamos aplicar os principais conceitos Nas Figuras 1 e 2 podemos visualizar a soluo tcnica uti-
relacionados tecnologia foco do estudo. Este tem como lizada para implementao deste estudo de caso. Esta soluo
objetivo automatizar um processo para clculo de de- utiliza-se da notao BPMN para descrio do processo (Figura 1)
sempenho de alunos em uma escola que realizado a e do diagrama de classes da UML para descrio conceitual das
cada final de semestre. O processo ir resultar na gerao classes envolvidas na implementao (Figura 2). No decorrer da
de dois arquivos: parte prtica, desenvolveremos processos que fazem uso das
1. Arquivo que contm os dados dos alunos aprovados duas modalidades batch descritas no primeiro artigo, sendo
no semestre, com mdia igual ou superior a 6.0; elas Chunk-oriented (que visa quebrar um grande processo em
2. Arquivo que contm os dados dos alunos reprovados pequenos pedaos (chunks)) e Batchlet (que foca em apenas uma
no semestre, com mdia inferior a 6.0. nica tarefa).
A partir das vises apresentadas nas Figuras 1 e 2, podemos
Atravs deste pequeno estudo de caso, apresentaremos ter uma ideia do que ser necessrio desenvolvermos em prol
o desenvolvimento dos componentes de software que da automatizao do processo de clculo de notas e gerao dos
faro parte deste processo, bem como o desenvolvimento arquivos de desempenho dos alunos.
de uma pgina a ser utilizada para dar incio ao processo Antes de detalharmos cada um dos componentes de software
batch e possibilitar o monitoramento do status final de indicados na Figura 2, vamos entender a estrutura de pacotes exis-
cada uma das execues. Durante essa implementao, tente nesta nova JSR. Na Tabela 1 podemos verificar a finalidade
conheceremos as principais interfaces e classes perten- de cada um dos pacotes. Mais informaes sobre essa estrutura
centes ao pacote javax.batch. O objetivo deste estudo de podem ser encontradas no Javadoc da verso 7 da plataforma Java
caso trabalhar com as duas abordagens de desenvolvi- EE. O endereo para acesso ao Javadoc pode ser encontrado na
mento batch existentes na JSR 352: Chunk e Batchlet. seo Links deste artigo.
Tecnologias utilizadas
Para que possamos implementar tudo o
que projetamos anteriormente, faremos
uso das seguintes ferramentas:
A IDE Eclipse Kepler;
O servidor de aplicaes GlassFish 4.0;
O framework web JavaServer Faces 2;
Engine para realizao da Injeo de
Dependncias (CDI);
A API Java Batch (implementao da
JSR 352).
Desenvolvimento da soluo
Para comearmos o nosso trabalho de
implementao, dividiremos nosso de-
senvolvimento em seis etapas, conforme
descrito a seguir:
1. Criao de um projeto web utilizando o
framework JSF. Para execuo deste projeto Figura 1. Viso macro do processo de gerao de arquivo com desempenho semestral dos alunos
utilizaremos o servidor de
aplicao GlassFish;
2. Adio das APIs necess-
rias para injeo de depen-
dncia (CDI) e processamen-
to batch (JSR 352);
3. Codificao do arquivo
com as definies batch uti-
lizando a linguagem JSL (Job
Specification Language). Esta
codificao utiliza o formato
XML para determinar o flu-
xo de execuo dos jobs e os
parmetros de execuo;
4. Desenvolvimento das
classes Java envolvidas na
soluo batch; Figura 2. Viso geral da soluo Modelo Conceitual
de instalao do GlassFish, mais precisamente no diretrio de- <job>: Esta tag representa um Job. Para definir a nomenclatura
nominado modules. Os nomes das bibliotecas so: javax.batch-api do job, utilizamos o atributo id. Neste caso, temos um Job deno-
.jar e weld-integration.jar. minado JobDesempenho;
Para adicionarmos as bibliotecas citadas anteriormente, devemos <flow>: Esta tag realiza a definio de um fluxo de execuo que
clicar com o boto direito do mouse em cima do projeto criado pode conter 1 ou N steps. O atributo id inserido para definir o
(na view Project Explorer do Eclipse) e selecionar as opes Build nome do fluxo. Assim, este fluxo pode ser referenciado em uma
Path e, logo depois, Configure Build Path. Ao abrir a nova janela, tag <next> para determinar o prximo fluxo a ser executado;
selecione a aba denominada Libraries e clique no segundo boto, <step>: Esta tag realiza a definio de um step. O atributo id,
localizado direita da janela, chamado Add External Jars. A par- assim como nos casos anteriores, inserido para definir a nomen-
tir disso ser possvel informar o local onde as bibliotecas esto clatura do step. Da mesma forma que a tag <flow>, este id pode ser
localizadas, para que sejam adicionadas estrutura do projeto. referenciado em uma tag <next> para determinar o prximo step
Depois, basta clicar no boto OK. a ser executado. Alm disso, dentro do monitor de execues Batch
Por fim, para habilitarmos o CDI dentro do nosso projeto web, existente no servidor de aplicao GlassFish, possvel acompa-
se faz necessria a criao do arquivo beans.xml no diretrio Web- nhar o resultado de cada um dos steps executados por um job.
Content\WEB-INF\. Para o nosso projeto, este arquivo dever ser Neste caso, o id do step tambm utilizado. Em nosso exemplo,
criado sem nenhum contedo. temos dois steps: o primeiro, com a finalidade de processar um
arquivo de alunos com suas respectivas notas, calculando suas
Arquivo de configurao dos processos batch mdias e classificando-os como Aprovados ou Reprovados; e o
Para que a execuo dos Jobs seja possvel, necessrio que exista segundo e ltimo step, com a finalidade de segmentar os dados,
pelo menos um arquivo JSL (arquivo utilizado para configurao separando os alunos Aprovados dos alunos Reprovados;
da estrutura do Job, seus respectivos Steps e fluxos de execuo) <chunk>: Esta tag define um step como sendo do tipo chunk-
configurado no projeto. oriented. A propriedade denominada item-count indica que a
Por padro, todos os arquivos JSL devem ser armazenados no leitura-processamento-sada de informaes ocorrer em peda-
diretrio WebContent\WEB-INF\classes\META-INF\batch-jobs os (chunks) de 10 em 10 registros (valor default caso no seja
com a extenso do tipo .xml. A definio do nome do arquivo informado);
fica a cargo do desenvolvedor, porm deve-se ter em mente um <reader>: Esta tag define qual ser a classe que atuar como
padro de nomenclatura, uma vez que, quando o incio do Job for classe de leitura de informaes dentro do processo referente ao
realizado, o nome do arquivo JSL dever ser informado. step atual;
Dentro de um arquivo JSL podemos definir vrias propriedades <processor>: Esta tag define qual ser a classe que atuar como
a serem utilizadas pelos Jobs durante seu processamento, assim classe de tratamento das informaes referente ao step atual;
como vrios fluxos de execuo, definio da execuo de Jobs <writer>: Esta tag define qual ser a classe que atuar como
em paralelo e at mesmo critrios de continuao da execuo em classe de gravao de informaes dentro do processo referente
caso de falhas. Na Listagem 1 podemos verificar o arquivo JSL ao step atual;
que utilizaremos em nosso exemplo. <next>: Como j informado, essa tag utilizada para definir a
execuo do prximo step ou fluxo existente no job. A proprieda-
Listagem 1. Contedo do arquivo JSL denominado JobDesempenho.xml. de on indica qual o retorno esperado frente ao processamento
do step corrente para que o prximo step/fluxo seja executado.
<job id=JobDesempenho xmlns=http://xmlns.jcp.org/xml/ns/javaee
version=1.0 restartable=true>
A propriedade to indica qual ser o step/fluxo que ser executado.
<flow id=flow1> Os retornos esperados podem ser:
<step id=step1 > - ABANDONED;
<chunk item-count=10>
<reader ref=itemReaderDesempenho />
- COMPLETED;
<processor ref=itemProcessorDesempenho /> - FAILED;
<writer ref=itemWriterDesempenho /> - STARTED;
</chunk>
<next on=COMPLETED to=step2 /> - STARTING;
</step> - STOPPED;
<step id=step2> - STOPPING.
<batchlet ref=selecaoBatchlet />
</step> <batchlet>: Esta tag define o step como sendo do tipo Batchlet
</flow> e tambm indica qual ser a classe que atuar como classe de
</job>
processamento.
A seguir podemos visualizar todas as consideraes referentes Classes Java envolvidas no processo Batch
listagem anterior. Essas consideraes esto divididas por <tags> Na Listagem 1 especificamos todas as classes que participaro
para facilitar o entendimento: do processo batch. Todas elas foram definidas atravs das tags
package br.com.devmedia.batch.reader;
import java.io.BufferedReader; //Realiza o processo de abertura do arquivo.
import java.io.FileReader; fr = new FileReader(resourceName);
import java.io.Serializable; br = new BufferedReader(fr);
import java.util.Properties; System.out.println([ItemReaderDesempenho] Abertura do arquivo de
import javax.batch.api.chunk.AbstractItemReader; notas dos alunos a partir do registro: + numeroRegistros);
import javax.batch.operations.JobOperator; }
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.context.JobContext; @Override
import javax.inject.Inject; //Mtodo executado logo aps o mtodo open(). Tem como objetivo
import javax.inject.Named; //realizar a leitura registro a registro.
public Object readItem() throws Exception {
@Named(itemReaderDesempenho)
public class ItemReaderDesempenho extends AbstractItemReader { //Realiza a leitura do arquivo.
line = br.readLine();
@Inject
private JobContext jobContext; //Valida se o registro diferente de null para que
private FileReader fr; //se possa realizar a contagem do mesmo.
private BufferedReader br; if (line != null) {
private String line; /* A partir do momento em que o registro lido com sucesso,
private int numeroRegistros; * incrementamos 1 ao nmero de registros.
*/
@Override numeroRegistros++;
//Mtodo com a funo de realizar a abertura do arquivo. }
public void open(Serializable prevCheckpointInfo) throws Exception { return line;
}
//JobOperator utilizado para se obter os parmetros de
//execuo definidos para o job. @Override
JobOperator jobOperator = BatchRuntime.getJobOperator(); //Mtodo de fechamento do arquivo, executado ao final da leitura
//de todos os registros.
//Obtm os parmetros de execuo existentes para este public void close() throws Exception {
//Job definidos em tempo de execuo. br.close();
Properties jobParameters = jobOperator.getParameters( fr.close();
jobContext.getExecutionId()); System.out.println([ItemReaderDesempenho] Mtodo de Fechamento
do Arquivo foi Executado. Total de Registros Lidos:
//Obtm o nome do arquivo de entrada, enviado como parmetro + numeroRegistros + ]]);
//no momento da execuo do Job. }
String resourceName = (String) jobParameters.get(INPUT_DATA_FILENAME); }
Como vimos, essa interface adotada em diversas classes analisa- Criando a interface web para iniciar o processo
das anteriormente e tambm estar presente no managed bean que Para possibilitarmos a execuo do processo batch, criaremos
codificaremos no tpico Desenvolvendo dos componentes JSF. uma interface web que oferecer ao usurio uma opo que,
Por fim, nas Listagens 8, 9 e 10 encontraremos a definio das quando ativada, ir gerar o desempenho dos alunos. Esta pgi-
classes auxiliares descritas no incio deste tpico, que possuem um na possuir ainda um simples monitor de execues, para que
papel importante na estruturao das informaes, dando uma seja possvel acompanhar todos os resultados decorrentes dos
semntica para cada dado lido, processado e armazenado. processos batch.
Nas Listagens 11 e 12 so apresentados os cdigos do nosso o job. Este ltimo mtodo inclui todos os parmetros que sero
managed bean e da pgina XHTML, analisados a seguir. transmitidos ao job antes de sua execuo, realizada atravs do
Na Listagem 11 podemos ver a estr ut urao de nos- mtodo start() existente na classe JobOperator. A incluso dos
so managed bean, dividido em trs mtodos principais: parmetros neste momento fundamental para que os compo-
calcularDesempenho(ActionEvent ae), responsvel pelo acio- nentes ItemReaderDesempenho, ItemWriterDesempenho e
namento do mtodo startNewBatchJob() e pelo armazenamento SelecaoSituacaoBatchlet possam utiliz-los.
das informaes iniciais da execuo do processo batch; atuali Atravs da Listagem 12 podemos visualizar o cdigo referente
zarStatusExecucao(ActionEvent ae), responsvel por atualizar nossa pgina, que possui uma tabela, utilizada para apresentao
a lista de jobs executados, atualizao esta que refletida em dos status dos Jobs, e dois botes: um denominado Calcular De-
nossa pgina JSF; e startNewBatchJob(), responsvel por invocar sempenho, cuja funo acionar o mtodo calcularDesempenho();
package br.com.devmedia.batch.MB;
//Adiciona as informaes de execuo na lista para que seja exibida para o usurio.
// imports omitidos... jobs.add(job);
verificarmos o encerramento da execuo (atravs da penltima Para finalizarmos, vlido informar que tambm podemos visu-
linha exibida na Figura 8). alizar a execuo dos processos batch utilizando o console nativo
Para que possamos visualizar as informaes das colunas End do GlassFish. Para isto, devemos executar os seguintes passos:
Time (data do fim da execuo) e Batch Status (Status da execuo Acessar a URL: http://caminhoServidor:4848;
do job) existentes em nossa pgina JSF, precisamos clicar no boto Feito isso, ser apresentada ao usurio a pgina inicial de
Atualizar, para que os status sejam verificados e atualizados de administrao do GlassFish. Atravs desta pgina, clique no
acordo com a implementao de nosso managed bean, descrito link localizado ao lado esquerdo da pgina, denominado server
na Listagem 11. A Figura 9 mostra o resultado da execuo desse (Admin Server);
processo de atualizao. Aps acessar a seo de Admin Server, clique na aba denominada
Caso ocorra alguma falha na execuo do job por conta de al- Batch;
guma exceo lanada, ser possvel verificar o status FAILED
na coluna Batch Status. Neste caso o erro dever ser averiguado Na prxima pgina possvel verificar a execuo de todos os
pelo desenvolvedor. Para facilitar o processo de identificao dos processos batch. Para termos acesso a um nvel maior de granu-
erros, recomenda-se que seja implementado um mecanismo de laridade do resultado, devemos clicar no link existente na coluna
log utilizando APIs como a Log4J, ao invs dos nossos sysouts Execution ID. Ele nos levar a uma tela de detalhamento inicial do
criados durante o desenvolvimento. job selecionado (Figura 10), na qual ser possvel visualizarmos os
parmetros que foram transmi-
tidos na execuo, o status final
da execuo (Batch Status), a hora
de incio (Start Time) e fim (End
Time) e a quantidade de steps
(Step Count).
Para visualizarmos os steps
executados dentro do job, bem
como o retorno de cada um dos
steps e at mesmo o nome dos
mesmos, clique na aba Execution
Steps. Assim, ser apresentada
a pgina de detalhamento dos
steps (veja a Figura 11). Nesta
Figura 9. Resultado da atualizao do status de execuo pgina podemos encontrar o
nome de cada um dos steps, no-
mes estes que foram definidos em
nosso arquivo de configurao
e que so importantes quando
queremos identificar com maior
facilidade o ponto de erro. Alm
disso, possvel verificarmos
seus respectivos status de execu-
o, data de incio e fim e mtri-
cas padres, como a quantidade
de leituras realizadas.
Este artigo abordou de forma
simples as principais classes e
interfaces existentes na JSR 352.
Para isso, apresentamos um
estudo de caso e desenvolvemos
componentes de software que,
em conjunto, realizam tarefas
objetivas que visam automatizar
processos, como, por exemplo, o
processo de clculo de desem-
Figura 10. Tela de detalhamento da execuo de um job penho. Alm disso, vimos como
Quando utilizamos a notao prefixa, comeamos a perceber firmemente na imutabilidade, que o princpio em que um valor
que os parnteses tm uma razo lgica para existir e, com o no se altera at o final da execuo do cdigo, e a transformao
tempo, comearo a ser naturais para quem est comeando com de dados, onde uma funo recebe um valor ou um conjunto de
a linguagem. Em Clojure, os mesmos clculos acima ficariam valores e devolve um novo valor ou conjunto de valores.
conforme apresenta a Listagem 2. Baseando-se nisso, vamos armazenar os valores de 1 a 10 em uma
sequncia ao invs de alterar o valor de uma varivel dez vezes.
Listagem 2. Os mesmos clculos, em Clojure. Para armazenar essa sequncia, vamos usar a palavra chavedef,
que internamente cria uma estrutura chamada Var. Apesar do
(+ 2 (* 3 4))
Clojure no ter variveis, vamos pensar noVarcomo sendo uma
; 14
varivel global. Para o que vamos fazer, essa analogia mais do
(* (+ 2 3) 4) que suficiente. Dito isso, execute o seguinte cdigo no REPL:
; 20
Listagem 3. Exemplo de cdigo imperativo. Dentro da biblioteca padro do Clojure existe tambm uma
funo chamadafilter, que recebe como parmetros uma funo,
int soma = 0;
que vamos chamar depredicado, e uma lista de dados, retornando
for (int num = 1; num <= 10; num++) { uma nova lista contendo somente os itens que fizerem o predicado
if(num % 2 == 0) { retornartrue.
soma += num;
} Tanto em programao quanto na matemtica, chamamos
} de predicado uma funo que retorna true ou false de acordo
com o parmetro recebido. Neste exemplo, a funo even? o
System.out.println(soma);
nosso predicado.
Perceba no cdigo da Listagem 5 como a funofilternos retorna
Perceba que os valores de soma e num mudam vrias vezes somente os nmeros pares, e no altera o valor original denums.
durante a execuo do programa. Linguagens imperativas como Esse um dos fundamentos da imutabilidade: os dados permane-
o Java se apoiam namutabilidadedos dados, enquanto linguagens cem intactos e uma nova sequncia criada com os dados novos.
funcionais, como o caso do Clojure, preferem utilizar deimuta- Voltando ao Java, como a classe Stringfunciona, retornando um
bilidade, retornando dados transformados e mantendo os dados novo objetoStringa cada operao e mantendo o valor original
originais intactos. do objeto que invocou o mtodo.
No cdigo imperativo, a base do nosso cdigo ofore os valores A API padro nos fornece ainda uma funo chamadareduce,
que vo de 1 a 10. O for trabalha alterando o valor da varivel que tambm recebe uma funo e uma lista como parmetros. Essa
de controle, no nosso caso o num, tantas vezes quantas forem funo, qual chamamos decallback, aplicada cumulativamente
necessrias. J o paradigma funcional de programao apoia-se aos itens da lista, de dois em dois, at que tenhamos um nico
Uma segunda forma de resolver esse problema consiste em Perceba que em Clojure no existereturn, sendo considerado
usar a funoapply no lugar da funo reduce. A funoapply como o retorno da funo o ltimo valor avaliado, de modo pare-
tambm recebe uma funo como callback e uma lista como pa- cido com o Ruby. J o sinal de interrogao no nome da funo
rmetros, mas transforma todos os itens da lista em parmetros uma mera conveno para indicar que a funo um predicado.
para o callback. Adicionar esse smbolo ao final do nome da funo serve como
Exemplificando, o cdigo(apply + [1 2 3])gera internamente o uma boa prtica, mas no obrigatrio.
cdigo(+ 1 2 3). Tanto uma forma como a outra fazem exatamente o Em seguida vamos usar a funo filter, que j utilizamos
mesmo. Assim sendo, basta substituirreduce porapply e teremos anteriormente, para retornar uma lista contendo somente os
a mesma resposta, como demonstra o cdigo da Listagem 7. nmeros mltiplos de trs. Para sabermos o tamanho dessa lista,
faremos uso da funo count, que tambm pertence biblioteca
padro do Clojure. Separando os nmeros triplos e contando
Listagem 7. Cdigo completo usando apply.
quanto eles so, chegamos ao resultado do nosso problema (veja
(def lista [1 2 3 4 5 6 7 8 9 10]) a Listagem 8).
(apply + (filter even? lista))
; 30
Listagem 8. Cdigo completo usando a funo triplo?.
tidade de linhas de cdigo, compare a simplicidade do cdigo (count (filter triplo? lista))
completo em Clojure com a verso escrita em Java.
Ao criar a funotriplo?, voc deu um nome a ela, permitindo Operadores -> e ->>
que ela seja usada tantas vezes quantas forem necessrias. S que Como vimos com as funes annimas, a biblioteca padro do
existem casos em que voc s vai utilizar a funo uma nica vez, Clojure prov uma srie de construes alternativas para que o
tornando desnecessrio que ela fique disponvel para o restante da cdigo fique mais limpo e simples de entender.
aplicao e, por conta disso, no havendo a necessidade de nome- Dentre essas formas, a linguagem oferece tambm dois opera-
la. A entram as chamadasfunes annimas, ou funes lambda. dores,->>e->, que tornam o cdigo mais legvel, mas que podem
Para criar uma funo annima, temos que usar a formafn. A parecer confusos primeira vista. Esses operadores so chamados
sintaxe parecida com a da forma defnque vimos antes, mas aqui de threads macros, arrows ou setas, dependendo do autor. O uso
voc no informa o nome da funo. Optando por uma funo desses operadores permite que o fluxo de transformao dos
annima, nosso cdigo ficar assim: dados se torne explcito e facilmente compreendido para quem
ler o cdigo.
(count (filter (fn [num] (= (mod num 3) 0)) lista)) Vamos comear pelo operador->>, chamado dethread last. Este
recebe uma lista de parmetros, pega a primeira expresso da
Caso voc ache que o cdigo ficou difcil de ler, recomenda-se lista e passa como ltimo parmetro da expresso seguinte.
que ele seja formatado alinhando os argumentos das funes um O resultado dessa operao passado como parmetro para a
embaixo do outro, como exposto na Listagem 9. prxima expresso, e assim por diante. Os demais parmetros,
se existirem, so mantidos em suas respectivas posies. Por
Listagem 9. Cdigo formatado usando uma funo annima.
exemplo, o cdigo (->> 3 (+ 1 2)) o equivalente a (+ 1 2 3), como
veremos com maiores detalhes a seguir.
(count Para explicar na prtica como esse operador funciona, vamos
(filter
(fn [num] voltar ao nosso exemplo dos mltiplos de 3 e reescrev-lo usando
(= (mod num 3) 0)) o ->>. Para facilitar, leve em considerao que, ao utilizar este
lista)) operador, voc precisa ler a sua expresso do final para o comeo.
Isso acontece porque o Clojure avalia as expresses de dentro
Apenas a ttulo de curiosidade, quando utilizamos a for- para fora, como j dissemos no incio do artigo: a expresso que
ma defn para darmos um nome a uma funo, o Clojure in- estiver mais aninhada ser avaliada primeiro, em seguida a ime-
ternamente usadefefnem conjunto, ou seja, quando criamos diatamente menos aninhada e assim sucessivamente at que toda
uma funodobrousando (defn dobro [x] (* x 2)), o compilador a expresso tenha sido avaliada.
converte para algo como(def dobro (fn [x] (* x 2))). Usando a Listagem 8 como exemplo, veremos que a expresso mais
Em alguns casos, declarar uma funo annima dessa forma aninhada do nosso cdigo (filter triplo? lista). Assim, pegamos o
pode tornar o cdigo difcil de ler. Por isso, existe ainda outra ltimo parmetro,lista, e passamos para o restante da expresso,
forma de declararmos uma funo annima, que empregando a que (filter triplo?). Feito isso nosso cdigo vai ser modificado para
forma reduzida#( ), que funciona como ofn, mas sem especificar (->> lista (filter triplo?)). O resultado dessa expresso passado por
os parmetros. Caso a funo receba um parmetro, o utiliza- parmetro para a funocount, que vai para a ltima posio da lista
remos atravs do smbolo%. Caso a funo receba mais de um de argumentos do operador ->>, ficando (->> lista (filter triplo?)
parmetro, usaremos%1para o primeiro parmetro,%2para o count). Apresentando esse cdigo de maneira formatada, temos:
segundo, e assim por diante. A forma#( ) meramente uma-
car sinttico, que internamente vai ser interpretado como se voc (->> lista
tivesse usadofn. Portanto, fique a vontade para usar a forma que (filter triplo?)
for mais conveniente. (count))
Com essa forma reduzida, temos o cdigo da Listagem 10.
Recapitulando, dessa vez no sentido oposto, pegamos lista e
passamos como o ltimo parmetro da expresso seguinte, que
Listagem 10. Cdigo formatado usando funo annima em sua forma reduzida.
(filter triplo?). A expresso vai ser entendida pelo compilador
(count como (filter triplo? lista), e o resultado, vai ser passado como
(filter
#(= (mod % 3) 0)
ltimo parmetro para a expresso seguinte, que (count), sendo
lista)) avaliado como(count (filter triplo? lista)), que exatamente o
cdigo original que usamos como exemplo, que est completo
na Listagem 8.
Perceba como o cdigo ficou mais limpo. Como j foi dito, J o operador->trabalha quase da mesma forma, mas passando
tantofnquanto#( )vo gerar exatamente o mesmo cdigo in- o resultado da expresso anterior como o primeiro parmetro da
ternamente, sendo a escolha de um ou de outro uma questo de expresso seguinte. Vamos usar um clculo simples para entender
preferncia de acordo com a situao. a diferena. Veja a Listagem 11.
No nosso exemplo, caso a funo no receba nenhum argumento, Listagem 14. Usando def dentro de uma funo.
retornar o textoNenhum parmetro. Caso receba apenas um
(def x 10)
parmetro, retornarUm parmetroe, caso receba dois par-
metros, retornar o texto Dois parmetros. Porm, ao usar trs (defn errado []
ou mais parmetros, voc receber uma mensagem de erro. Caso (def x 40)
voc s precise de at dois parmetros, nossa funo suficiente, (println O valor de x dentro x))
(defn certo []
Macros
(let [x 40] Macros so construes que permitem que voc estenda o
(println O valor de x dentro x))) compilador do Clojure escrevendo cdigo em Clojure. Visual-
mente elas se parecem com funes, tendo um nome, uma lista
(println O valor de x antes x)
de argumentos e um corpo que ser executado, assim como uma
(certo) funo, mas na prtica tm propsitos diferentes. Imagine se voc
pudesse criar novas palavras chaves ou construes em Java que
(println O valor de x depois x) fossem compiladas e executadas exatamente da mesma forma
que as construes nativas. Enquanto em Java isso no possvel,
; O valor de x antes 10
macros permitem que voc faa isso em Clojure.
; O valor de x dentro 40
Listagem 17. Demonstrando o uso das funes rest, str e apply.
; O valor de x depois 10
(def texto cebola)
Listagem 16. Usando let para organizar o cdigo em passos lgicos.
(rest texto)
(use [clojure.string :only [lower-case upper-case]]) ; (\e \b \o \l \a)
de dados fictcio ser apagado. Caso contrrio, o usurio receber nomes completos, contendo inclusive os namespaces de origem.
uma mensagem de erro e nada ser apagado. Criamos tambm a Isso serve para garantir que o compilador vai usar exatamente
funounlesse a executamos passando respectivamente false e a funo ou o operador que precisa, sem se preocupar com fun-
depois true como parmetros, para que possamos testar as duas es que tenham o mesmo nome, mas que esto em namespaces
condies possveis. diferentes. Vamos ver como osyntax quotefunciona na prtica na
Listagem 20.
Listagem 18. Criando a construo unless como uma funo.
Listagem 20. Usando syntax quote.
(defn unless [condition falsey truey]
(if-not condition `(if-not true 0 1)
falsey ; (clojure.core/if-not true 0 1)
truey))
voc precisa resolver. Por consequncia, faz com que a criao A brincadeira no termina aqui
de linguagens especficas de domnio seja algo completamente Neste artigo foi apresentada apenas uma pequena parte dessa
transparente. linguagem to poderosa chamada Clojure. Existem inmeros
Existe um livro, chamadoLet Over Lambda, que explica de manei- recursos que pretendemos abordar aqui naJava Magazinecomo,
ra profunda o funcionamento e a criao de macros em Common por exemplo, integrao com Java, programao concorrente,
LISP, que uma linguagem prima do Clojure e parecida em vrios criao de projetos para Web, recurso, lazy sequences, list
aspectos. Assim que voc j estiver familiarizado com os demais comprehension, memorization e mais uma lista enorme de
recursos que foram apresentados neste artigo, recomenda-se uma coisas bacanas.
lida nos captulos abertos disponveis no site do livro para que De qualquer maneira, o que foi abordado mais do que su-
voc tenha uma boa ideia do quo poderoso esse recurso. ficiente para que voc comece a brincar e se acostumar com a
cara diferente da linguagem. Com o tempo, voc vai notar que
Listagem 22. Cdigo completo usando macro. se tornou um desenvolvedor melhor na sua linguagem favorita
simplesmente pelo fato de ter aprendido novas formas de pensar
(defmacro unless [condition falsey truey]
`(if-not ~condition e de resolver problemas.
~falsey
~truey))
Links:
(drop-database false)
; Acesso negado Site oficial da linguagem Clojure.
http://clojure.org
(drop-database true)
; O banco foi apagado Site do Leiningen.
http://leiningen.org/ C
M
Site do livro Let Over Lambda.
http://letoverlambda.com/
Autor
Y
Plnio Balduino
https://gist.github.com/pbalduino MY
pbalduino@gmail.com
desenvolvedor h 18 anos, autor do livro Dominando JavaScript CY
com jQuery, pela editora Casa do Cdigo e do curso Ruby on Rails Voc gostou deste artigo? CMY
do comeo ao Fim, pelo iMasters Pro. Criou a linguagem Lucio para fins
de aprendizado e colaborou com a engine JavaScript dynjs. Atualmente
K
organiza os encontros do (clj-sp), Grupo de Usurios Clojure de So Paulo, administrador D seu voto em www.devmedia.com.br/javamagazine/feedback
da lista Clojure Brasil, membro ativo das listas Clojure Portugal, da lista oficial da linguagem Ajude-nos a manter a qualidade da revista!
e apresenta palestras e coding dojos sobre Clojure pelo pas.
CM
MY
CY
CMY
CM
MY
CY
CMY