package org.meb.speedway.dao;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.ManyToMany;
import javax.persistence.NoResultException;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.ManagedType;
import org.apache.commons.lang.StringUtils;
import org.meb.speedway.Query;
import org.meb.speedway.SortOrder;
import org.meb.speedway.SortOrder.Direction;
import org.meb.speedway.SortOrder.SortOrderItem;
import org.meb.speedway.config.General;
import org.meb.speedway.config.SpeedwayDatabase;
@General
public class BaseDao<T> {
@Inject
@SpeedwayDatabase
private EntityManager em;
public EntityManager getEntityManager() {
return em;
}
public T find(Class<T> clazz, Object id) {
return em.find(clazz, id);
}
public List<T> find(Query<T> query) {
Class<T> clazz = (Class<T>) query.getEntityClass();
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(clazz);
Root<T> root = cq.from(clazz);
ManagedType<T> mt = em.getMetamodel().managedType(clazz);
SortOrder sortOrder = query.getSortOrder();
if (sortOrder != null && !sortOrder.isEmpty()) {
// Iterator<Entry<String, Direction>> iter = sortOrder.iterator();
Iterator<SortOrderItem> iter = sortOrder.iterator();
List<Order> orderList = new ArrayList<Order>();
while (iter.hasNext()) {
// Entry<String, Direction> entry = iter.next();
// Path<?> path =
// root.get(mt.getSingularAttribute(entry.getKey()));
// if (entry.getValue() == Direction.ASC) {
// orderList.add(cb.asc(path));
// } else if (entry.getValue() == Direction.DESC) {
// orderList.add(cb.desc(path));
// } else if (entry.getValue() == Direction.ASC_TRUNC) {
// orderList.add(cb.asc(cb.function("trunc", Path.class,
// path)));
// } else if (entry.getValue() == Direction.DESC_TRUNC) {
// orderList.add(cb.desc(cb.function("trunc", Path.class,
// path)));
// }
SortOrderItem item = iter.next();
Path<?> path = root.get(mt.getSingularAttribute(item.getProperty()));
Direction direction = item.getDirection();
if (direction == Direction.ASC) {
orderList.add(cb.asc(path));
} else if (direction == Direction.DESC) {
orderList.add(cb.desc(path));
} else if (direction == Direction.ASC_TRUNC) {
orderList.add(cb.asc(cb.function("trunc", Path.class, path)));
} else if (direction == Direction.DESC_TRUNC) {
orderList.add(cb.desc(cb.function("trunc", Path.class, path)));
}
}
cq.orderBy(orderList);
}
List<Predicate> predicates = createPredicates(query, root);
if (predicates.size() > 0) {
cq.where(predicates.toArray(new Predicate[predicates.size()]));
}
return getEntityManager().createQuery(cq).getResultList();
}
public T findUnique(Query<T> query) {
Class<T> clazz = (Class<T>) query.getEntityClass();
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(clazz);
Root<T> root = cq.from(clazz);
List<Predicate> predicates = createPredicates(query, root);
if (predicates.size() > 0) {
cq.where(predicates.toArray(new Predicate[predicates.size()]));
}
try {
return getEntityManager().createQuery(cq).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
private List<Predicate> createPredicates(Query<T> query, Root<T> root) {
Class<T> clazz = query.getEntityClass();
ManagedType<T> mt = em.getMetamodel().managedType(clazz);
List<Predicate> predicates = new ArrayList<Predicate>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers())
|| Modifier.isTransient(field.getModifiers())) {
continue;
}
if (field.isAnnotationPresent(Transient.class)
|| field.isAnnotationPresent(OneToMany.class)
|| field.isAnnotationPresent(ManyToMany.class)
|| field.isAnnotationPresent(OneToOne.class)) {
continue;
}
String getterName = "get" + StringUtils.capitalize(field.getName());
try {
Object value = clazz.getMethod(getterName).invoke(query.getEntity(),
new Object[] {});
if (value != null) {
predicates.add(em.getCriteriaBuilder().equal(
root.get(mt.getSingularAttribute(field.getName())), value));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return predicates;
}
public void persist(T entity) {
getEntityManager().persist(entity);
}
public T merge(T entity) {
return getEntityManager().merge(entity);
}
}