package nu.xss.jpa.dao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import nu.xss.jpa.entity.TypedEntity;
import nu.xss.jpa.query.Pagination;
import nu.xss.jpa.query.Sort;
import nu.xss.jpa.query.filter.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class GenericJpaDao<E extends TypedEntity<K>, K> implements
Dao<E, K>, Serializable {
private static final long serialVersionUID = 4998055731089977476L;
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@PersistenceContext
protected EntityManager entityManager;
protected Class<E> entity;
@SuppressWarnings("unchecked")
public GenericJpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass()
.getGenericSuperclass();
Type type = genericSuperclass.getActualTypeArguments()[0];
if (type instanceof Class) {
this.entity = (Class<E>) type;
} else if (type instanceof ParameterizedType) {
this.entity = (Class<E>) ((ParameterizedType)type).getRawType();
}
}
public void save(E entity) {
entityManager.persist(entity);
logger.info("Saved entity: {}.", entity.toString());
}
public void merge(E entity) {
entityManager.merge(entity);
logger.info("Updated unmanaged entity: {}.", entity.toString());
}
public void delete(E entity) {
final E persistentEntity = findById(entity.getId());
if (persistentEntity != null) {
entityManager.remove(persistentEntity);
}
logger.info("Deleted entity: {}.", entity.toString());
}
public E findById(K id) {
return entityManager.find(entity, id);
}
@Override
public int count() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int count(Filter... filter) {
// TODO Auto-generated method stub
return 0;
}
@Override
public List<E> findAll() {
return find(null, null, null);
}
@Override
public List<E> findAll(Sort sort) {
return find(null, sort, null);
}
@Override
public List<E> findAll(Pagination pagination) {
return find(null, null, pagination);
}
@Override
public List<E> findAll(Sort sort, Pagination pagination) {
return find(null, sort, pagination);
}
@Override
public List<E> findAll(Filter... filter) {
return find(null, null, null, filter);
}
@Override
public List<E> findAll(Sort sort, Filter... filter) {
return find(null, sort, null, filter);
}
@Override
public List<E> findAll(Pagination pagination, Filter... filter) {
return find(null, null, pagination, filter);
}
@Override
public List<E> findAll(Sort sort, Pagination pagination, Filter... filter) {
return find(null, sort, pagination, filter);
}
protected List<E> find(CriteriaQuery<E> query) {
return find(query, null, null);
}
protected List<E> find(CriteriaQuery<E> query, Pagination pagination) {
return find(query, null, pagination);
}
protected List<E> find(CriteriaQuery<E> query, Sort sort) {
return find(query, sort, null);
}
protected List<E> find(CriteriaQuery<E> query, Sort sort, Pagination pagination, Filter... filter) {
Root<E> root;
// check if we have a 'simple' query
if (query == null) {
query = createQuery();
}
root = query.from(this.entity);
query.select(root);
if (filter != null) {
Set<Predicate> predicates = new HashSet<Predicate>();
for (final Filter f: filter) {
f.buildFilters(getCriteriaBuilder(), root);
for (Predicate p : f.getPredicates()) {
predicates.add(p);
}
}
if (predicates.size() > 0) {
query.where((Predicate[]) predicates.toArray());
}
}
// Result Sorting
// TODO: Multcolum sort
if (sort != null) {
if (sort.isAsc()) {
query.orderBy(getCriteriaBuilder().asc(root.get(sort.getColumn())));
} else {
query.orderBy(getCriteriaBuilder().desc(root.get(sort.getColumn())));
}
}
// Result pagination
TypedQuery<E> q = entityManager.createQuery(query);
if (pagination != null) {
if ( pagination.getCount() > 0 ) {
q.setFirstResult(pagination.getCount());
}
if ( pagination.getOffset() > 0) {
q.setMaxResults(pagination.getOffset());
}
}
return q.getResultList();
}
protected E findSingle(CriteriaQuery<E> query) {
return entityManager.createQuery(query).getSingleResult();
}
protected E findSingleOrNull(CriteriaQuery<E> query) {
try {
return findSingle(query);
} catch (final NoResultException e) {
return null;
} catch (final NonUniqueResultException e) {
logger.error("Found more than one result.. return first one");
return null;
}
}
protected E findSingleFirstOrNull(CriteriaQuery<E> query) {
try {
return findSingle(query);
} catch (final NoResultException e) {
return null;
} catch (final NonUniqueResultException e) {
logger.warn("Found more than one result.. return first one");
return find(query).get(0);
}
}
protected CriteriaBuilder getCriteriaBuilder() {
return entityManager.getCriteriaBuilder();
}
protected CriteriaQuery<E> createQuery() {
CriteriaQuery<E> c = getCriteriaBuilder().createQuery(this.entity);
return c;
}
}