domingo, 25 de outubro de 2009

Enumeração de Caminhos - Algoritmo Grafos

Olá pessoal!
Na postagem de hoje irei mudar um pouco o foco atual do blog que, desde seu início, tem sido focado mais em tecnologias (spring, hibernate, jsf entre outras).

Hoje vou comentar um pouco sobre grafos que sempre foi um assunto de meu interesse na época de faculdade. Mais especificamente, através de uma apresentação de slides, vou mostrar dois algoritmos (baseados em rotulação de nós e arcos) para encontrar o número de caminhos entre dois nós de um grafo acíclico.

Os algoritmos são bem interessantes e tranquilos, visto que podemos usar e abusar da orientação a objetos para implementa-los (os que tornam mais interessante ainda).

Para melhor entendimento da apresentação, aconselho que o leitor tenha já um certo conhecimento de conceitos básicos de grafos. Dentre eles pode-se citar: matriz de adjacência, nós sucessores, antecessores etc.



Os fontes da implementação mostrada na apresentação estão disponíveis o link abaixo:
Fontes dos algoritmos

Quem desejar somente o executável está disponível em:
JAR da implementação

O implementação foi feita em Java... Só para lembrar!!

Abraço!!

quinta-feira, 27 de agosto de 2009

Desvendando o ZK Framework

Olá!
Aproveitando o embalo do post anterior, neste vou apresentar conceitos do ZK Framework e um exemplo de implementação (ressaltando os conceitos) através de alguns slides. Esta apresentação trata-se de apenas uma referencia inicial para as pessoas que desejam se aprofundar na tecnologia.
A apresentação está bem interessante! Vale a pena dar uma olhada!




Para maiores informações: http://www.zkoss.org/

Até!

quarta-feira, 22 de julho de 2009

Mundo Java - número 36

O post de hoje será somente para falar um pouco sobre a edição 36 da revista
Mundo Java. Na verdade, o motivo disso é a minha presença na edição com o artigo ZK Framework - Utilizando Ajax sem Javascript.












No artigo procurei ressaltar conceitos referentes os ZK e ainda construir exemplos mostrando seu uso. Segue uma prévia de alguns trechos do artigo publicado..

" Cada vez mais se faz necessário que as aplicações web sejam intuitivas e fáceis de se usar. Esta necessidade está diretamente ligada à camada de visão de tais aplicações. Porém, a criação de aplicações com interfaces ricas exige esforços cada vez maiores. Essa exigência muitas vezes acaba desviando o foco do desenvolvimento que deveria ser, na maior parte do tempo, nas regras de negócio. Com efeito, surgem diversas ferramentas tentando facilitar essa tarefa, sendo uma delas o ZK Framework. "

" ... as tecnologias utilizadas em aplicações web apresentaram uma notável evolução. Inicialmente tinham-se aplicações cujas camadas de visão eram compostas somente por páginas HTML estáticas que, com o decorrer do tempo, foram gradativamente evoluindo para páginas HTML dinâmicas (DHTML), páginas utilizando Flash, Applets e, por fim, para páginas que incorporavam o uso de Ajax ... "

" Com a maturação da tecnologia Ajax, surgiram vários frameworks baseados nela, sendo o ZK um deles. A idéia principal do ZK Framework é facilitar a incorporação de Ajax nas aplicações web desenvolvidas em Java, de maneira a dispensar qualquer conhecimento de Javascript. Essa facilidade é oriunda dos mecanismos internos do ZK que geram código Javascript de forma transparente para o desenvolvedor. "



E por aí vai correndo o assunto..
Além desse artigo, a edição apresenta vários outros assuntos interessantes dos quais cita-se: JRuby, Demoiselle Framework, hábitos eficazes para tratamento de exceções etc.

Para quem desejar saber mais sobre o ZK Framework segue uma dica quente:
http://www.zkoss.org/

Mais adiante vou postar alguns exemplos mostrando o uso do ZK.

até!

domingo, 12 de julho de 2009

Internacionalização de mensagens com JSF – Exemplo prático.

Nesta postagem vamos mostrar como fazer a internacionalização de mensagens utilizando JSF. Internacionalizar mensagens é uma maneira de isolar toda a mensageiria de uma aplicação em arquivos. Desta forma, pode-se definir mensagens em idiomas diferentes em arquivos separados sem que a aplicação sofra nenhum impacto.

Para exemplificar a internacionalização com JSF, vamos aproveitar a aplicação exemplo mostrada na postagem “Iniciando com JSF (Tutorial com exemplo prático)”.

