// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.jpa; import org.apache.tapestry5.grid.GridDataSource; import org.apache.tapestry5.grid.SortConstraint; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; import java.util.List; /** * A simple implementation of {@link org.apache.tapestry5.grid.GridDataSource} based on a * {@linkplain javax.persistence.EntityManager} and a known * entity class. This implementation does support multiple * {@link org.apache.tapestry5.grid.SortConstraint sort * constraints}. * * This class is <em>not</em> thread-safe; it maintains internal state. * * Typically, an instance of this object is created fresh as needed (that is, it is not stored * between requests). * * @since 5.3 */ public class JpaGridDataSource<E> implements GridDataSource { private final EntityManager entityManager; private final Class<E> entityType; private int startIndex; private List<E> preparedResults; public JpaGridDataSource(final EntityManager entityManager, final Class<E> entityType) { super(); this.entityManager = entityManager; this.entityType = entityType; } /** * {@inheritDoc} */ @Override public int getAvailableRows() { final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Long> criteria = builder.createQuery(Long.class); final Root<E> root = criteria.from(entityType); criteria = criteria.select(builder.count(root)); applyAdditionalConstraints(criteria, root, builder); return entityManager.createQuery(criteria).getSingleResult().intValue(); } /** * {@inheritDoc} */ @Override public void prepare(final int startIndex, final int endIndex, final List<SortConstraint> sortConstraints) { final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); final CriteriaQuery<E> criteria = builder.createQuery(entityType); final Root<E> root = criteria.from(entityType); applyAdditionalConstraints(criteria.select(root), root, builder); for (final SortConstraint constraint : sortConstraints) { final String propertyName = constraint.getPropertyModel().getPropertyName(); final Path<Object> propertyPath = root.get(propertyName); switch (constraint.getColumnSort()) { case ASCENDING: criteria.orderBy(builder.asc(propertyPath)); break; case DESCENDING: criteria.orderBy(builder.desc(propertyPath)); break; default: } } final TypedQuery<E> query = entityManager.createQuery(criteria); query.setFirstResult(startIndex); query.setMaxResults(endIndex - startIndex + 1); this.startIndex = startIndex; preparedResults = query.getResultList(); } protected void applyAdditionalConstraints(final CriteriaQuery<?> criteria, final Root<E> root, final CriteriaBuilder builder) { } /** * {@inheritDoc} */ @Override public Object getRowValue(final int index) { return preparedResults.get(index - startIndex); } /** * {@inheritDoc} */ @Override public Class<E> getRowType() { return entityType; } }