Pular para o conteúdo principal

Um pouco sobre a arquitetura do ScrumToys


O ScrumToys é um projeto que nasceu com o propósito de demonstrar o maior número possível de funcionalidades do JSF 2.0. Contudo, o ScrumToys vai alem e realiza alguns desafios que foram encontrados durante o seu refactoring para ser incorporado à versão final do NetBeans 6.8.

A primeira versão!


A primeira versão do ScrumToys foi desenvolvida aplicando efetivamente o padrão de projeto MVC. Através deste padrão, a camada view foi implementada com os componentes visuais do JSF, a camada controller foi implementada através de Managed Beans configurados via anotações e a camada model se distribuía em classes JavaBeans para realizar alguns componentes de negócios, entidades persistentes (JPA) e persistência através de Data Access Objects (DAOs). Estas várias camadas realizavam o ScrumToys para rodar no JBossAS 4.2.3 com banco de dados baseado no MySQL Database Server 5.0. Além disso, o projeto foi criado inicialmente através do Eclipse.

O refactoring!


Para simplificar ao máximo esta aplicação de demonstração, esta passou por um refactoring completo na camada model, além de uma revisão detalhada da camada de apresentação (view e controller). Neste refactoring, foi necessário tomar algumas decisões em prol da simplicidade que deixariam qualquer desenvolvedor purista de cabelos em pé. Algumas destas decisões envolveram:
  • Migrar o projeto do Eclipse para o NetBeans (inicialmente o NetBeans 6.7.1);
  • Alterar e eliminar possíveis configurações da aplicação Web para rodar no Glassfish sem a necessidade de configurações extras (tornando-o plug'n play);
  • Usar o banco de dados JavaDB (antigo Derby) que já vem integrado numa instalação padrão do NetBeans e do Glassfish. Isso eliminaria a necessidade de instalar um MySQL, criar um usuário e um esquema no banco;
  • Simplificar a configuração do JPA para usar o TopLink ou Eclipse Essentials, além de criar o banco de dados automaticamente no esquema padrão que já existe no JavaDB do NetBeans. Notamos que o Glassfish v2 (ainda Java EE 5) usa o TopLink como implementação de JPA 1.0 e o Glassfish v3 (que já é Java EE 6 e está embutido no NetBeans 6.8) usa o Eclipse Essentials, como implementação de JPA 2.0 (código aberto e doado do TopLink pela Oracle para o Eclipse.org, considerada a implementação de referência do JPA).
  • E agora a decisão de projeto mais radical e ofensiva para alguns desenvolvedores: simplificar a camada model ao eliminar componentes de negócios e todos os Data Access Object. Assim, a lógica necessária para persistência e manipulação das entidades de negócios seriam implementadas na camada controller (dentro dos Managed Beans).
A última decisão de projeto, levou a uma arquitetura muito mais simples em detrimento da organização comumente recomendada para as camadas de uma aplicação web robusta e escalonável. Mas, esta arquitetura permitiu evitar o uso de Enterprise JavaBeans para o gerenciamento do contexto de persistência e demarcação de transação com recursos do EJB Container. Aspecto que fugiria do escopo do projeto e do propósito inicial da demonstração implementada. Contudo, mesmo ao eliminar os DAOs, a aplicação ainda precisaria ter acesso ao contexto de persistência (JPA) e realizar a demarcação da transação (neste caso, demarcação programática) dentro dos Managed Beans.

Uma nova arquitetura!


A segunda versão da aplicação, após o refactoring, passou a oferecer uma arquitetura simples através de classes que realizam simplesmente o propósito de demonstrar o maior número possível de funcionalidades do JSF 2.0, sem desviar a atenção para outras tecnologias que constituem o Java EE 6.

Como parte do processo de simplificação da arquitetura e para atender a necessidade de gerenciar um contexto de persistência e demarcação dentro dos Managed Beans da camada controller, a seguinte classe abstrata foi implementada para servir de base para todos os Managed Beans implemenatados.
package jsf2.demo.scrum.web.controller;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.EntityManagerFactory;
import javax.transaction.UserTransaction;
// Outros imports foram omitidos ...

/**
* @author Dr. Spock (spock at dev.java.net)
*/
public abstract class AbstractManager {

@PersistenceUnit
private EntityManagerFactory emf;
@Resource
private UserTransaction userTransaction;

protected final <T> T doInTransaction(PersistenceAction<T> action)
throws ManagerException {
EntityManager em = emf.createEntityManager();
try {
userTransaction.begin();
T result = action.execute(em);
userTransaction.commit();
return result;
} catch (Exception e) {
try {
userTransaction.rollback();
} catch (Exception ex) {
Logger.getLogger(AbstractManager.class.getName()).log(Level.SEVERE,
null, ex);
}
throw new ManagerException(e);
} finally {
em.close();
}
}

protected final void doInTransaction(PersistenceActionWithoutResult action)
throws ManagerException {
EntityManager em = emf.createEntityManager();
try {
userTransaction.begin();
action.execute(em);
userTransaction.commit();
} catch (Exception e) {
try {
userTransaction.rollback();
} catch (Exception ex) {
Logger.getLogger(AbstractManager.class.getName()).log(Level.SEVERE,
null, ex);
}
throw new ManagerException(e);
} finally {
em.close();
}
}

protected static interface PersistenceAction<T> {
T execute(EntityManager em);
}

protected static interface PersistenceActionWithoutResult {
void execute(EntityManager em);
}

// Alguns outros métodos foram omitidos

}
Esta classe aplica os padrões de projeto Template Method e Strategy ao disponibilizar o método doInTransaction() que demarca a transação via JTA e permite receber o algoritmo de persistência através de uma implementação de callback ao realizar a "inner" interface PersistenceAction ou PersistenceActionWithoutResult. Esta implementação foi inspirada em classes presentes na arquitetura do Spring Framework chamadas de Template que encapsulam códigos padrões.

Como os Managed Beans são componentes gerenciados e deverão herdar o código base apresentado acima, o Web Container Java EE 6 realizará a injeção de dependência ao fornecer referências válidas de objetos aos atributos dos tipos EntityManagerFactory e UserTransaction.

O diagrama a seguir ilustra a estrutura básica dos Managed Beans implementados no ScrumToys usando a classe abstrata acima como base.


O Managed Bean ProjectManager herdará a capacidade de persistência e já terá uma demarcação simples de transação através dos métodos Template doInTransaction(). A seguir está um fragmento de código deste controller.
package jsf2.demo.scrum.web.controller;

import jsf2.demo.scrum.model.entities.Project;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// Outros imports foram omitidos

/**
* @author Dr. Spock (spock at dev.java.net)
*/
@ManagedBean(name = "projectManager")
@SessionScoped
public class ProjectManager extends AbstractManager
implements Serializable {

private static final long serialVersionUID = 1L;
private Project currentProject;
private DataModel<Project> projects;
private List<SelectItem> projectItems;
private List<Project> projectList;

@PostConstruct
public void construct() {
this.currentProject = new Project();
init();
}

// ...

public void init() {
try {
setProjectList(doInTransaction(new PersistenceAction<List<Project>>() {
public List<Project> execute(EntityManager em) {
Query query = em.createNamedQuery("project.getAll");
return (List<Project>) query.getResultList();
}
}));
} catch (ManagerException ex) {
Logger.getLogger(ProjectManager.class.getName()).log(Level.SEVERE,null,ex);
}
projectItems = new LinkedList<SelectItem>();
projectItems.add(new SelectItem(new Project(), "-- Select one project --"));
if (getProjectList() != null) {
projects = new ListDataModel<Project>(getProjectList());
for (Project p : getProjectList()) {
projectItems.add(new SelectItem(p, p.getName()));
}
}
}

// ...

public String remove() {
final Project project = projects.getRowData();
if (project != null) {
try {
doInTransaction(new PersistenceActionWithoutResult() {
public void execute(EntityManager em) {
if (em.contains(project)) {
em.remove(project);
} else {
em.remove(em.merge(project));
}
}
});
getProjectList().remove(project);
} catch (Exception e) {
Logger.getLogger(getClass()).log(Level.SEVERE,
"Error on try to remove Project: " + getCurrentProject(), e);
addMessage("Error on try to remove Project", FacesMessage.SEVERITY_ERROR);
return null;
}
}
init();
// Using implicity navigation, this request come from /projects/show.xhtml
// and directs to /project/show.xhtml could be null instead
return "show";
}

// Alguns métodos foram omitidos.

}
Veja, no código acima, as linhas 33 a 38 que aplica o uso do Template Method doInTransaction() e do callback do tipo PersistenceAction para recuperar da base de dados todas as instancias persistidas de projetos. Este trecho de código herda o gerenciamento do EntityManager (abri e fechar) e a demarcação de transação (begin/commit/rollback). Outro exemplo se encontra entre as linhas 58 e 66, ao usar o callback do tipo PersistenceActionWithoutResult.

A simplicidade tornando-se referência!


A arquitetura proposta no ScrumToys influenciou a implementação de alguns códigos dos exemplos contidos no livro JavaServer Faces 2.0, The Complete Reference escrito pelo Ed Burns, líder da especificação do JSF 2.0 no JCP, e pelo Chris Schalk, Developer Advocate no Google. Algumas páginas deste livro estão disponívels no Google Books:

JavaServer Faces 2.0, The Complete Reference


Segue abaixo uma página deste livro citando a arquitetura de persistência e gerenciamento de transação implementada na aplicação Virtual Trainer.


Luz, câmera, AÇÃO!


O vídeo a seguir ilustra a criação de um projeto no NetBeans 6.8 para ter acesso aos códigos do ScrumToys e avaliar a implementação da arquitetura proposta em ação.


Para mais informações sobre este projeto:
By Spock
http://blog.spock.com.br/
http://twitter.spock.com.br/
http://www.springbrasil.com.br/
Outros posts: http://blog.globalcode.com.br/search/label/Spock

Comentários

Marcio Duran disse…
Artigo interessante, e bem explicado entretanto:

ScrumToys é dependente da IDE NetBeans 6.8 para rodar na sua especificação,e na mesma velocidade sem crachs de erro posso executar no Eclipse atual, alguma recomendação ?

Thanks !!!!
Dr. Spock disse…
O ScrumToys está otimizado para rodar no Glassfish v3 com JavaDB. Não depende do NetBeans 6.8. Se durante a criação do projeto ScumToys através do wizard do NB8 for selecionada a categoria "Exemplos | Maven", será criado um projeto sem os arquivos específicos do NetBeans, mas terá um POM para build através do Maven. Assim, torna-se possível criar o projeto para o Eclipse usando algumas instruções do Maven. Contudo, ainda será necessário fazer as devidas configurações do servidor de aplicações no Eclipse.

Uma versão do ScrumToys portada para rodar no JBossAS 6 está disponível para download em http://dl.dropbox.com/u/3027034/jib2010/Scrumtoys.Jboss6M2.zip
Outros detalhes em: http://blog.globalcode.com.br/2010/05/jsf-20-uma-evolucao-nas-interfaces-web.html
Marcio Duran disse…
Obrigado , pelos esclarecimentos !!!

Vou procurar fazer os devidos testes, eu comentei sobre o Eclipse pois ele é o padrão pra o desenvolvimento Comercial preferido pelas empresas, poderia não ter features compativeis mas vou tentar por aqui....

Valeu !!!!
Filipe Névola disse…
Artigo muito bem explicado e conciso. Parabéns
Cristiano Moraes disse…
Olá, onde posso baixar o ScrumToys para Glassfish sem precisar fazer o download do Netbeans ?
Dr. Spock disse…
Este projeto está no repositório do Mojarra (JSF RI). Veja em:
https://mojarra.dev.java.net/source/browse/mojarra/trunk/jsf-demo/sandbox/scrumtoys2009/eclipseProject/
Instruções para download estão em:
https://mojarra.dev.java.net/source/browse/mojarra/

Postagens mais visitadas deste blog

Melhorando Performance de JPA com Spring Web Flow

No TDC2009 realizado pela Globalcode em São Paulo foi apresentado um Lightning Talk sobre um problema específico de performance em aplicações Web com JPA e uma possível solução usando o Spring Web Flow . Num período de 15 minutos, os slides a seguir foram apresentados e seguidos de alguns vídeos de demonstração de uma aplicação Web em execução. Melhorando performance do JPA com Spring Web Flow View more presentations from Dr. Spock . Nesta apresentação foi dito que temos encontrado problemas de performance em aplicações Web que utilizam as tecnologias JSF + JPA + Ajax quando precisamos gerenciar um contexto de persistência (EntityManager). Estes problemas se manifestam quando aplicamos uma resposta errada para a pergunta: Como gerenciar o contexto de persistência numa aplicação Web? Se as aplicações não usam Ajax e limitam-se ao modelo orientado a requisições, a solução mais comum é o uso do design pattern chamado "Open Session In View Filter". Através deste design

O que é Lógica de programação?

Este é o segundo de uma série de posts voltados aos leitores do blog que estão dando início à carreira de desenvolvimento de software. O assunto de hoje é a lógica de programação. Para ler antes: Entendendo como funciona a programação de computadores: linguagens de programação, lógica, banco de dados A lógica de programação é um pré-requisito para quem quer se tornar um desenvolvedor de software, independente da linguagem de programação que se pretende utilizar. Mas o que é de fato a Lógica de Programação e como saber se eu tenho esse pré-requisito? A lógica de programação nada mais é do que a organização coerente das instruções do programa para que seu objetivo seja alcançado. Para criar essa organização, instruções simples do programa, como mudar o valor de uma variável ou desenhar uma imagem na tela do computador, são interconectadas a estruturas lógicas que guiam o fluxo da execução do programa. Isso é muito próximo ao que usamos em nosso cotidiano para realizar atividad

Dica rápida: Apagando registros duplicados no MySQL

Ola pessoal, Sei que vocês estão acostumados a ver posts meus sobre tecnologia móvel ou algo relacionado, mas hoje vou falar sobre um pequeno "truque" que usei esse final de semana com o MySQL. Eu estava desenvolvendo o lado servidor de uma nova aplicação mobile (ahh, então "tem a ver" com mobile hehe), e quando fui fazer alguns testes percebi que tinha quase 7 mil registros duplicados (!!!) na minha base de dados! Bom, o meu primeiro reflexo como programador foi pensar em fazer um "programinha" Java para buscar e deletar todos esses registros duplicados. Mas ai, resolvi tirar as teias de aranha dos neurônios e usar os vários anos de experiência que passei com SQL e criar uma query que fizesse esse trabalho todo de uma vez!! E a query ficou assim: delete from TABLE_NAME USING  TABLE_NAME, TABLE_NAME  AS  auxtable WHERE   ( NOT  TABLE_NAME.id  =  auxtable.id ) AND   ( TABLE_NAME.name  =  auxtable.name ) Explicação direta: TABLE_NAME

Muitas vagas, otimismo e sensação de reaquecimento da economia

2010 começou cedo, contrariando a expectativa que muitos Brasileiros tem de "O ano começa mesmo depois do carnaval".  Embora o inicio do ano tenha sido "repleto" de catástrofes naturais e muita chuva aqui no Brasil, no campo profissional o otimismo está evidente, as pessoas estão cheias de energia e boas perspectivas em relação as oportunidades de JavaEE 6 e muitas outras tecnologias. Mas, parece que não são somente as pessoas que estão otimistas, os anúncios de vagas voltaram a crescer, empresas anunciando boas vagas, ou grandes quantidades de vagas, refletindo o que podemos chamar de "Otimismo corporativo" . Veja algumas empresas que anunciaram vagas: IBM SpringSource   Yahoo!  Elumini   Cyberlynxx   Google Kaizen SPC Brasil Se em 2009, um ano de crise fizemos tudo isto , imagine em 2010. E você está preparado ?  Está otimista ? []s Yara http://twitter.com/yarasenger http://twitter.com/globalcode

Devo fazer um curso ou ler um livro?

Acredito que todos os instrutores ou professores, independentemente da área, escola ou centro de treinamento, já devam ter recebido essa pergunta alguma vez na vida: devo fazer um curso ou ler um livro? Para responder a essa pergunta, precisamos avaliar os prós e contras de cada opção. Trabalho com treinamento há algum tempo e, hoje, recebi essa pergunta de um aluno. Não adianta responder a ou b sem argumentar, demonstrando as opções conforme a situação do aluno. O conteúdo, a forma de transmissão e a capacidade de assimilação do indivíduo são chaves para haver benefício maior de aprendizado. Tanto em um bom curso quanto em um bom livro, o conteúdo é a premissa básica . Por conteúdo entendemos: se está organizado; se respeita pré-requisitos; se promove o aprendizado guiado e incremental; se aborda de forma satisfatória os principais pontos; se tem bom balanço entre teoria, exemplos e prática (favorecendo exemplos e prática); se tem como premissa a acessibilidade possível (e cabível) pa

JavaLi no Lançamento mundial do JDK7 em São Paulo

O Lançamento mundial do JDK7 foi realizado no dia 7/7 em três cidades simultaneamente: São Paulo (SouJava), Londres (London User Group) e São Francisco (Oracle) com transmissão ao vivo via satélite! Evidentemente as cidades não foram escolhidas por acaso, e podemos enxergar a escolha da cidade de São Paulo como um sinal de reconhecimento à comunidade Java Brasileira, ao SouJava e à Globalcode. Com certeza houveram várias pessoas fundamentais para isto, como o Bruno Souza e o Mauricio Leal responsáveis pela organização e realização do Mês de Java! Veja a entrevista com o JavaLi no TDC2011: Veja também as fotos do Lançamento do JDK7 na cobertura realizada aqui no Globalcoders. É isso aí pessoal, próxima parada ? Trilha Java TDC2011 Goiânia! E você, já se inscreveu? Participe, colabore, divulgue esta iniciativa. []s Yara Senger http://twitter.com/yarasenger