Primeiramente deve-se definir os arquivos com as mensagens. Para isso foi criado um pacote com.sample.messages e lá foram colocados dois arquivos com as mensagens da aplicação (um com mensagens em inglês e outro em português).

A listagem 1 e 2 mostram como ficaram os arquivos com as mensagens da aplicação.

messages_en_US.properties (mensagens em inglês)
portuguese=Portuguese
english=English
save=Save
delete=Delete
name=Name
nationality=Nationality
title=JSF

Listagem 1

messages_pt_BR.properties (mensagens em português)
portuguese=Portugues
english=Ingles
save=Salvar
delete=Excluir
name=Nome
nationality=Nacionalidade
title=JSF

Listagem 2

O pacote com os arquivos de mensagens é ilustrado na figura 1:
Figura 1: Pacote mensagens


Agora temos que configurar o faces-config.xml para o funcionamento da mensageiria. Para isso basta adicionar o seguinte trecho no faces-config.xml conforme a listagem 3:

<application>
<resource-bundle>
<base-name>com.sample.messages.messages</base-name>
<var>msgs</var>
</resource-bundle>
<locale-config>
<default-locale>pt_BR</default-locale>
<supported-locale>en_US</supported-locale>
</locale-config>
<message-bundle>
com.sample.messages.messages
</message-bundle>
</application>

Listagem 3

Vamos agora criar um controller para gerenciar qual será o locale (idioma) usado na aplicação. Esse controller chamaremos de LocaleController e ficará dentro do pacote com.sample.controller do exemplo. A listagem 4 mostra a implementação do LocaleController.


package com.sample.controller;

import java.util.Locale;

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

public class LocaleController {
private Locale currentLocale = new Locale("pt", "BR");

public void englishLocale() {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
currentLocale = Locale.US;
viewRoot.setLocale(currentLocale);
}

public void portugueseLocale() {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
currentLocale = new Locale("pt", "BR");
viewRoot.setLocale(currentLocale);
}

public Locale getCurrentLocale() {
return currentLocale;
}
}

Listagem 4

Vamos também definir um managed-bean no faces-config.xml para o LocaleController (listagem 5).

<managed-bean>
<managed-bean-name>localeController</managed-bean-name>
<managed-bean-class>
com.sample.controller.LocaleController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Listagem 5

Agora vamos definir a página pessoa.jsp para testar a internacionalização (listagem 6).

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<html>
<f:view locale="#{localeController.currentLocale}">
<head>
<title><h:outputText value="#{msgs.title}" /></title>
</head>
<body>
<h:form>
<table>
<tr>
<td><h:commandLink value="#{msgs.portuguese}" action="#{localeController.portugueseLocale}" /></td>
<td><h:commandLink value="#{msgs.english}" action="#{localeController.englishLocale}" /></td>
</tr>
<tr>
<td><h:outputText value="#{msgs.name}" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nome}" /></td>
</tr>
<tr>
<td><h:outputText value="#{msgs.nationality}" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nacionalidade}" /></td>
</tr>
<tr>
<td><h:commandButton value="#{msgs.save}" action="#{pessoaController.save}" /></td>
</tr>
</table>
<h:dataTable value="#{pessoaController.pessoas}" var="p"
rendered="#{not empty pessoaController.pessoas}" border="1">
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.name}" />
</f:facet>
<h:commandLink value="#{p.nome}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.nationality}" />
</f:facet>
<h:commandLink value="#{p.nacionalidade}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.delete}" />
</f:facet>
<h:commandLink value="#{msgs.delete}" action="#{pessoaController.delete}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
</body>
</f:view>
</html>

Listagem 6

Com as configurações mostradas acima podemos ver o comportamento da aplicação (figura 2).

Figura 2: Comportamento da aplicação


Em síntese, com a aplicação exemplificamos como internacionalizar mensagens.
Os fontes do exemplo completo estão disponíveis aqui.

Até!

quinta-feira, 11 de junho de 2009

Iniciando com JSF (Tutorial com exemplo prático)

Nesta postagem será mostrado um exemplo prático (CRUD de pessoas) para aqueles que desejam iniciar o uso da tecnologia JSF. Para isso, será utilizado o servidor de aplicação Apache Tomcat 6.0 e a IDE Eclipse Ganymede.

