package com.metrink.croquet.examples.crm.data; import java.io.Serializable; import java.util.Iterator; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * A generic {@link SortableDataProvider} that reads from a DB through an {@link EntityManager}. * * @param <T> the type of the entity to read. */ public class GenericDataProvider<T extends Serializable> extends SortableDataProvider<T, String> { private static final long serialVersionUID = -4513383410805199586L; private static final Logger LOG = LoggerFactory.getLogger(GenericDataProvider.class); @SuppressFBWarnings("SE_BAD_FIELD") private final EntityManager entityManager; private final Class<T> type; /** * Constructs an instance of the {@link GenericDataProvider} injecting an instance of the {@link EntityManager}. * @param entityManager the injected {@link EntityManager} to be used for queries. * @param type the type to associate with the data provider. */ @Inject GenericDataProvider(final EntityManager entityManager, @Assisted final Class<T> type) { this.entityManager = entityManager; this.type = type; } @Override public IModel<T> model(final T arg) { return new Model<T>(arg); } /** * Get the entity manager for classes that extend this one. * @return returns the entity manager. */ EntityManager getEntityManager() { return entityManager; } /* * Note we cannot use the @Transactional annotation here because it makes * not serializable: https://code.google.com/p/google-guice/issues/detail?id=12 */ @Override public Iterator<? extends T> iterator(final long first, final long count) { entityManager.getTransaction().begin(); try { final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); final CriteriaQuery<T> criteria = criteriaBuilder.createQuery(type); final Root<T> from = criteria.from(type); // setup the sort final SortParam<String> param = getSort(); if(param == null || param.isAscending()) { LOG.debug("Setting order by to ascending for {}", type.getName()); criteria.orderBy(criteriaBuilder.asc(from.get("name"))); } else { LOG.debug("Setting order by to descending for {}", type.getName()); criteria.orderBy(criteriaBuilder.desc(from.get("name"))); } return entityManager.createQuery(criteria) .setFirstResult((int)first) .setMaxResults((int)count) .getResultList() .iterator(); } finally { entityManager.getTransaction().commit(); } } @Override public long size() { return entityManager.createQuery("select count(*) from " + type.getName(), Long.class) .getSingleResult(); } /** * Factory class for the {@link GenericDataProvider}. */ public interface GenericDataProviderFactory<T2 extends Serializable> { /** * Factory method for creating a new {@link GenericDataProvider} given a type. * @param type the entity type to associate with this {@link GenericDataProvider}. * @return an {@link GenericDataProvider}. */ public GenericDataProvider<T2> create(final Class<T2> type); } }