/*
*
* Copyright (c) 2013 - 2014 INT - National Institute of Technology & COPPE - Alberto Luiz Coimbra Institute
- Graduate School and Research in Engineering.
* See the file license.txt for copyright permission.
*
*/
package DAO.generico;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import DAO.exception.InfraestruturaException;
import DAO.exception.ObjetoNaoEncontradoException;
import util.JPAUtil;
import util.ListaComPaginacao;
/**
* Faz a implementa��o de um DAO gen�rico para a JPA. � uma classe inteiramente
* gen�rica que pode ser usada exatamente como est� em qualquer aplica��o.
*
* Faz uma implementa��o "typesafe" dos m�todos CRUD e dos m�todos de busca.
*
* Ser "typesafe" significa que o compilador consegue identificar o tipo do
* objeto
*/
public class JPADaoGenerico<T, PK extends Serializable> implements
DaoGenerico<T, PK> {
private Class<T> clazz;// tipo == Familia.class
public JPADaoGenerico(Class<T> tipo) {
this.clazz = tipo;
}
@SuppressWarnings("unchecked")
public final T inclui(T o) {
EntityManager em = JPAUtil.getEntityManager();
try {
em.persist(o);
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
return o;
}
public final void altera(T o) {
EntityManager em = JPAUtil.getEntityManager();
try {
em.merge(o);
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
/**
* Este m�todo exige que o objeto passado seja persistente senao gera um erro!
*/
public final void exclui(T o) {
EntityManager em = JPAUtil.getEntityManager();
try {
em.remove(o);
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
public final T getPorId(PK id) throws ObjetoNaoEncontradoException {
EntityManager em = JPAUtil.getEntityManager();
T t = null;
try {
t = em.find(clazz, id);
if (t == null) {
throw new ObjetoNaoEncontradoException();
}
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
return t;
}
// implementacao de lock pessimista
// deve ter cuidado pois deve ser usado no inicio do processo de acesso ao
// recurso critico
// para que nao haja risco de alteracoes simultaneas
public final T getPorIdComLock(PK id) throws ObjetoNaoEncontradoException {
EntityManager em = JPAUtil.getEntityManager();
T t = null;
try {
t = em.find(clazz, id);
if (t != null) {
em.lock(t, LockModeType.READ); // read: define o tipo de lock
// como sendo de leitura
em.refresh(t);
} else {
throw new ObjetoNaoEncontradoException();
}
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
return t;
}
// daqui para baixo s�o os metodos relativos ao "ExecutorDeBuscas" (os
// metodos acima s�o efetivamente genericos
// enquanto que os de busca s�o genericos porem tem querys especificas.
@SuppressWarnings("unchecked")
public final T busca(Method metodo, Object[] argumentos)
throws ObjetoNaoEncontradoException {
EntityManager em = JPAUtil.getEntityManager();
T t = null;
try {
String nomeDaBusca = getNomeDaBuscaPeloMetodo(metodo); // ex:
// Familia.recuperaUmaFamiliaEModelos
Query namedQuery = em.createNamedQuery(nomeDaBusca);
preencheParametros(argumentos, namedQuery);
t = (T) namedQuery.getSingleResult();
return t;
} catch (NoResultException e)// caso nao seja encontrado o objeto sera
// retornada esta excecao
{
throw new ObjetoNaoEncontradoException();
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
@SuppressWarnings("unchecked")
public final T buscaUltimoOuPrimeiro(Method metodo, Object[] argumentos)
throws ObjetoNaoEncontradoException {
EntityManager em = JPAUtil.getEntityManager();
T t = null;
try {
List lista;
String nomeDaBusca = getNomeDaBuscaPeloMetodo(metodo);
Query namedQuery = em.createNamedQuery(nomeDaBusca);
preencheParametros(argumentos, namedQuery);
lista = namedQuery.getResultList();
t = (lista.size() == 0) ? null : (T) lista.get(0);
if (t == null) {
throw new ObjetoNaoEncontradoException();
}
return t;
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
@SuppressWarnings("unchecked")
public final List<T> buscaLista(Method metodo, Object[] argumentos) {
EntityManager em = JPAUtil.getEntityManager();
try {
String nomeDaBusca = getNomeDaBuscaPeloMetodo(metodo);
Query namedQuery = em.createNamedQuery(nomeDaBusca);
preencheParametros(argumentos, namedQuery);
return (List<T>) namedQuery.getResultList();
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
@SuppressWarnings("unchecked")
public final Set<T> buscaConjunto(Method metodo, Object[] argumentos) {
EntityManager em = JPAUtil.getEntityManager();
try {
String nomeDaBusca = getNomeDaBuscaPeloMetodo(metodo);
Query namedQuery = em.createNamedQuery(nomeDaBusca);
preencheParametros(argumentos, namedQuery);
List<T> lista = namedQuery.getResultList();
return new LinkedHashSet(lista);
} catch (RuntimeException e) {
throw new InfraestruturaException(e);
}
}
@SuppressWarnings("unchecked")
public final List<T> buscaListaPaginada(Method metodo, Object[] argumentos,
int pageSize) {
EntityManager em = JPAUtil.getEntityManager();
String nomeDaBusca = null;
try {
nomeDaBusca = getNomeDaBuscaPeloMetodo(metodo);
String nomeDaBuscaCount = nomeDaBusca + "Count";
Query namedQueryCount = em.createNamedQuery(nomeDaBuscaCount);
preencheParametros(argumentos, namedQueryCount);
long tamanhoTotal = 0;
try {
tamanhoTotal = (Long) namedQueryCount.getSingleResult();
} catch (NoResultException e) {
}
return new ListaComPaginacao<T>(nomeDaBusca, argumentos, pageSize,
tamanhoTotal);
} catch (PersistenceException pe) {
pe.printStackTrace();
throw new InfraestruturaException(
"A NAMED QUERY DO COUNT DEVE SER CRIADA! O SEU NOME DEVE SER: "
+ nomeDaBusca + "Count");
} catch (RuntimeException e) {
e.printStackTrace();
throw new InfraestruturaException(e);
}
}
@SuppressWarnings("unchecked")
public static <T> List<T> executaQuery(String hql, Object[] argumentos,
int inicio, int quantidade) {
EntityManager em = JPAUtil.getEntityManager();
try {
Query query = em.createNamedQuery(hql);
preencheParametros(argumentos, query);
// define o primeiro elemento a ser recuperado e
// a quantidade de elementos a serem recuperados
return query.setFirstResult(inicio).setMaxResults(quantidade)
.getResultList();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
JPAUtil.closeEntityManager();
}
return null;
}
// preenche os parametros posicionalmente, ou seja na ordem em que os
// parametros s�o declarados na query
private static void preencheParametros(Object[] argumentos, Query namedQuery) {
if (argumentos != null) {
for (int i = 0; i < argumentos.length; i++) {
Object arg = argumentos[i];
namedQuery.setParameter(i + 1, arg);// Par�metros de buscas
// s�o 1-based.
}
}
}
// devolve uma String com o nome da classe + nome do metodo.
private String getNomeDaBuscaPeloMetodo(Method metodo) {
return clazz.getSimpleName() + "." + metodo.getName(); // ex:
// Familia.recuperaPorDescricao
}
}