Para começar, é preciso criar um novo projeto. No Eclipse, basta abrir o menu file conforme mostrado na figura 1. Em seguida, será aberta uma tela para escolher o tipo de aplicação que será desenvolvida. No caso do exemplo, selecione Dynamic Web Project (figura 2) e clique no botão Next.
Na seqüência, dê um nome para o projeto (no exemplo será jsfdemo) e selecione a combo Target RunTime para Apache Tomcat v6.0 (figura 3). Depois, clique no botão Finish que o projeto estará criado.

Um vez criado o projeto, é necessário configurar o ambiente para que a aplicação funcione. Para isso, faça o download da ultima versão do JSF e extraia os jars para a pasta WEB-INF/lib do projeto. Por fim, é necessário configurar o web.xml do projeto, cuja configuração é mostrada na listagem 1.


Figura 1:Novo projeto


Figura 2: Dynamic Web Project


Figura 3: Configuração inicial do projeto


<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
</web-app>
Listagem 1: web.xml

A partir deste ponto já podemos começar a efetivamente desenvolver a aplicação de exemplo.

Construindo a aplicação

Para iniciar, vamos criar os seguintes pacotes na projeto:
  • com.sample.controller;
  • com.sample.dao;
  • com.sample.model.
A figura 4 ilustra a organização dos pacotes no eclipse.

Figura 4: Pacotes

Dentro do pacote model vamos criar a classe pessoa cujo código é listado na listagem 2.

package com.sample.model;

public class Pessoa {
private Integer id;
private String nome;
private String nacionalidade;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getNacionalidade() {
return nacionalidade;
}

public void setNacionalidade(String nacionalidade) {
this.nacionalidade = nacionalidade;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.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;
Pessoa other = (Pessoa) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
Listagem 2: Pessoa.java

Dentro do pacote dao vamos definir a interface PessoaDao cujo código é mostrado na listagem 3.
package com.sample.dao;

import java.util.List;

import com.sample.model.Pessoa;

public interface PessoaDao {
void save(Pessoa pessoa);
void delete(Integer id);
Pessoa getById(Integer id);
List<Pessoa> findAll();
}
Listagem 3: PessoaDao.java

Dentro do pacote dao é necessário criar também a implementação da interface PessoaDao. No caso do exemplo será definido a classe PessoaDaoImpl (listagem 4).
package com.sample.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sample.model.Pessoa;

public class PessoaDaoImpl implements PessoaDao {
private static PessoaDaoImpl INSTANCE = new PessoaDaoImpl();
private static Map<Integer, Pessoa> database
= new HashMap<Integer, Pessoa>();
private static Integer nextId = 0;

private PessoaDaoImpl() {
}

public static PessoaDaoImpl getInstance() {
return INSTANCE;
}

@Override
public void save(Pessoa pessoa) {
if (pessoa != null) {
if (pessoa.getId() == null) {
nextId++;
pessoa.setId(nextId);
}
database.put(pessoa.getId(), pessoa);
}
}

@Override
public void delete(Integer id) {
if (id != null)
database.remove(id);
}

@Override
public Pessoa getById(Integer id) {
return database.get(id);
}

@Override
public List<Pessoa> findAll() {
return new ArrayList<Pessoa>(database.values());
}
}
Listagem 4: PessoaDaoImpl.java

Dentro do pacote controller vamos definir a classe PessoaController que será o nosso managed bean (listagem 5).
package com.sample.controller;

import java.util.List;

import javax.faces.context.FacesContext;

import com.sample.dao.PessoaDao;
import com.sample.dao.PessoaDaoImpl;
import com.sample.model.Pessoa;

public class PessoaController {
private PessoaDao pessoaDao = PessoaDaoImpl.getInstance();
private Pessoa pessoa;

public PessoaController() {
pessoa = new Pessoa();
}

public void save() {
pessoaDao.save(pessoa);
pessoa = new Pessoa();
}

public void edit() {
// pega o parametro passado no link
Integer id = Integer.parseInt((String)
FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("id"));
pessoa = pessoaDao.getById(id);
}

public void delete(){
// pega o parametro passado no link
Integer id = Integer.parseInt((String)
FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("id"));
pessoaDao.delete(id);
}

// getters e setters
public Pessoa getPessoa() {
return pessoa;
}

public void setPessoa(Pessoa pessoa) {
this.pessoa = pessoa;
}

public List<Pessoa> getPessoas() {
return pessoaDao.findAll();
}
}
Listagem 5: PessoaController.java

Vamos agora configurar o faces-config.xml (localizado dentro da pasta WEB-INF) cuja configuração é mostrada na listagem 6.


<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<navigation-rule>
<from-view-id>pessoa.jsp</from-view-id>
<navigation-case>
<from-outcome>*</from-outcome>
<to-view-id>pessoa.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>pessoaController</managed-bean-name>
<managed-bean-class>
com.sample.controller.PessoaController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Listagem 6: faces-config.xml

Por fim, vamos criar nossa página pessoa.jsp (listagem 7).


<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<html>
<f:view>
<head>
<title><h:outputText value="Desvendando JSF" /></title>
</head>
<body>
<h:form>
<table>
<tr>
<td><h:outputText value="Nome" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nome}" /></td>
</tr>
<tr>
<td><h:outputText value="Nacionalidade" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nacionalidade}" /></td>
</tr>
<tr>
<td><h:commandButton value="salvar" action="#{pessoaController.save}" /></td>
</tr>
</table>
<h:dataTable value="#{pessoaController.pessoas}"
var="p" rendered="#{not empty pessoaController.pessoas}" border="1">
<h:column>
<f:facet name="header">
<h:outputText value="Nome" />
</f:facet>
<h:commandLink value="#{p.nome}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Nacionalidade" />
</f:facet>
<h:commandLink value="#{p.nacionalidade}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Excluir" />
</f:facet>
<h:commandLink value="excluir" action="#{pessoaController.delete}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
</body>
</f:view>
</html>
Listagem 7: pessoa.jsp

