/**
* This file is part of xss-jpa.
*
* Copyright 2012 Sebastian Schmelzer
* http://xss.nu/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with library. If not, see .
*
*/
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;
/**
* The Class GenericJpaDao.
*
* @param
* the element type
* @param
* the key type
*/
public abstract class GenericJpaDao, K> implements
Dao, Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 4998055731089977476L;
/** The logger. */
private Logger logger = LoggerFactory.getLogger(this.getClass());
/** The entity manager. */
@PersistenceContext
private EntityManager entityManager;
/** The entity. */
private Class entityClass;
/**
* Instantiates a new generic jpa dao.
*/
@SuppressWarnings("unchecked")
public GenericJpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass()
.getGenericSuperclass();
Type type = genericSuperclass.getActualTypeArguments()[0];
if (type instanceof Class) {
this.entityClass = (Class) type;
} else if (type instanceof ParameterizedType) {
this.entityClass = (Class) ((ParameterizedType) type).getRawType();
}
}
@Override
public void save(final E entity) {
getEntityManager().persist(entity);
logger.info("Saved entity: {}.", entity.toString());
}
@Override
public void merge(final E entity) {
getEntityManager().merge(entity);
logger.info("Updated unmanaged entity: {}.", entity.toString());
}
@Override
public void delete(final E entity) {
final E persistentEntity = findById(entity.getId());
if (persistentEntity != null) {
getEntityManager().remove(persistentEntity);
}
logger.info("Deleted entity: {}.", entity.toString());
}
@Override
public final E findById(final K id) {
return getEntityManager().find(entityClass, id);
}
@Override
public int count() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int count(final Filter... filter) {
// TODO Auto-generated method stub
return 0;
}
@Override
public final List findAll() {
return find(null, null, null);
}
@Override
public final List findAll(final Sort sort) {
return find(null, sort, null);
}
@Override
public final List findAll(final Pagination pagination) {
return find(null, null, pagination);
}
@Override
public final List findAll(final Sort sort, final Pagination pagination) {
return find(null, sort, pagination);
}
@Override
public final List findAll(final Filter... filter) {
return find(null, null, null, filter);
}
@Override
public final List findAll(final Sort sort, final Filter... filter) {
return find(null, sort, null, filter);
}
@Override
public final List findAll(final Pagination pagination, final Filter... filter) {
return find(null, null, pagination, filter);
}
@Override
public final List findAll(final Sort sort, final Pagination pagination, final Filter... filter) {
return find(null, sort, pagination, filter);
}
/**
* Creates the query.
*
* @return the criteria query
*/
protected final CriteriaQuery createQuery() {
CriteriaQuery c = getCriteriaBuilder().createQuery(this.entityClass);
return c;
}
/**
* Find.
*
* @param query
* the query
* @return the list
*/
protected final List find(final CriteriaQuery query) {
return find(query, null, null);
}
/**
* Find.
*
* @param query
* the query
* @param pagination
* the pagination
* @return the list
*/
protected final List find(final CriteriaQuery query, final Pagination pagination) {
return find(query, null, pagination);
}
/**
* Find.
*
* @param query
* the query
* @param sort
* the sort
* @return the list
*/
protected final List find(final CriteriaQuery query, final Sort sort) {
return find(query, sort, null);
}
/**
* Find.
*
* @param query
* the query
* @param sort
* the sort
* @param pagination
* the pagination
* @param filter
* the filter
* @return the list
*/
protected List find(final CriteriaQuery query, final Sort sort, final Pagination pagination,
final Filter... filter) {
Root root;
CriteriaQuery q = query;
// check if we have a 'simple' query
if (q == null) {
q = createQuery();
}
root = q.from(getEntityClass());
q.select(root);
if (filter != null) {
Set predicates = new HashSet();
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()) {
q.orderBy(getCriteriaBuilder().asc(root.get(sort.getColumn())));
} else {
q.orderBy(getCriteriaBuilder().desc(root.get(sort.getColumn())));
}
}
// Result pagination
TypedQuery tq = getEntityManager().createQuery(q);
// TODO: do we need to check cast long->int?
if (pagination != null) {
if (pagination.getCount() > 0) {
tq.setMaxResults((int) pagination.getOffset());
}
if (pagination.getOffset() > 0) {
tq.setFirstResult((int) pagination.getCount());
}
}
return tq.getResultList();
}
/**
* Find single.
*
* @param query
* the query
* @return the e
*/
protected final E findSingle(final CriteriaQuery query) {
return getEntityManager().createQuery(query).getSingleResult();
}
/**
* Find single or null.
*
* @param query
* the query
* @return the e
*/
protected final E findSingleOrNull(final CriteriaQuery 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;
}
}
/**
* Find single first or null.
*
* @param query
* the query
* @return the e
*/
protected final E findSingleFirstOrNull(final CriteriaQuery 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);
}
}
/**
* Gets the criteria builder.
*
* @return the criteria builder
*/
protected final CriteriaBuilder getCriteriaBuilder() {
return getEntityManager().getCriteriaBuilder();
}
/**
* Gets the logger.
*
* @return the logger
*/
public final Logger getLogger() {
return logger;
}
/**
* Gets the entity manager.
*
* @return the entity manager
*/
public final EntityManager getEntityManager() {
return entityManager;
}
/**
* Sets the entity manager.
*
* @param entityManager the new entity manager
*/
public final void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* Gets the entity class.
*
* @return the entity class
*/
public Class getEntityClass() {
return entityClass;
}
}