9 771676 836002
00150
EXPEDIENTE
Editor
Eduardo Spnola (eduspinola@gmail.com)
Consultor Tcnico Diogo Souza (diogosouzac@gmail.com)
Produo
Jornalista Responsvel Kaline Dolabella - JP24185
Capa e Diagramao Romulo Araujo
Distribuio
FC Comercial e Distribuidora S.A
Rua Teodoro da Silva, 907, Graja - RJ
CEP 20563-900, (21) 3879-7766 - (21) 2577-6362
Atendimento ao leitor
muito importante para a equipe saber o que voc est achando da revista:
que tipo de artigo voc gostaria de ler, que artigo voc mais gostou e qual
artigo voc menos gostou. Fique a vontade para entrar em contato com os
editores e dar a sua sugesto!
Se voc estiver interessado em publicar um artigo na revista ou no site Java
Magazine, entre em contato com o editor, informando o ttulo e mini-resumo
do tema que voc gostaria de publicar:
Publicidade
publicidade@devmedia.com.br 21 3382-5038
Anncios Anunciando nas publicaes e nos sites do Grupo DevMedia,
voc divulga sua marca ou produto para mais de 100 mil desenvolvedores
de todo o Brasil, em mais de 200 cidades. Solicite nossos Media Kits, com
detalhes sobre preos e formatos de anncios.
Sumrio
Artigo no estilo Curso
Destaque - Vanguarda
Feedback
eu
sobre e
s
D
s
[ Marlon Patrick ]
edio
ta
Contedo sobre Novidades
D seu voto sobre esta edio, artigo por artigo, atravs do link:
www.devmedia.com.br/javamagazine/feedback
Porm, se tivssemos um cluster com vrios servidores conectados, deveramos passar uma lista com os IPs de alguns
deles na chamada desse mtodo.
Com uma conexo aberta para o cluster, deve-se conectar
ao bucket criado para nossa aplicao. Para isso, chama-se o
mtodo openBucket() do cluster passando como argumento
o nome e a senha do bucket. Por fim, aps seu uso, fechamos
a conexo com o cluster, o que possibilita a liberao dos
recursos utilizados e desencadeia no fechamento da conexo
do bucket.
A partir do momento em que uma conexo aberta, o objeto
que ser utilizado por todo o sistema para acessar o banco
ser o bucket. Deste modo, esse pode ser configurado como
singleton no sistema, possibilitando que seja injetado pelo
Spring ou outro framework de injeo de dependncias. Por
outro lado, o cluster usado apenas para abrir conexes com
buckets e desconectar de todos eles de uma s vez atravs do
disconnect(), caso o sistema utilize mais de um. Portanto, o
objeto cluster ter esse mtodo invocado no shutdown do
sistema para que os recursos sejam liberados.
A seguir, os principais mtodos da classe Bucket so explicados:
AsyncBucket async(): retorna uma verso assncrona do
Bucket. Com essa verso, todos os mtodos comuns do Bucket
estaro disponveis, porm, eles retornam um Observable do
RxJava, biblioteca que vem crescendo em adoo e cujo uso
recomendado. Como est fora do escopo deste artigo explic-la,
sero mostrados aqui apenas os mtodos sncronos;
JsonDocument get(String id): retorna o documento cujo
identificador seja igual ao passado como parmetro. Caso tal
documento no exista, null ser retornado;
JsonDocument getAndLock(String id, int lockTime): funciona da mesma maneira que o mtodo anterior, contudo, esse
mtodo utilizado para a concorrncia pessimista, explicada
anteriormente. Assim, caso o documento seja encontrado, ele
ser retornado e bloqueado. Caso esse mtodo seja invocado
novamente enquanto o documento estiver bloqueado, uma
Vale notar que todas as operaes que modificam um documento, vistas anteriormente, utilizam de concorrncia otimista
caso o valor de CAS esteja presente. Se houver diferena entre
o valor de CAS passado pelo cliente e o valor do servidor, assume-se que tal documento foi alterado em paralelo e a exceo
CASMismatchException lanada para indicar o ocorrido.
Com a viso bsica dos principais mtodos de Bucket, o prximo
passo explorar a interface Document e sua principal implementao, JsonDocument, a qual usaremos na maior parte do tempo.
Como mencionado na discusso sobre modelagem de documentos, ser utilizado um esquema de mapeamento com controle de
verso. Vejamos a explicao e o cdigo de exemplo desse mtodo
no tpico a seguir.
Mapeadores de documentos
O mapeamento de objetos se dar atravs de classes simples,
expostas adiante. Antes de mostrar esse cdigo, no entanto, sero apresentadas as entidades de exemplo. Vale notar que todas
elas implementaro uma classe abstrata, chamada Entity, com o
intuito de tornar disponvel em todas as entidades as seguintes
propriedades: String id, DateTime createdAt, DateTime lastModified e Long revision. Com elas, armazenamos o identificador do
documento, o momento em que o mesmo foi inserido, o momento
em que foi modificado pela ltima vez e o valor do CAS.
Para exemplificar, sero criadas apenas duas entidades: Task e
Category. A entidade Task representar uma tarefa a ser realizada e Category a encaixar em determinada categoria de tarefas.
Tal aplicao ser uma simples TODO List. Para torn-la o mais
simples possvel, ambas as entidades tero somente um campo,
chamado name, para armazenar o nome da tarefa e da categoria,
e a tarefa possuir ainda uma referncia para sua categoria, o que
configura uma relao de um para muitos.
Com as entidades prontas, deve-se criar os mapeadores de
documentos para as mesmas. A Listagem 2 mostra a interface
implementada por todos os mapeadores. Essa utiliza generics para
especificar qual tipo de entidade tal mapeador tratar, especificando seus dois mtodos de converso. Alm disso, quatro campos
que estaro presentes em todos os documentos so especificados
atravs de constantes. E para facilitar o trabalho das implementaes dessa interface, a classe AbstractDocumentMapper,
mostrada na Listagem 3, implementa os mtodos do mapeador de
forma a tratar os metadados do documento, como o identificador,
momento de criao e ltima modificao e o valor do CAS.
O primeiro ponto a se notar no cdigo de AbstractDocumentMapper o uso da classe ISODateTimeFormat, da biblioteca Joda
Time. O objetivo com isso que todos os timestamps sejam salvos
no formato padro definido pela ISSO 8601. Tal formato tem a vantagem de ter um ordenamento natural das datas, de forma que uma
ordenao simples de Strings colocaria os timestamps em ordem.
10
E getEntity(JsonDocument document);
JsonDocument getDocument(E entity);
}
Listagem 3. Classe abstrata criada com o propsito de ser superclasse de todos os
mapeadores.
public abstract class AbstractDocumentMapper<E extends Entity> implements
DocumentMapper<E> {
protected DateTimeFormatter dateTimeFormatter;
protected AbstractDocumentMapper() {
this.dateTimeFormatter = ISODateTimeFormat.dateTime();
}
@Override
public JsonDocument getDocument(E entity) {
JsonObject properties = JsonObject.create();
String id = entity.getId();
Long rev = entity.getRevision();
properties.put(CREATED_AT, entity.getCreatedAt().
toString(dateTimeFormatter));
properties.put(LAST_MODIFIED, entity.getLastModified().
toString(dateTimeFormatter));
return JsonDocument.create(id, properties, rev != null ? rev : 0);
}
protected void fillMetadata(E entity,JsonDocument document){
entity.setId(document.id());
entity.setRevision(document.cas());
JsonObject properties = document.content();
entity.setCreatedAt(dateTimeFormatter.parseDateTime((String)
properties.get(CREATED_AT)));
entity.setLastModified(dateTimeFormatter.parseDateTime((String)
properties.get(LAST_MODIFIED)));
}
}
return task;
@Override
public JsonDocument getDocument(Task task) {
JsonDocument document = super.getDocument(task);
JsonObject properties = document.content();
properties.put(TYPE, TaskDocumentMapper.DOC_TYPE);
properties.put(TYPE_VERSION, 1L);
properties.put(NAME, task.getName());
Category category = task.getCategory();
if(category != null){
properties.put(CATEGORY_ID, category.getId());
}
return document;
return category;
@Override
public JsonDocument getDocument(Category category) {
JsonDocument document = super.getDocument(category);
JsonObject properties = document.content();
properties.put(TYPE, CategoryDocumentMapper.DOC_TYPE);
properties.put(TYPE_VERSION, 1L);
properties.put(NAME, category.getName());
return document;
11
11
public TaskDocumentMapper(TaskDocumentMapperV1
taskDocumentMapperV1) {
this.mappers = new HashMap<>();
this.mappers.put(CURRENT_VERSION, taskDocumentMapperV1);
}
public CategoryDocumentMapper(CategoryDocumentMapperV1
categoryDocumentMapperV1) {
this.mappers = new HashMap<>();
this.mappers.put(CURRENT_VERSION, categoryDocumentMapperV1);
}
@Override
public Task getEntity(JsonDocument document) {
return mappers.get(((Number)document.content().get(TYPE_VERSION))
.intValue()).getEntity(document);
}
@Override
public Category getEntity(JsonDocument document) {
return mappers.get(((Number)document.content().get(TYPE_VERSION)).
intValue()).getEntity(document);
}
@Override
public JsonDocument getDocument(Task task) {
return mappers.get(CURRENT_VERSION).getDocument(task);
}
@Override
public JsonDocument getDocument(Category category) {
return mappers.get(CURRENT_VERSION).getDocument(category);
}
}
12
Utilizando Views
A forma de busca por dados utilizada no Couchbase algo novo
e completamente diferente das tradicionais consultas SQL. Assim,
ao invs de utilizar uma linguagem de busca de dados como em
bancos relacionais, o Couchbase utiliza da lgica de MapReduce
para indexar os dados em Views, as quais so uma forma de
organizao de um index de busca criado no banco e permitem
extrao, filtro, agregao e busca de informao.
O processo de criao de uma View se d pela configurao de
uma ou duas funes. A primeira a funo de map, que filtra
entradas e pode extrair informao. Seu resultado final uma lista
ordenada de chave-valor, chamada de index, que armazenada
em disco e atualizada de forma incremental medida que os
documentos so atualizados. Opcionalmente, pode-se prover uma
segunda funo, chamada reduce, que tem o objetivo de somar,
agregar ou realizar outros clculos sobre as informaes.
Quando nos referimos a funes, estamos mencionando rotinas
programadas em JavaScript, as quais sero executadas em cada
um dos documentos. Essas rotinas de map e reduce das Views
so armazenadas como strings em documentos especiais JSON,
13
13
14
O funcionamento dessa funo simples. Primeiro, certificase que o documento atual do tipo JSON, lembrando que
ele poderia ser binrio, armazenar Strings, ou outros tipos
mencionados anteriormente. Ento, verificamos se o tipo
do documento, armazenado no campo type, igual a task,
lembrando que esse campo foi criado em nossos mapeadores.
Por fim, emitimos o campo createdAt, que tem como valor
a data de criao em formato ISO. Como no ser utilizada
uma funo de Reduce, o valor passado para a funo emit()
nulo. Em JavaScript, um argumento nulo pode simplesmente
ser ignorado.
Para testar essa View pode-se executar parte do cdigo mostrado na Listagem 9, retirando o trecho que remove os documentos
A parte a se notar dessa tcnica a seguinte: chaves tambm podem ser emitidas como arrays, como pode ser visto nas invocaes
de emit(). Quando isso feito, as chaves continuaro sendo ordenadas naturalmente, mas utilizando todos os elementos do array
de forma que o elemento seguinte considerado apenas em caso
de empate na ordenao baseada no elemento anterior. Voltando
View criada, essa emitir todos os documentos de categoria e
tarefa. Os documentos de categoria tero como chave um array de
elemento nico com o identificador de cada documento, enquanto
os documentos de tarefa tero um array com o identificador da
categoria e a data de criao da tarefa como chave.
Quando essas chaves so ordenadas, as categorias e suas tarefas
ficam juntas, visto que suas chaves comeam com o identificador
da categoria. Com essas chaves emitidas, o registro da categoria
aparece antes das tarefas, j que sua chave possui apenas um
elemento, e logo aps a categoria, todas as tarefas relacionadas
so dispostas, ordenadas por sua data de criao.
Com essa ordenao, a responsabilidade do cdigo Java que
utilizar essa View ser de diferenciar os documentos de categoria
dos de tarefa. Assim, ao iterar pelas linhas obtidas como resultado,
sempre que uma categoria for encontrada ela ser guardada em
uma varivel temporria e todas as tarefas subsequentes sero
admitidas como da categoria corrente e tero seu valor de categoria
ajustado com ela. O cdigo com essa lgica implementada pode
ser visualizado na Listagem 13.
Outro uso para essa View seria a busca por todas as tarefas de
uma categoria j conhecida. Isso poderia ser feito com os mtodos startKey() e endKey() de ViewQuery, como mostrado na
Listagem 14. Esses mtodos so usados para especificar um intervalo de chaves dos documentos que sero encontrados. Assim,
uma chave que, em ordenao natural, seja superior startKey()
e inferior endKey() ter seu documento listado.
No entanto, para que a tcnica de listagem das tarefas de determinada categoria funcione, devemos saber que um elemento
vazio de um array toma precedncia sobre qualquer valor,
quando tratamos de ordenao natural. Ento, utiliza-se como chave inicial um array com um nico elemento, a chave da categoria
procurada, e a chave final ser um array cujo primeiro elemento
a chave da categoria e o segundo a String especial \uefff.
Essa String representa um nico caractere UTF-8, que grande o
suficiente para garantir que nenhum valor do segundo elemento
das chaves seja maior em uma ordenao alfabtica. Traduzindo
tudo isso, buscamos por chaves que comecem com o identificador
da categoria e aceitamos qualquer valor como segundo elemento
da chave, desde vazio at um valor qualquer.
Essas tcnicas podem ser combinadas com outras para se buscar
registros atravs de Views. Para isso, no entanto, deve ser feito
um bom planejamento com o intuito de reutilizar essas Views
na medida do possvel, pois uma criao excessiva delas pode
gerar um impacto bastante negativo na performance do banco
de dados.
A outra funo de uma View fazer resumo de dados. Para isso,
recomenda-se o uso da funo Reduce, que no ser apresentada
15
15
Uma boa notcia para aqueles que ficaram receosos com essa
forma de pesquisar dados, em verses mais novas do Couchbase
encontrada uma nova ferramenta: a N1QL. Conhecida como o
SQL para JSON, possui uma linguagem praticamente idntica
ao SQL. Ela no foi abordada neste artigo porque relativamente
nova e vem evoluindo nas ltimas verses do Couchbase.
Para suprir as necessidades de grandes aplicaes como o
Facebook e as solues do Google, diversas opes de bancos de
dados foram surgindo, resultando na criao do acrnimo NoSQL
para defini-las. Dentre elas, bancos como o Apache Cassandra e
BigTable foram criados e por fim abertos ao pblico.
Nessa linha de novos bancos, o primeiro a se destacar com estrutura de dados baseada em documentos foi o MongoDB, o qual
permanece sendo o mais utilizado nos dias de hoje. Porm, com a
fuso do CouchDB com o Membase surgiu um forte concorrente,
que foi apresentado neste artigo: o Couchbase.
Alm de demonstrar melhor performance que a concorrncia
em testes de benchmark, o Couchbase facilita a criao de novos
tipos de aplicao: aquelas que requerem funcionamento offline. Um grande exemplo disso so aplicaes mobile que tm o
contedo fornecido por um servidor, mas que devero trabalhar
frequentemente sem acesso internet. Para essas existe a combinao do Couchbase Server com o Couchbase Lite interligados
pelo Sync Gateway. Pelo lado do servidor, deve-se simplesmente
configurar o Sync Gateway para criar um meio de acesso ao
Couchbase Server. J pelo lado da aplicao mobile, utiliza-se
o Couchbase Lite para armazenar, recuperar e sincronizar os
dados com o servidor. Sua programao muito semelhante
16
Autor
Fernando Henrique Fernandes de Camargo
fernando.camargo.ti@gmail.com
desenvolvedor Java EE, Android e Grails. Atualmente mestrando em Engenharia de Computao na UFG. Desenvolve em
Java desde 2009 e para Android desde 2012. Possui a certificao OCJP6,
artigos publicados na Easy Java Magazine e na Java Magazine, alm de
palestras e minicursos apresentados em eventos.
Links:
Artigo sobre NoSQL.
www.couchbase.com/nosql-resources/what-is-no-sql
Comparao entre Couchbase e CouchDB.
www.couchbase.com/couchbase-vs-couchdb
Guia de desenvolvimento do Couchbase.
docs.couchbase.com/developer/dev-guide-3.0
Artigo sobre concorrncia otimista e pessimista.
blog.couchbase.com/optimistic-or-pessimistic-locking-which-one-should-you-pick
Instrues de instalao do Couchbase.
docs.couchbase.com/admin/admin/install-intro.html
Guia de desenvolvimento do Java SDK.
docs.couchbase.com/developer/java-2.1/java-intro.html
JAR com SDK do Couchbase.
mvnrepository.com/artifact/com.couchbase.client/java-client/2.1.4
Programador Java:
Por onde comear?
Descubra nesse vdeo como entrar
na carreira Java com o p direito!
DEVMEDIA
http://www.devmedia.com.br/programador-java-por-onde-comecar/33638
Edio 150 Java Magazine
Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia
17
17
om a exploso da Internet que vivenciamos atualmente, muitos novos desafios esto surgindo
para a indstria de software, desde a preocupao com a escalabilidade das aplicaes, que agora
possuem milhes de usurios, at mesmo a melhoria
contnua da usabilidade desses sistemas, dado que os
usurios se tornam cada vez mais exigentes e desejam
mais facilidades.
Um desses desafios trata-se do armazenamento e
processamento da imensa massa de dados gerada pelos
diversos servios disponveis. Por conta dela, novas
tecnologias de banco de dados emergiram nos ltimos
anos para atender uma srie de requisitos que o modelo mais tradicional (Relacional) no conseguiu suprir.
A esse novo movimento de tecnologias de bancos de
dados deu-se o nome de NoSQL.
Diante da relevncia do tema, apresentamos na primeira parte desse artigo um dos bancos NoSQL mais
renomados desse ecossistema, o Apache Cassandra. Para
18
Evoluindo o WebShelf
Na primeira parte do artigo iniciamos o desenvolvimento do
WebShelf: uma aplicao que possibilita aos seus usurios manter uma prateleira de livros online ao estilo do Amazon Shelfari.
At o momento, as principais configuraes do projeto j foram
demonstradas e explicadas, o que nos possibilita agora focar mais
nas funcionalidades da aplicao.
19
@MessageBundle
public interface Messages {
20
O ganho com PreparedStatements verificado quando uma instruo executada repetidas vezes, pois com esse tipo de statement
o parse acontece uma nica vez em cada n que for execut-lo.
Nas execues subsequentes, apenas o ID do statement e os valores dos parmetros so enviados pela rede. Considerando isso
em um ambiente distribudo com vrios ns, uma melhora de
performance significativa pode ser obtida.
Por fim, saiba que o mtodo prepare() sempre retornar uma nova
instncia de BoundStatement, a qual ser utilizada pelos clientes
para fazer o bind dos parmetros contidos na instruo CQL.
BOX 1. Caches
Como j demonstrado na implementao de CassandraCluster, a utilizao de caches ao se
trabalhar com Cassandra de fundamental importncia. Portanto, vale a pena estudar mais a
fundo as estratgias de cache a fim de identificar a que melhor se adequa sua realidade. Apesar
de ser possvel utilizar maps para esse intuito, como fizemos aqui, esta no a nica maneira e,
principalmente, no a melhor abordagem para grandes aplicaes. Por exemplo, voc pode
precisar de um cache que expira itens (mais antigos, menos utilizados, etc.) ou caso contrrio ir
acumular uma grande quantidade de objetos e poder ter problemas de estouro de memria.
21
22
if (!constraintViolations.isEmpty()) {
throw new ConstraintViolationException(constraintViolations);
}
}
}
Como pode ser visto no mtodo executeBeanValidation(), nesta classe injetamos um Validator para
invocar as validaes da API Bean Validation. Alm
disso, injetado um CassandraCluster para realizar
a comunicao com o Cassandra.
Ainda analisando este cdigo, o mtodo findUserByLogin() obtm um Mapper<User> e ento
faz a consulta pelo login, que nesse caso tambm
a primary key da tabela. Essa consulta realizada
atravs do mtodo Mapper.get(), que aceita uma
lista de parmetros correspondente primary key da
tabela na ordem declarada na sua criao. O retorno
um objeto com os campos devidamente preenchidos Figura 1. Exemplo de race condition Fonte: FinishJUG
graas ao mapeamento feito na classe User. Operao
semelhante acontece no mtodo deleteUser(), que tambm faz uso
inicial da aplicao, caso contrrio, uma mensagem de erro dever
de Mapper para remover o registro.
ser mostrada. Para quem ainda no tem cadastro, ser disponibilizado um boto que levar o usurio para a tela de Cadastro
Usando Lightweight Transactions (LWT) para garantir a unicidade
de Usurio.
Por fim, tem-se o mtodo insertUser(), o qual cadastra o usurio
no Cassandra. Apesar da classe Mapper possuir um mtodo save()
Elaborando pgina responsiva de login com PrimeFaces
que poderia ser usado aqui, foi necessrio criar um statement
A tela de login tem quatro componentes principais, conforme
manualmente atravs do mtodo CassandraCluster.boundInpode ser visto na Listagem 8: um input de login, outro da senha,
sertUser() para que fosse possvel usar lightweight transactions, j
um boto para efetuar o login e outro para se cadastrar.
que o Mapper no oferece (ainda) essa possibilidade.
Observe que o parmetro renderedMenuBar, logo no incio do
Como j informado, no WebShelf o login do usurio nico. Para
cdigo, foi setado para false, j que no deve ser exibido nenhum
garantir essa regra em bancos de dados relacionais, normalmente
menu enquanto o usurio no se logar.
usamos uma transao, na qual executada uma consulta para
Com o intuito de deixar a tela responsiva, utilizamos os mesmos
verificar a existncia do login. Caso ele no exista, executado o
recursos apresentados na Listagem 1. Assim, todos os compocomando de insert e finalmente feito o commit da operao.
nentes visuais da pgina foram englobados por uma div que
No Cassandra, por sua vez, no possvel proceder dessa forma
tem a classe ui-fluid e os inputs foram organizados dentro de
devido ausncia de transaes ACID. Desse modo, se voc tentar
componentes p:panelGrid configurados para usar o Grid CSS
fazer isso, poder cair numa race condition, como exemplificado
(layout=grid). Alm disso, os p:panelGrid definiram o tamanho
na Figura 1. Para contornar esse problema foi criado o conceito de
de suas colunas em funo das 12 colunas que o Grid CSS usa para
LWT, que no caso da insero do usurio se caracteriza pelo uso
dividir a tela responsivamente (ui-grid-col-*).
da seguinte condio ao fim do insert: IF NOT EXISTS. Ou seja,
ao invs de fazer uma consulta para verificar se o login existe ou
no, no ato do insert j ser feito essa checagem sem que outras
requisies interfiram na operao.
A execuo dessa instruo retorna um ResultSet a partir do
qual possvel checar se o insert foi aplicado ou no atravs do
mtodo wasApplied(). Caso este retorne false, significa que o
login ja existe.
Contudo, como dito na primeira parte deste tutorial, essa feature deve ser usada com moderao, pois impacta fortemente
na performance. Nesse exemplo, optou-se por fazer uso de LWT
porque a regra de unicidade de usurio considerada crtica para
a aplicao.
Implementao do Login
Como em quase todas as aplicaes web, tambm iremos desenvolver um mecanismo de login. O funcionamento deste ser
simples: o usurio ter que informar o seu login e sua senha e,
caso tudo esteja correto, dever ser redirecionado para a pgina
23
24
// imports omitidos...
@Named
@RequestScoped
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private HttpServletRequest request;
@Inject
private UserBean userBean;
@Inject
private JsfMessage<Messages> messages;
@NotBlank(message=Senha: no pode est em branco.)
private String password;
@NotBlank(message=Login: no pode est em branco.)
private String login;
public String getPassword() {
return this.password;
}
public String getLogin() {
return this.login;
}
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
package br.com.devmedia.webshelf.util;
import br.com.devmedia.webshelf.model.User;
public class ResourceProducer {
@Inject
private HttpSession session;
@Produces
@LoggedInUser
@SessionScoped
@Named(loggedInUser)
protected User getLoggedInUser() {
User loggedInUser = (User)session.getAttribute(loggedInUser);
if(request.getSession(Boolean.FALSE) != null){
request.getSession(Boolean.FALSE).invalidate();
}
request.getSession().setAttribute(loggedInUser, user);
return /private/home.xhtml?faces-redirect=true;
if (loggedInUser == null) {
loggedInUser = new User();
}
}
public String logout() throws ServletException {
request.getSession().removeAttribute(loggedInUser);
request.getSession().invalidate();
return /public/login.xhtml?faces-redirect=true;
}
}
return loggedInUser;
}
}
25
25
Como podemos observar, a implementao do mtodo getLoggedInUser() bem simples. Ele retorna o usurio logado que
est na sesso caso exista um. Vale lembrar que o usurio logado
colocado na sesso atravs do mtodo LoginController.doLogin(). Se no houver nenhum usurio logado, ento ele devolve
um objeto User vazio. Isso porque no permitido retornar
nulo em mtodos produtores no CDI.
Listagem 11. Qualifier CDI para Usurio logado
package br.com.devmedia.webshelf.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggedInUser {
}
@Inject
private User dummyUser;
Cadastro de Livro
O cadastro de livro permitir ao usurio do WebShelf cadastrar
novos livros que, por ventura, ele no tenha conseguido encontrar
26
na pesquisa. Essa funcionalidade seguir o mesmo molde do cadastro de usurio, que composto de uma tela JSF, um controller
e um bean de negcio.
Nota
Atualmente a API de object-mapping bastante limitada, e por conta disso seu uso ser restrito a
cenrios mais simples, normalmente CRUDs sem qualquer feature mais complexa do Cassandra.
package br.com.devmedia.webshelf.model;
import java.nio.ByteBuffer;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
public class Book {
import br.com.devmedia.webshelf.model.User;
import br.com.devmedia.webshelf.util.LoggedInUser;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((isbn == null) ? 0 : isbn.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (isbn == null) {
if (other.isbn != null)
return false;
} else if (!isbn.equals(other.isbn))
return false;
return true;
}
27
27
28
29
29
30
Autor
Marlon Patrick
marlon.patrick@mpwtecnologia.com - marlonpatrick.info
bacharel em Cincia da Computao e atua como Consultor
Java no Grupo Mquina de Vendas com aplicaes de misso
crtica, tem oito anos de experincia com tecnologia Java e certificado
SCJP 5.
31
31
Introduo ao Java 9:
Conhea os novos
recursos
Aprenda neste artigo as principais novidades do
JDK, que trar para o Java a modularizao, jShell,
HTTP 2.0, JMH, entre outras melhorias
plataforma Java uma das opes mais populares quando pensamos em desenvolvimento de
aplicaes, e isso se torna ainda mais evidente
quando o escopo so as solues voltadas para a web.
Atualmente, estima-se que cerca de nove milhes de
desenvolvedores adotam o Java. Completando 20 anos
em breve, a plataforma classificada por muitos como
antiga, nesse universo em que novas solues surgem
e desaparecem num piscar de olhos.
Todo esse tempo, obviamente, possibilitou mais robustez e confiabilidade ao Java, no entanto, por ser projetada
com alguns conceitos hoje tidos como obsoletos, a exemplo da arquitetura no-modular, possui uma estrutura
monoltica, ou seja, no dividida em mdulos. Essa
ausncia, presente em algumas das linguagens mais
modernas, torna mais difcil o reuso e a manuteno do
cdigo, restringindo a sua utilizao, principalmente, em
dispositivos de baixa capacidade de processamento. Por
causa disso, h muito tempo a comunidade Java solicita
uma grande reforma na estrutura da plataforma, com o
objetivo de torn-la modular.
Vale lembrar, ainda, que ao longo de sua histria a
plataforma Java cresceu de um pequeno sistema criado
para dispositivos embarcados para uma rica coleo de
bibliotecas, que atende s mais diversas necessidades e
que precisam rodar em ambientes com sistemas operacionais e recursos de hardware distintos. Hoje sabemos
que possuir um canivete suo com tantos recursos
essencial ao desenvolvedor, contudo, essa abundncia
tambm traz alguns problemas:
32
33
33
Essas caractersticas auxiliam no desenvolvimento de aplicaes, bibliotecas e da prpria plataforma Java, pois garante
maior escalabilidade com aplicaes/plataformas mais enxutas,
e apenas com as dependncias necessrias; maior integridade,
ao evitar a utilizao de dependncias cujas verses no so as
mais adequadas; assim como grandes melhorias em termos de
desempenho, com a resoluo de dependncias e coleta de lixo
mais eficientes, bem como um tamanho menor dos arquivos de
execuo.
Mdulos
Os mdulos so um novo tipo de componente do Java, possuindo um nome e um cdigo descritivo, isto , um arquivo que
define os detalhes e propriedades dos mesmos, alm de outras
informaes adicionais. Essas informaes adicionais descrevem,
basicamente, configuraes de servios ou recursos que o mdulo
pode utilizar.
No cdigo descritivo, por sua vez, o mdulo deve informar se
faz uso de tipos (classes, interfaces ou pacotes) de outros mdulos,
de forma que a aplicao possa compilar e executar sem erros.
Para isso, deve-se utilizar a clusula requires em conjunto com
o nome do recurso. Alm disso, pode ser necessrio informar ao
compilador quais tipos desse mdulo podem ser acessados por
outros, ou seja, declarar quais recursos ele exporta, o que feito
atravs da clusula exports.
A partir disso, o sistema de mdulos localiza os mdulos necessrios e, ao contrrio do sistema de classpath, garante que o
cdigo de um mdulo acesse apenas os tipos dos mdulos dos
quais ele depende. Como complemento, o sistema de controle de
acesso da linguagem Java e da mquina virtual tambm previnem
34
que cdigos acessem tipos oriundos de pacotes que no so exportados pelos mdulos que os definem.
Com o intuito de evitar a forte dependncia entre mdulos, um
mdulo pode declarar que utiliza (uses) uma interface (tipo genrico) em vez de uma classe (tipo especfico) de um determinado
servio cuja implementao fornecida (provided) em tempo
de execuo por outro modulo. Essa estratgia permite que os
desenvolvedores possam, entre outras coisas, estender a API do
Java, codificando classes que implementam uma interface que
utilizada pelo mdulo em desenvolvimento, interface essa declarada atravs da sintaxe uses nomedainterface. Isso ocorre porque
a dependncia do mdulo que declara a interface com a classe
criada pelo desenvolvedor resolvida em tempo de compilao
e de execuo, sem necessidade de quaisquer intervenes. Juntamente a essa capacidade de resoluo de componentes genricos,
o sistema de mdulos mantm a hierarquia atual de classloaders,
facilitando a execuo ou migrao de aplicaes legadas para
verso 9 do Java.
Tendo em vista que os mdulos so descritos atravs de um cdigo, a maneira mais simples de declar-los especificar apenas
os seus respectivos nomes em um arquivo, conforme o cdigo a
seguir:
module br.com.devmedia {}
Como j mencionado, no entanto, existem mais opes de configurao, como informar que um mdulo depende de outro,
utilizando a clusula requires. Desse modo, supondo que o mdulo criado anteriormente (br.com.devmedia) dependa de outro
(br.com.devmediaOutro), a estrutura utilizada para descrever
essa relao ser semelhante exposta na Listagem 1.
possvel, ainda, declarar os pacotes do mdulo cujos tipos
pblicos podem ser acessados por outros, atravs da clusula
exports. Na Listagem 2, br.com.devmedia define que os pacotes
br.com.devmedia.pacote1 e br.com.devmedia.pacote2 podem
ser utilizados por outros mdulos. Portanto, se na declarao de
um mdulo no existe a clusula exports, o mdulo no ir, de
forma alguma, exportar pacotes para outros.
Listagem 1. Declarao do mdulo br.com.devmedia com dependncia ao mdulo br.com.devmediaOutro.
module br.com.devmedia {
requires br.com.devmediaOutro;
}
Listagem 2. Configurao do mdulo br.com.devmedia com dependncia e
exports declarados.
module br.com.devmedia {
requires br.com.devmediaOutro;
exports br.com.devmedia.pacote1;
exports br.com.devmedia.pacote2;
}
module java.base {
exports java.io;
exports java.lang;
exports java.lang.annotation;
exports java.lang.invoke;
exports java.lang.module;
exports java.lang.ref;
exports java.lang.reflect;
exports java.math;
exports java.net;
...
}
Artefatos de mdulos
Como sabemos, as ferramentas de linha de comando da plataforma Java so capazes de criar, manipular e consumir arquivos JAR.
Diante disso, de forma a facilitar a adoo e migrao para a nova
verso do JDK, os desenvolvedores criaram tambm o arquivo JAR
modular. Como se pode imaginar, um arquivo JAR modular um
arquivo JAR comum que possui a definio do mdulo compilada
(o arquivo module-info.class) no seu diretrio raiz (vide BOX 1). Por
exemplo, um JAR para o mdulo especificado anteriormente teria
a estrutura apresentada na Listagem 3.
Resoluo e dependncia
BOX 1. Arquivo JAR modular
Pode ser utilizado como um mdulo (a partir do Java 9) ou como um arquivo JAR comum (em
todas as verses). Assim, para fazer uso de um arquivo JAR modular como se fosse um JAR comum,
basta informar o mesmo no classpath da aplicao. Dessa forma o arquivo module-info.class ser
ignorado. Essa estratgia permite que aplicaes legadas, que executam em verses anteriores do
Java, possam se beneficiar de bibliotecas desenvolvidas de forma modular, mantendo com isso a
retrocompatibilidade.
35
35
module br.com.devmedia-app {
requires br.com.devmedia;
requires java.sql;
}
module java.sql {
requires java.logging;
requires java.xml;
exports java.sql;
Note que o mdulo ncleo da aplicao, no caso br.com.devmedia-app, seria o ponto de partida para que o sistema encontre
as dependncias necessrias para a mesma, tendo como base os
nomes dos mdulos indicados pela clusula requires do descritor
do mdulo inicial, como demonstrado no exemplo. Saiba, ainda,
que cada mdulo do qual o mdulo inicial depende pode depender de outros. Nestes casos, o sistema de mdulos procurar
recursivamente por todas as dependncias de todos os outros, at
que no reste nenhuma a ser acrescentada. Logo, se essa relao
de dependncia entre mdulos fosse desenhada em um grfico,
o desenho teria a forma de um grafo, no qual cada relao entre
duas dependncias seria expressa por uma aresta e cada dependncia seria um vrtice.
Com o intuito de construir o grafo com as dependncias do mdulo br.com.devmedia-app, o compilador precisa ler as descries
dos mdulos que ele depende (java.sql e br.com.devmedia). Logo,
para melhor compreender a construo desse grafo, preciso
dar uma olhada na declarao dos mdulos que se depende.
exports javax.sql;
exports javax.transaction.xa;
}
Nota
No foi criada uma nova listagem com a descrio do mdulo br.com.devmedia porque j foi
demonstrado na Listagem 2. Alm disso, para ser mais breve, tambm foram omitidas as descries
dos mdulos java.logging e java.xml, dos quais o mdulo java.sql depende.
36
Servios
Como sabemos, o baixo acoplamento de componentes
de software alcanado atravs de interfaces de servios e
provedores de servios uma poderosa ferramenta para a
construo de grandes sistemas. Por esse motivo, o Java suporta h um bom tempo essa tcnica atravs da classe java
.util.ServiceLoader, a qual utilizada pelo JDK e tambm por
bibliotecas e aplicaes.
Essa classe localiza provedores de servios em tempo de execuo ao procurar por arquivos de configurao dos servios
na pasta META-INF/services. Entretanto, se um servio fornecido por um mdulo, esses arquivos no estaro no classpath
da aplicao. Sendo assim, foi preciso implementar uma nova
estratgia para localizar os provedores de servios e carreg-los
corretamente, como demonstraremos a seguir.
Vejamos um exemplo: supon ha que o mdulo br.com
.devmedia-app usa um banco de dados PostgreSQL e que o
driver JDBC (recurso) para o mesmo seja fornecido em um
mdulo declarado de acordo com a Listagem 7.
Conforme pode ser observado nessa listagem, a declarao de
exportao de org.postgresql.jdbc refere-se ao pacote do mdulo
de mesmo nome, que possui o driver JDBC do banco de dados
Post-greSQL. Esse driver uma classe Java que implementa a
interface de servio java.sql.Driver, contida no mdulo java
.sql (veja a nota a seguir). Alm disso, para que o mdulo org
.postgresql.jdbc possa fazer uso dos mdulos dos quais
depende(java.sql e org.slf4j), preciso que os mesmos sejam adicionados ao grafo de mdulos em tempo de execuo, conforme
a Figura 2, tornando possvel que a classe de carregamento de
37
37
38
Utilizando o jShell
Esta seo tem o intuito de demonstrar, brevemente, as principais funcionalidades do jShell, de modo que o leitor tenha uma
melhor compreenso do funcionamento da ferramenta. Portanto,
detalhes de implementao sero omitidos, focando apenas nas
formas bsicas de uso.
O primeiro passo executar o terminal de linha de comando, tal
qual informado anteriormente: teclas Windows + R e digitar cmd.
Com o terminal aberto, mude o diretrio do mesmo para o
diretrio no qual est o arquivo kulla.jar, digitando cd /d f:\java9\
kulla\. Uma vez alterado o diretrio, o jShell pode ser executado
com o comando java -jar kulla.jar.
39
39
40
Essa observao importante porque possvel que o desenvolvedor tenha escrito um trecho de cdigo que o compilador
entenda, por exemplo, que no realiza nenhuma tarefa realmente
necessria, sendo, portanto, removido pelo mesmo em tempo de
compilao, de forma a otimizar a execuo da aplicao. Com
a otimizao do cdigo, no entanto, a aplicao executar mais
lentamente do que sem quaisquer intervenes do compilador.
Isso porque as melhorias so realizadas apenas quando a aplicao inicializada, fazendo com que o tempo total para a mesma
terminar todas as tarefas de uma determinada execuo seja
maior, j que contabiliza o tempo levado pelo compilador para
otimizar o cdigo, mais o tempo que o cdigo otimizado precisa
para finalizar a execuo.
Deste modo, os resultados dos testes de desempenho desse trecho de cdigo estaro distorcidos. Com isso em mente, saiba que
uma das premissas para bons testes de desempenho
fazer com que a contagem do tempo de execuo do
teste s inicie aps as otimizaes no cdigo da aplicao, viabilizando testes que possibilitam obter, com
preciso, o tempo levado pela mesma para realizar as
tarefas. Esse o propsito do JMH.
Enfim, com o JMH ser possvel escrever testes de
desempenho mais confiveis, uma vez que o mesmo
fortemente integrado plataforma Java, o que facilita
o monitoramento do gerenciamento de memria da
JVM, das otimizaes do compilador, entre outros fatores que podem distorcer os resultados dos testes.
Nota
No faz parte do escopo deste artigo entrar em detalhes sobre o funcionamento do JMH e como
escrever testes de desempenho com essa ferramenta.
41
41
No momento de executar a coleta de lixo na memria, o G1 percorre todas as trs regies (eden, survivor e old generation) e faz a
transio de objetos alocados de uma regio para a outra, conforme
o tempo de vida de cada um. Em seguida, inicia a desalocao dos
objetos pela regio mais vazia at a mais cheia, potencializando a
liberao de memria. Esse mtodo assume que as regies mais
vazias tm mais probabilidade de possuir objetos que podem ser
descartados.
Nota
importante mencionar que o G1 no executa a coleta de lixo a todo momento. Em vez disso,
os desenvolvedores especificam um tempo de pausa aceitvel para a aplicao e, baseado nisso,
o coletor de lixo adota um modelo de predio para alcanar esse tempo desejado. Alm disso,
considerando dados de outras coletas, estima quantas regies podem ser coletadas durante o
perodo especificado.
HTTP 2.0
42
A soluo
O HTTP/2 busca fazer melhor uso das conexes com os servidores web ao modificar como as solicitaes e respostas trafegam
pela rede, o que era uma grande limitao da verso anterior do
protocolo. Com a nova verso, o navegador realiza uma nica
conexo com o servidor web e ento pode, de acordo com a necessidade, efetuar vrias solicitaes e receber vrias respostas
ao mesmo tempo, como sinaliza a Figura 11.
De acordo com essa figura, o navegador utiliza uma nica conexo e enquanto est enviando mais uma solicitao ao servidor
(#6), tambm est recebendo mltiplas respostas para solicitaes
feitas anteriormente como, por exemplo, o cabealho para o arquivo #3, o corpo do arquivo solicitado pela requisio #1, o corpo do
arquivo solicitado pela requisio #3, cujo cabealho j foi recebido, e o cabealho do arquivo solicitado pela requisio #2.
Note que com apenas uma conexo o navegador consegue
enviar vrias requisies e receber vrias respostas, em ordem
diversa, otimizando assim o trfego de dados. Note, tambm,
que as respostas para uma nica solicitao podem ser fragmentadas em vrios pedaos menores, como aconteceu com os dados
43
43
44
45
45
representa o processo recm-criado para a execuo do comando cmd /k dir, passado como parmetro. Em seguida, o
mtodo imprimeDetalhesProcesso(), cujo cdigo pode ser
visto na Listagem 11, invocado, recebendo como parmetro
um controlador do processo (ProcessHandle) obtido atravs de
processo.toHandle().
Listagem 11. Impresso na tela das informaes do processo atual com a nova API.
public class ExemploProcessoAtual{
public static void main(String[] args){
//Pega o controle (handle) do processo em andamento
ProcessHandle processoAtual = ProcessHandle.current();
System.out.println(**** Informacao do processo atual ****);
imprimeDetalhesProcesso(processoAtual);
}
public static void imprimeDetalhesProcesso(ProcessHandle processoAtual){
//Retorna uma instncia do objeto que referencia as informaes do processo
ProcessHandle.Info processoAtualInfo = processoAtual.info();
if (processoAtualInfo.command().orElse().equals()){
return;
}
//Imprime o id do processo na tela
System.out.println(PID: + processoAtual.getPid());
//Imprime o comando de incio do processo na tela. Se no tiver um comando,
//retornar vazio - orElse()
System.out.println(Comando: + processoAtualInfo.command().orElse())
//Imprime os parmetros do comando de incio do processo na tela
String[] parametros = processoAtualInfo.parametros().orElse(new String[]{});
if ( parametros.length != 0){
System.out.print(parametros: );
for(String parametro : parametros){
System.out.print(parametro + );
}
System.out.println();
}
//Imprime o horrio de incio do processo na tela
System.out.println(Inicio: + processoAtualInfo.startInstant().
orElse(Instant.now()).toString());
//Imprime o tempo que o processo est rodando
System.out.println(Rodando:+ processoAtualInfo.totalCpuDuration()
.orElse(Duration.ofMillis(0)).toMillis() + ms);
//Imprime o nome do usurio ao qual o processo est vinculado
System.out.println(Usuario: + processoAtualInfo.user().orElse());
}
}
Listagem 12. Cdigo que cria um processo e imprime suas informaes.
import java.io.IOException;
import java.io.*;
import java.util.*;
46
Nota
Quando se fala em subprocessos no ter comandos para inicializa-los, no quer dizer que eles no
realizam tarefas, mas sim que os processos que os gerenciam que so responsveis por inicializ-los,
manipul-los e encerr-los.
Como precisamos acessar cada processo para obter suas informaes, utilizamos o mtodo ProcessHandle.allProcesses(). Esse
mtodo retorna uma stream e a partir dela realizamos as filtragens
com o comando .filter(processHandle -> processHandle.info()
.command().isPresent(), que usa o controlador para acessar as
informaes dos processos que tm um comando associado (isPresent()). Em seguida, pode-se identificar que a lista ser restrita
a trs processos com a chamada a .limit(3). Por ltimo, tem-se a
etapa da execuo do cdigo que envolve imprimir as informaes
de cada processo da lista final. Para isso, chamado o mtodo
forEach(), que percorre a lista de processos e imprime no terminal
de linha de comando as informaes dos mesmos valendo-se do
mtodo imprimeDetalhesProcesso().
Listagem 13. Imprime as informaes de trs processos que esto rodando no
sistema operacional
public class ExemploListagemTodosProcessosSO{
public static void main(String[] args){
//lista os processos que esto rodando no sistema operacional
ProcessHandle.allProcesses()
.filter(processHandle -> processHandle.info().command().isPresent())
.limit(3)
.forEach((processo) ->{
imprimeDetalhesProcesso(processo);
});
}
public static void imprimeDetalhesProcesso(ProcessHandle processoAtual){
As demonstraes realizadas nas listagens anteriores, principalmente na Listagem 10, reforam a necessidade de implementao
de uma soluo para tal problema. Felizmente, a nova verso da
API de processos resolve essa antiga pendncia, permitindo controlar centenas de processos com uma nica thread, diminuindo
a complexidade da codificao e maximizando o desempenho
das solues que fazem uso desse recurso.
Portanto, com a nova API os desenvolvedores tero muito mais controle sobre os processos em um sistema operacional, alm do bvio
ganho em produtividade e segurana. Apesar disso, recomendado
muito cuidado ao utilizar todo esse controle, pois pode interferir na
estabilidade do ambiente que roda a aplicao e por isso imprescindvel ter um conhecimento aprimorado desses recursos.
Como verificado, o Java 9 trar melhorias importantes e h muito
esperadas pela comunidade, empresas e desenvolvedores que fazem uso da plataforma. Essas novidades, em sua maioria, tm como
meta obter ganhos em termos de desempenho e, principalmente,
escalabilidade, a fim de atender tambm dispositivos com pouco
poder de processamento. Sendo assim, podemos afirmar que a
novidade de maior destaque mesmo o sistema de mdulos.
Essa nova estrutura do Java possui muitas facetas e por isso alguns
detalhes no foram descritos neste documento, devido ao espao.
No entanto, grande dos desenvolvedores precisa conhecer apenas
alguns conceitos, como os apresentados, pois so os que realmente
sero utilizados no dia a dia, a exemplo da declarao de mdulos
e da criao de arquivos JAR modulares.
Em relao ao JShell, espera-se que seja uma ferramenta notvel
para diminuir, principalmente, a curva de aprendizado da linguagem. Logo, a expectativa que os aprendizes faam bastante uso da
mesma, como tambm os usurios mais avanados, a fim de testar
alguns comandos e expresses antes de efetivamente inseri-los nas
aplicaes. Ademais, essa funcionalidade aproxima a linguagem
Java das linguagens de script, as quais j possuem solues como
essa por padro.
O JMH, por sua vez, um recurso que dever ser explorado por
desenvolvedores mais avanados, que possuem conhecimento em
testes de desempenho, visto que difcil obter resultados precisos
com esse tipo de teste. Entretanto, uma API de extrema importncia, uma vez que o Java no possua uma forma de implementar
tais testes sem recorrer a bibliotecas de terceiros, o que dificultava
bastante a obteno de resultados satisfatrios.
J a definio do G1 como o coletor de lixo padro uma alterao bem-vinda e bastante esperada pela comunidade, aps longos
debates acerca do assunto. Essa alterao permitir menos pausas
nas aplicaes e garantir uma melhor experincia ao usurio.
Nesse momento algumas pessoas podem argumentar que a opo de escolher o G1 como coletor de lixo j existia nas verses
anteriores, porm isso no deixa essa mudana menos importante,
pois muitos desenvolvedores e administradores no sabiam da
existncia dessa opo.
Com relao ao HTTP 2.0, um protocolo que promete ser uma
revoluo na Internet, ao oferecer maior capacidade de transferncia
de contedo atravs da multiplexao e compresso de dados. Essa
uma evoluo indispensvel e que vem para suprir as deficincias
da verso atual do HTTP. Apesar de ainda pouco adotado, por ser
bastante recente, a tendncia que seu uso cresa exponencialmente
ao longo dos anos. Portanto, fundamental que o Java se antecipe
e disponibilize uma API que possibilite o uso do novo protocolo
nas aplicaes, o que se materializar com o advento da verso 9
da plataforma.
Autor
Jos Guilherme Macedo Vieira
jguilhermemv@gmail.com
Arquiteto de Software e desenvolvedor Java EE de uma das empresas pblicas de tecnologia da informao mais respeitadas
do pas, a DATAPREV. Possui mais de 10 anos de experincia na plataforma
Java. Projeta solues de alta escalabilidade, fazendo uso, em especial,
da plataforma Java EE. Tem ministrado diversos treinamentos in-company, bem como
participado de projetos inovadores na rea de Big Data. Pesquisador e entusiasta do
Apache Cassandra, com o qual trabalhou em projetos em reas como anlise de riscos e
deteco de fraudes. Colaborador da revista Java Magazine.
Links:
Modularidade do Java 9.
http://paulbakker.io/java/java-9-modularity/
Especificao do sistema de mdulos.
http://openjdk.java.net/projects/jigsaw/spec/sotms/
Especificao para tornar o G1 o coletor de lixo padro.
http://openjdk.java.net/jeps/248
Especificao do JMH.
http://openjdk.java.net/jeps/230
Especificao das melhorias da API de processos.
http://openjdk.java.net/jeps/102
Especificao da API do HTTP/2.
http://openjdk.java.net/jeps/110
Projeto Kulla
https://adopt-openjdk.ci.cloudbees.com/view/OpenJDK/job/langtools-1.9-linux-x86_64kulla-dev/lastSuccessfulBuild/artifact/
47
47
Simplificando o
desenvolvimento de
microsservios com o
WildFly Swarm
Conhea neste artigo uma nova abordagem da
Red Hat para criar microsservios utilizando Java
48
49
49
O antes e o depois
Ao utilizar um servidor de aplicaes como o WildFly para
desenvolver solues que adotam uma arquitetura voltada para
microsservios, realizamos o setup inicial do container e, ento,
iniciamos o desenvolvimento da soluo em si. O problema
de adotar servidores de aplicaes padro para arquiteturas
desse tipo que provavelmente voc acabar carregando mais
funcionalidades do que sua soluo necessita, o que pode levar
ao consumo excessivo de recursos. A Figura 1 demonstra essa
afirmao, mostrando que o servio MyApp precisa somente da
API JAX-RS, mas o WildFly carrega vrias outras APIs.
Para lidar com esse problema o Swarm faz uso de um recurso
bem conhecido no Java, o Uber JAR (ou Fat JAR). Diferente do modelo convencional, esse tipo de JAR contm no somente o projeto
final compilado, mas pode tambm conter todas as dependncias
embutidas (a maneira como ele empacotado lembra muito a dos
arquivos WAR). A diferena do arquivo gerado que ele contm
tambm uma instncia do Swarm. Assim, o que temos ao final
um arquivo auto executvel que contm a aplicao e o prprio
container com os mdulos selecionados pelo desenvolvedor.
A Figura 2 mostra a estrutura do servio MyApp nesse modelo.
O resultado dessa mudana uma menor utilizao de recursos,
gerando um nico artefato de tamanho reduzido.
Um pouco de histria
Para compreender o Swarm, no podemos ignorar a histria
que veio antes dele. E caso nunca tenha utilizado o JBoss AS, a
50
Caso queira saber mais sobre a histria do JBoss AS, em edies anteriores da Java Magazine existem
vrios artigos que explicam detalhadamente as diferenas entre todas as verses.
51
51
02.
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
03.
<project.reporting.outputEncoding>UTF-8</project.reporting
04.
<maven.min.version>3.2.1</maven.min.version>
05.
<maven.compiler.target>1.8</maven.compiler.target>
06.
<maven.compiler.source>1.8</maven.compiler.source>
07.
<version.wildfly-swarm>1.0.0.Alpha6</version.wildfly-swarm>
.outputEncoding>
08. </properties>
<groupId>org.wildfly.swarm</groupId>
03.
<artifactId>undertow</artifactId>
04.
<version>${version.wildfly-swarm}</version>
05. </dependency>
06. <dependency>
07.
<groupId>org.wildfly.swarm</groupId>
08.
<artifactId>weld</artifactId>
09.
<version>${version.wildfly-swarm}</version>
10. </dependency>
52
Ademais, pode ser encontrado em implementaes para ambientes servlet-only como o Tomcat e o Jetty.
Agora necessitamos declarar os plug-ins que sero utilizados
na fase de build do nosso projeto. A Listagem 3 mostra cada um
deles.
Listagem 3. Plugins utilizados no projeto para configurao e gerao do WAR,
controle do Swarm.
01. <build>
02.
<finalName>${project.artifactId}</finalName>
03.
<plugins>
04.
<plugin>
05.
<groupId>org.apache.maven.plugins</groupId>
06.
<artifactId>maven-war-plugin</artifactId>
07.
<version>2.6</version>
08.
<configuration>
09.
10.
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
11.
</plugin>
12.
<plugin>
<groupId>org.wildfly.swarm</groupId>
14.
<artifactId>wildfly-swarm-plugin</artifactId>
15.
<version>${version.wildfly-swarm}</version>
16.
<executions>
17.
<execution>
18.
<goals>
<goal>package</goal>
20.
</goals>
21.
</execution>
22.
</executions>
23.
<configuration>
24.
25.
<bundleDependencies>true</bundleDependencies>
</configuration>
26.
</plugin>
27.
<plugin>
28.
<groupId>org.apache.maven.plugins</groupId>
29.
<artifactId>maven-compiler-plugin</artifactId>
30.
<version>3.3</version>
31.
<configuration>
32.
33.
34.
35.
36.
13.
19.
02.
03. import java.io.IOException;
04. import javax.servlet.ServletException;
05. import javax.servlet.annotation.WebServlet;
06. import javax.servlet.http.HttpServlet;
07. import javax.servlet.http.HttpServletRequest;
08. import javax.servlet.http.HttpServletResponse;
09.
10. @WebServlet(name = HelloSwarmServlet, urlPatterns = /HelloSwarm)
11. public class HelloSwarm extends HttpServlet{
12.
13.
14.
15.
@Override
16.
17.
18.
rep.getWriter().write(Hello Swarm);
}
19. }
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
37. </build>
53
53
54
Nota
O Swarm ainda no possui todos os mdulos do WildFly no formato de fractions, contudo, Ken
Finnigan afirmou que a comunidade tem sido muito receptiva e vem contribuindo consideravelmente
para o amadurecimento da ferramenta, o que deve acelerar o ritmo de lanamento das prximas
releases e implementao de novas fractions.
02.
03. import org.jboss.shrinkwrap.api.ShrinkWrap;
04. import org.wildfly.swarm.container.Container;
05. import org.wildfly.swarm.undertow.WARArchive;
06.
07. public class App
08. {
09.
10.
try {
11.
12.
container.start();
13.
System.out.println( Swarm no ar );
14.
15.
deployment.addClass(HelloSwarm.class);
16.
<groupId>org.wildfly.swarm</groupId>
17.
<artifactId>wildfly-swarm-logging</artifactId>
18.
<version>${version.wildfly-swarm}</version>
19.
</dependency>
20.
container.deploy(deployment);
} catch (Exception e) {
e.printStackTrace();
}
}
21. }
55
55
Tipo
Descrio
JARArchive
Uma verso melhorada do JAR que fornece mtodos fceis para adicionar dependncias.
WARArchive
Uma verso melhorada do WAR que fornece mtodos fceis para adicionar contedo esttico como pginas HTML, CSS e JavaScript, assim como
arquivos de configurao, como o web.xml.
JAXRSArchive
Web archive que permite criar uma aplicao REST a partir de uma classe sem a necessidade de declararmos a anotao @ApplicationPath. Basta adicionar essa classe ao JAXRSArchive atravs do mtodo addResource() e depois definir o nome do servio com o mtodo
setApplicationName(nome-servico). Assim, a URL REST estar disponvel em http://localhost:8080 /nome-servico.
Secured
Tipo de arquivo que injeta o arquivo keycloak.json e configura restries de segurana. O Keycloak uma soluo de SSO para aplicaes web que
disponibilizam servios atravs de chamadas RESTful.
RibbonArchive
Arquivo que pode registrar servios baseados em Ribbon-based, soluo que age como um load balancer de chamadas desenvolvido pela Netflix.
Quando procedemos dessa forma, para iniciar o projeto devemos realizar todo o trabalho que anteriormente era efetuado
automaticamente pelo Swarm. Assim, agora precisamos subir
o container, preparar os arquivos que estaro no projeto e, por
ltimo, realizar o deploy.
Na linha 11 temos o cdigo que cria um container, uma instncia
do Undertow, e como voc pode imaginar, toda a inicializao do
mesmo feita na linha 12. Com isso, temos o Swarm j funcionando, mas ainda sem o nosso projeto.
Na linha 14 criamos um WARArchive, que age como um arquivo
WAR carregado em memria. Aqui vale uma ressalva: note que
ainda estamos utilizando o empacotamento do nosso projeto como
um JAR. Usamos o recurso de alocao em memria como um
WAR apenas para realizar o deploy de nosso servio.
Nesse cdigo, fizemos uso tambm da classe ShrinkWrap,
que facilita criar, importar, exportar e manipular arquivos em
memria. Na linha 14 utilizamos seu mtodo esttico create(),
que aceita como parmetro uma classe genrica para definir o
tipo de arquivo a ser criado. Como queremos alocar um WAR em
memria para realizar o deploy em nosso container, declaramos
a classe WARArchive. A partir da podemos adicionar os nossos
recursos, como classes, pginas HTML e arquivos JavaScript,
que, diferentemente do que ocorre em um projeto web padro no
Swarm, precisaro ser explicitamente inseridos no WAR virtual
que estamos manipulando.
A Tabela 1, retirada da prpria documentao do Swarm, mostra
os tipos de arquivos virtuais que o mesmo disponibiliza. Saiba
que esses tipos de arquivos esto diretamente relacionados ao
tipo de aplicao que voc vai querer realizar o deploy. Como
estamos fazendo o deploy de um projeto web padro, utilizamos
o WARArchive.
Voltando explicao do cdigo da Listagem 7, o prximo passo adicionar nossa classe ao deploy que iremos realizar, como
demonstra a linha 15. Logo aps, na linha 16, realizamos de fato
o deploy.
Agora, precisamos inserir no POM o apontamento para a classe
main customizada (App). Sendo assim, depois do elemento bundleDependencies, adicione a seguinte linha:
<mainClass>br.com.devmedia.App</mainClass>
56
Caso tenha criado um projeto com um pacote ou classe com nomes diferentes, no esquea de atualizar o seu POM. Em seguida,
inicie o Swarm novamente e observe que obtivemos o mesmo
resultado de quando no utilizamos a classe customizada.
Vale ressaltar que o uso de uma classe principal customizada
nem sempre opcional. Em alguns fractions, como o do JSF,
existe a necessidade de criar a classe main customizada porque
precisaremos incluir arquivos HTML, CSS, JavaScript, dentre
outros ao nosso deploy.
03.
xsi:schemaLocation=http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd>
04.
<context-param>
05.
<param-name>javax.faces.PROJECT_STAGE</param-name>
06.
<param-value>Development</param-value>
07.
</context-param>
08.
<servlet>
09.
<servlet-name>Faces Servlet</servlet-name>
10.
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
11.
<load-on-startup>1</load-on-startup>
12.
</servlet>
13.
<servlet-mapping>
14.
15.
16.
17.
<h:head>
<meta http-equiv=Content-Type content=text/html; charset=UTF-8 />
<title>Exemplo de Swarm + JSF</title>
07.
</h:head>
08.
<h:body>
09.
10.
11.
12.
<div id=top>
<ui:insert name=top>
<h4>Seu primeiro Facelet via Swarm.</h4>
</ui:insert>
13.
</div>
14.
<div id=content>
15.
<ui:insert name=content>Content</ui:insert>
16.
</div>
17.
<div id=bottom>
18.
<ui:insert name=bottom>Powered by
<img src=http://wildfly-swarm.io/images/swarm_logo.png
style=width:200px; height:auto; /></ui:insert>
19.
</div>
20.
</h:body>
21. </html>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
57
57
package br.com.devmedia;
import javax.enterprise.inject.Model;
@Model
public class Welcome {
public String welcomeFromJSF() {
return Bem vindo ao JSF!! Ou voc prefere hello world?;
}
}
02.
<groupId>org.wildfly.swarm</groupId>
03.
<artifactId>jsf</artifactId>
04.
<version>${version.wildfly-swarm}</version>
05. </dependency>
Listagem 14. Cdigo da classe App atualizado.
01. package br.com.devmedia;
02.
03. import org.jboss.shrinkwrap.api.ShrinkWrap;
04. import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset;
05. import org.wildfly.swarm.container.Container;
06. import org.wildfly.swarm.undertow.WARArchive;
07.
08. public class App
09. {
10.
11.
12.
13.
container.start();
14.
System.out.println( Swarm no ar );
15.
16.
deployment.addClass(Welcome.class);
17.
deployment.addAsWebResource(
18.
19.
deployment.addAsWebResource(
20.
21.
deployment.addAsWebInfResource(
22.
23.
deployment.addAsWebInfResource(
24.
new ClassLoaderAsset(WEB-INF/template.xhtml,
App.class.getClassLoader()), template.xhtml);
25.
deployment.addAllDependencies();
26.
deployment.addClass(HelloSwarm.class);
27.
28.
container.deploy(deployment);
}
29. }
58
Autor
Joel Backschat
joel@cafecomjava.com.br
Bacharel em Sistemas da Informao pela Universidade da
Regio de Joinville, possui certificao SCJP e Adobe FLEX. J
trabalhou em empresas como TOTVS e Supero. Desde 2014 arquiteto
de software da Fcamara Formao e Consultoria nas reas de inovao
e logstica porturia. Entusiasta de novas tecnologias, mantm o site cafecomjava.com.
br para compartilhar suas experincias que vo do hardware ao software.
Links:
Pgina do Swarm.
http://wildfly-swarm.io/
Documentao oficial do WildFly Swarm.
https://wildfly-swarm.gitbooks.io/
Pgina do projeto Undertow.
http://undertow.io/
Palestra de Ken Finnigan sobre Swarm.
https://developers.redhat.com/video/youtube/i1aiUaa8RZ8/
Grupo no Google sobre o Swarm.
https://groups.google.com/forum/#!forum/wildfly-swarm
Canal no IRC sobre o Swarm.
http://webchat.freenode.net/?channels=wildfly-swarm
Matria sobre persistncia poliglota.
http://martinfowler.com/bliki/PolyglotPersistence.html
59
59
Cenrio
DevOps um dos termos mais populares do momento no mercado
da Tecnologia da Informao. Muito se fala a respeito, e a expectativa
quanto aos benefcios de sua adoo alta. Com base nisso, este artigo
visa contribuir com a discusso e disseminao de alguns dos elemen-
60
61
61
62
Tipo de projeto
Freestyle project
Git URL
https://github.com/pedrobrigatto/devmedia_devops_series.git
Branches to build
*/master
Triggers
Build
63
63
64
65
65
66
Essa verso do Nexus, que acabamos de mencionar, encontrase disponvel em um repositrio do GitHub cuja URL a git://
github.com/shekhargulati/nexus.git. Os comandos executados para
prepar-la e implant-la foram agrupados na Listagem 2. O primeiro passo que demos foi, de dentro do diretrio da gear criada
(devmediasonar), adicionar ao Git uma referncia para o branch do
projeto que baixaremos, e cuja URL acabamos de citar. Em seguida, realizamos um merge do contedo desse branch com aquele
encontrado no diretrio devmediasonar, dando preferncia ao material do branch caso algum conflito seja encontrado. Finalmente,
submetemos todo o material para o nosso servidor. O processo de
configurao e inicializao normalmente bem rpido e, assim
que concludo, j permite que acessemos a aplicao a partir do
painel de administrao de nossa conta OpenShift.
67
67
68
<artifactId>sonar-maven-plugin</artifactId>
<version>${sonar.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>releases</serverId>
<nexusUrl>http://devmedianexus-pedrobrigatto.rhcloud.com/nexus/
</nexusUrl>
</plugins>
</pluginManagement>
</build>
<distributionManagement>
<repository>
<id>snapshots</id>
<name>Snapshots</name>
<url>http://devmedianexus-pedrobrigatto.rhcloud.com/nexus/content/
repositories/snapshots/
</url>
</repository>
</distributionManagement>
</project>
69
69
70
71
71
No entanto, nem sempre teremos nossa disposio os servidores da empresa ou bancados por ela para executar nossos
testes locais. Nesses casos, podemos adotar as mesmas tecnologias que essas solues de PaaS usam e, assim, montar nossos
prprios ambientes para, seno replicar, simular o mais prximo
da realidade os ambientes-alvo de nossas aplicaes (mesmo
sistema operacional, mesmos caminhos de diretrio, mesmos
scripts, etc.).
Uma das tecnologias muito populares no quesito de provisionamento de recursos, e que estudaremos de forma introdutria no
texto que se segue, o Vagrant. Essa ferramenta desenvolvida e
mantida por uma empresa chamada HashiCorp e apresenta uma
forma muito simples para criar, configurar e gerenciar mquinas
virtuais, atuando logo acima de ferramentas de virtualizao
como VMware e VirtualBox.
Essa facilidade de uso deve-se principalmente forma como o
Vagrant se apresenta para ns. Toda a definio de uma infraestrutura escrita a partir de um arquivo chamado Vagrantfile,
que se usa de uma linguagem pr-definida e muito bem documentada em seu site oficial (disponvel na seo Links) para,
passo a passo, criar todos os ns de um ambiente desejado,
consideradas todas as caractersticas de poder de processamento,
quantidade de espao em disco, memria, configuraes de rede,
dentre outros. Veremos, logo mais, um pouco sobre a estrutura
desse arquivo.
Assim que o Vagrant instalado, podemos passar a utiliz-lo via
linha de comando. Trata-se de uma ferramenta cujas instrues
so bastante simples e com as quais rapidamente nos familiarizamos medida do uso. Ao abrir um terminal e digitar, por exemplo,
vb.name = clusternode1
end
clusternode1.vm.provision :shell, path: vm_bootstrap.sh
Vagrant.configure(2) do |config|
end
config.vm.box = chef/centos-6.5
if Vagrant.has_plugin?(vagrant-cachier)
config.cache.scope = :box
vb.memory = 1024
vb.name = clusternode2
config.cache.enable :generic, {
end
end
}
end
vb.memory = 1024
vb.name = clusternode3
end
72
73
74
Autor
Pedro E. Cunha Brigatto
pedrobrigatto.devmedia@gmail.com
Engenheiro da Computao graduado pela Universidade Federal de So Carlos, desenvolvedor certificado SAP Netweaver
(Java Stack) e programador certificado SCJP. Especialista em Engenharia
de Software graduado pela Unimep e ps-graduado em Administrao
pela Fundao BI-FGV, atua com desenvolvimento de software desde 2005. Atualmente
atua como consultor tcnico no desenvolvimento de solues de alta disponibilidade
na Avaya.
Links:
Cdigo do projeto tema no GitHub.
https://github.com/pedrobrigatto/devmedia_devops_series
Texto refletindo sobre a opo entre Gradle e Maven.
http://devops.com/2015/03/27/puzzle-gradle-maven/
Trabalhando com hooks no Git.
https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
Atlas catlogo de imagens da HashiCorp.
https://atlas.hashicorp.com/boxes/search
Pgina oficial do Buddy.
https://buddy.works/
Guia HTML 5
DEVMEDIA
http://www.devmedia.com.br/guias/guia-html/3
75
75
76