A partir deste ponto, com as definições acima, podemos vizualizar a aplicação através da URL http://localhost:8080/jsfdemo/pessoa.faces .

Veja uma prévia do funcionamento dela (figura 5). Trata-se de um CRUD básico de pessoa.

Figura 5: Aplicação JSF


Um excelente referencia para quem deseja aprender conceitos relacionados ao JSF é o livro Core JavaServer Faces.

Os fontes do exemplo (incluindo Jars) estão disponíveis aqui.

Até!

Veja também:

sábado, 30 de maio de 2009

Integrando sistemas corporativos ao Google.

Ferramentas de comunicação e colaboração cada vez mais estão sendo necessárias nas empresas e instituições. Tais ferramentas buscam prover maior interação entre pessoas visando facilitar a realização de atividades em grupo e agilizar tarefas.

Como todos já devem saber, quando se fala em ferramentas de comunicação e colaboração logo lembra-se do Google devido a superioridade dos serviços oferecidos. Há pouco tempo atrás, o Google lançou o Google Apps que, a grosso modo, trata-se de um ponto de acesso aos serviços personalizados de comunicação e colaboração do Google. Em síntese, com Google Apps tornou-se possível que uma instituição tenha acesso a todos os serviços do Google de forma customizada.

Ano passado (2008), a Universidade Federal de Juiz de Fora (MG) iniciou um processo de integração de seu sistema acadêmico com o Google Apps. O projeto foi um sucesso e está até hoje em contínuo desenvolvimento.

Como participante ativo do projeto na época tenho ciência dos benefícios que essa integração trouxe para a universidade.

Para quem se interessar sobre funcionamento o Google Apps acesse:
http://www.google.com/a/help/intl/pt-BR/index.html

Para quem desejar saber como foi a integração do sistema de gestão acadêmica da Universidade Federal de Juiz de Fora com o Google Apps segue uma referência:
http://sites.google.com/site/csscode/Home/integra.pdf?attredirects=0

Eu recomendo a leitura. O projeto é muito interessante (envolve vários conceitos de ciência da conputação) e ainda não vi nenhuma instituição de ensino fazer algo parecido.

Até mais!

sábado, 25 de abril de 2009

Mapeamento objeto-relacional (ORM) com Hibernate – Uma abordagem prática

Nesta postagem será mostrado como fazer o mapeamento objeto-relacional (ORM) utilizando o hibernate através de um exemplo prático. A idéia principal do exemplo é apenas mostrar como fazer o mapeamento objeto-relacional sem ressaltar conceitos envolvidos. Espera-se que ele sirva como uma referência rápida e objetiva para desenvolvedores.

Para iniciar, vamos definir o modelo de dados relacional através de um diagrama entidade-relacionamento (figura abaixo).



Para melhor visualização clique na imagem


Através do diagrama entidade-relacionamento acima, podemos extrair alguns casos a serem mapeados.
  • Herança – Entidades envolvidas: aluno, professor, pessoa;
  • N : M sem atributos intermediários – Entidades envolvidas: disciplina_professor, professor, disciplina;
  • 1 : N – Entidades envolvidas: turma, aluno;
  • N : M com atributo intermediário – Entidades envolvidas: professor_turma, turma, professor.
