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

Saiba como programar para Arduino sem ter nenhum hardware disponível

O Arduino já é uma tecnologia muito difundida entre os amantes de tecnologia. É difícil encontrar um profissional da computação que não brincou um pouco com esta ferramenta de prototipagem ou, que gostaria de fazer isso. Porém, em alguns casos, o programador quer conhecer o arduino mas não dispõe de nenhum hardware, nem mesmo da placa. Como isso poderia ser resolvido? A primeira resposta seria aquela mais simples e direta: ir as compras. Isso pode ser feito em uma loja física ou pela internet. No meu caso, por exemplo, tive a felicidade de encontrar em um site (não me lembro qual) um kit arduino, com um conjunto de sensores e um DVD com 41 vídeo aulas. Mas digamos que o profissional não esteja passando por um bom momento financeiro, ou ainda, simplesmente não queira comprar o Arduino sem antes conhecê-lo um pouco melhor. Para a última situação também já existe uma resposta, e diga-se de passagem, uma excelente resposta. Trata-se do site 123D Circuits.io . Depois de criar seu u

Entendendo como funciona a programação de computadores: linguagens de programação, lógica, banco de dados

Nesse post, diferente dos últimos que foram mais enfáticos nas experiências com tecnologias, vou focar um pouco mais nos profissionais que estão começando, ou pretendem ingressar na área de desenvolvimento de software, falando sobre conceitos fundamentais relacionados a programação em geral . Mercado de trabalho para programação Conforme já sabemos, o mercado de desenvolvimento de software, especialmente no Brasil, continua em franca expansão, sendo que cada vez mais as empresas buscam desenvolver seus próprios sistemas usando as mais diferentes e novas tecnologias. Algumas matérias interessantes: As seis profissões mais valorizadas em 2010 no IDG Now! Muitas vagas e sensação de reaquecimento da economia Por isso, a área de desenvolvimento de software tem despertado interesse em muitos profissionais de outras áreas que desejam mudar de profissão, já que as oportunidades de trabalho tendem a ser maiores. Esse é um perfil presente em muitos dos clientes da Globalcode que acabou m

JSON fácil em Java com GSon !

Ola pessoal ! O formato JSON ( J ava S cript O bject N otation) vem se consagrando cada vez mais na comunicação de dados, principalmente nos dispositivos móveis devido a esse formato ser mais leve que o XML e também mais legível. Uma prova disso são as inúmeras bibliotecas que existem para manipular esse formato, e no caso do Android, o suporte ao JSON é nativo. Mas apesar de ter esse suporte nativo, algumas operações devem ser feitas manualmente e o código acaba ficando um pouco verboso e repetitivo, já que para cada objeto que se deseja transmitir é necessário fazer um método que lê as propriedades do JSON e faz as devidas atribuições no seu objeto Java. Vamos supor o seguinte objeto sendo transmitido em JSON: {   user: {     id: 123456,     name: "Neto Marin",     username: "netomarin",     email: "netomarin@globalcode.com.br"   } } Se você fosse tratar um Webservice que envia esse JSON para o seu aplicativo Android, além de criar a o