Abaixo temos as classes java com o mapeamento objeto-relacional exemplificando os casos citados acima.

Mapeamento de Pessoa:

import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "pessoa", catalog = "mapeamentohibernate")
@Inheritance(strategy = InheritanceType.JOINED)
public class Pessoa implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "nome")
private String nome;
// getters e setters omitidos
}

Mapeamento de Aluno:


import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;


@SuppressWarnings("serial")
@Entity
@Table(name = "aluno", catalog = "mapeamentohibernate")
@PrimaryKeyJoinColumn(name = "id") // id da tabela aluno
public class Aluno extends Pessoa implements Serializable {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idturma")
private Turma turma;

@Column(name = "matricula")
private String matricula;

// getters e setters omitidos
}

Mapeamento de Professor:


import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "professor", catalog = "mapeamentohibernate")
@PrimaryKeyJoinColumn(name = "id") // id da tabela professor
public class Professor extends Pessoa implements Serializable {

@Column(name = "formacao")
private String formacao;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "professor")
private Set<ProfessorTurma> professorTurma =
new HashSet<ProfessorTurma>(0);

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "disciplina_professor", catalog = "mapeamentohibernate",
joinColumns = { @JoinColumn(name = "idprofessor", nullable = false,
updatable = false) }, inverseJoinColumns = {
@JoinColumn(name = "iddisciplina", nullable = false, updatable = false) })
private Set<Disciplina> disciplinas = new HashSet<Disciplina>(0);

// getters e setters omitidos
}

Mapeamento de Disciplina:

import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;


@SuppressWarnings("serial")
@Entity
@Table(name = "disciplina", catalog = "mapeamentohibernate")
public class Disciplina implements Serializable {

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "nome")
private String nome;

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "disciplina_professor", catalog = "mapeamentohibernate",
joinColumns = { @JoinColumn(name = "iddisciplina", nullable = false,
updatable = false) }, inverseJoinColumns = {
@JoinColumn(name = "idprofessor", nullable = false, updatable = false) })
private Set<Professor> professores = new HashSet<Professor>(0);

// getters e setters omitidos
}

Mapeamento de Turma:

import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "turma", catalog = "mapeamentohibernate")
public class Turma implements Serializable {

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "descricao")
private String descricao;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "turma")
private Set<ProfessorTurma> professorTurma = new
HashSet<ProfessorTurma>(0);

@OneToMany(fetch = FetchType.LAZY, mappedBy = "turma")
private Set<Aluno> alunos = new HashSet<Aluno>(0);

// getters e setters omitidos
}

Mapeamento de ProfessorTurma:

import java.io.Serializable;
import java.util.Date;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@SuppressWarnings("serial")
@Entity
@Table(name = "professor_turma", catalog = "mapeamentohibernate")
public class ProfessorTurma implements Serializable {

@EmbeddedId
@AttributeOverrides( { @AttributeOverride(name = "idturma", column =
@Column(name = "idturma", nullable = false)), @AttributeOverride(name =
"idprofessor", column = @Column(name = "idprofessor", nullable = false)) })
private Id id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idturma", nullable = false, insertable = false,
updatable = false)
private Turma turma;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idprofessor", nullable = false, insertable = false,
updatable = false)
private Professor professor;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "horario", length = 19)
private Date horario;

// getters e setters omitidos

//Id da associacao (chave composta no banco)
@Embeddable
public static class Id implements Serializable {

@Column(name = "idTurma", nullable = false)
private Integer idTurma;

@Column(name = "idProfessor", nullable = false)
private Integer idProfessor;

public Integer getIdTurma() {
return this.idTurma;
}

public void setIdTurma(Integer idturma) {
this.idTurma = idturma;
}

public Integer getIdProfessor() {
return this.idProfessor;
}

public void setIdProfessor(Integer idprofessor) {
this.idProfessor = idprofessor;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + idProfessor;
result = prime * result + idTurma;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Id other = (Id) obj;
if (idProfessor != other.idProfessor)
return false;
if (idTurma != other.idTurma)
return false;
return true;
}
}
}


Note que, no caso N:M que não tem atributo intermediário (tabela disciplina_professor) , não há necessidade de uma classe para representar a associação. No caso em que há atributos intermediários, como o da tabela professor_turma, temos que criar uma classe para representar a associação (classe ProfessorTurma).

O banco de dados utilizado no exemplo foi o MySQL. Quem quiser fazer o download do script do banco basta acessar o link:
http://sites.google.com/site/csscode/Home/mapeamentohibernate.sql

Uma dica para quem não tem muita familiaridade com o mapeamento objeto-relacional é usar o hibernate tools. O hibernate tools trata-se de um plugin do eclipse que auxilia na árdua e massante tarefa de mapear. Vale a pena conferir!!!


Thiago Baesso Procaci

quinta-feira, 23 de abril de 2009

Testes Unitários da Camada de Persistência com Spring, Hibernate e JUnit.


O teste unitário é uma modalidade de teste voltada para a verificação de “pedaços de software” (ou unidades) que funcionam de maneira independente das demais partes de um sistema. Em softwares construídos em linguagens orientadas a objetos, essas unidades podem ser uma classe ou um método. Em linhas gerais, busca-se com testes unitários garantir que uma parte isolada de um sistema funcione corretamente de acordo com o contexto em que ela se encontra.

Atualmente, em projetos de software, muito se tem visto testes unitários para a camada de persistência com objetivo de assegurar que os objetos que representam o domínio de dados serão salvos, recuperados e excluídos corretamente. Em projetos em que há mudanças consideráveis no modelo de dados (devido a necessidade de adaptações ou mudança de requisitos) os testes unitários da camada de
persistência mostram-se como uma ferramenta poderosa na verificação dos impactos das mudanças na persistência dos dados. Afinal, nada melhor que após mudanças no projeto averiguar que partes isoladas ainda descrevem o comportamento esperado.

Nesta postagem será mostrada uma forma eficiente e prática de testar a camada de persistência de uma aplicação através do uso do spring-test (parte do spring destinada a testes unitários), juntamente com o JUnit. Por questões de praticidade será utilizado o hibernate para o mapeamento objeto-relacional do exemplo.

Para iniciar o exemplo, vamos definir a classe Pessoa que representará a entidade que será persistida no banco de dados.

import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "pessoa", catalog = "springtest")
public class Pessoa implements Serializable {

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;
@Column(name = "nome")
private String nome;
@Column(name = "idade")
private Integer idade;
// getters e setters omitidos
}

Vamos também definir um DAO para pessoa cuja interface será:

public interface PessoaDao {
void save(Pessoa pessoa);
void delete(Pessoa pessoa);
Pessoa getById(Integer id);
}

Certamente para a classe que implementará a interface PessoaDao deverá ser definido um bean no contexto do spring.

Agora vamos montar os testes unitários da camada de persistência de pessoa utilizando o spring-test junto com o JUnit.


import static junit.framework.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.springtest.dao.PessoaDao;
import com.springtest.model.Pessoa;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:WebContent/WEB-INF/persistencia.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class PessoaTest {
@Autowired
private PessoaDao pessoaDao;

@Test
public void testSave() {
Pessoa pessoa = new Pessoa();
pessoa.setNome("Thiago Baesso Procaci");
pessoa.setIdade(22);
pessoaDao.save(pessoa);
assertNotNull(pessoa.getId());
}

@Test
public void testDelete(){
// implementacao do teste
}

@Test
public void testUpdate(){
// implementacao do teste
}
}
Através da classe de teste acima pode-se notar algumas facilidades que o spring-test e o JUnit oferecem através de anotações. Segue abaixo uma breve explicação de cada uma delas:
  • @RunWith(SpringJUnit4ClassRunner.class): anotação responsável por definir “quem” irá rodar os testes. No caso, aclasse SpringJUnit4ClassRunner já provê algumas facilidades para testes
    unitários que utilizam o spring;

  • @ContextConfiguration: carrega o contexto do spring (beans) para serem utilizados na classe de teste;

  • @Transactional / @TransactionConfiguration: definem cada método de teste unitário como uma transação;

  • @Autowired: Injeta os beans do spring para serem utilizados nos testes;

  • @Test: definem os métodos que serão os testes unitários.

Enfim, testes em geral são fundamentais para a assegurar a qualidade de qualquer sistema. Achei essa abordagem com o spring-test muito interessante e prática para a confecção de testes unitários.

Para quem quiser mais detalhes sobre o funcionamento do spring-test acesse:

http://static.springframework.org/spring/docs/2.5.x/reference/testing.html

Os fontes do exemplo estão disponíveis em:

http://sites.google.com/site/csscode/Home/Exemplo_Teste_Unitario.zip?attredirects=0

Abraço a todos!!!

Thiago Baesso Procaci