001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.jpa; 014 015import org.apache.tapestry5.grid.GridDataSource; 016import org.apache.tapestry5.grid.SortConstraint; 017 018import javax.persistence.EntityManager; 019import javax.persistence.TypedQuery; 020import javax.persistence.criteria.CriteriaBuilder; 021import javax.persistence.criteria.CriteriaQuery; 022import javax.persistence.criteria.Path; 023import javax.persistence.criteria.Root; 024import java.util.List; 025 026/** 027 * A simple implementation of {@link org.apache.tapestry5.grid.GridDataSource} based on a 028 * {@linkplain javax.persistence.EntityManager} and a known 029 * entity class. This implementation does support multiple 030 * {@link org.apache.tapestry5.grid.SortConstraint sort 031 * constraints}. 032 * 033 * This class is <em>not</em> thread-safe; it maintains internal state. 034 * 035 * Typically, an instance of this object is created fresh as needed (that is, it is not stored 036 * between requests). 037 * 038 * @since 5.3 039 */ 040public class JpaGridDataSource<E> implements GridDataSource 041{ 042 043 private final EntityManager entityManager; 044 045 private final Class<E> entityType; 046 047 private int startIndex; 048 049 private List<E> preparedResults; 050 051 public JpaGridDataSource(final EntityManager entityManager, final Class<E> entityType) 052 { 053 super(); 054 this.entityManager = entityManager; 055 this.entityType = entityType; 056 } 057 058 /** 059 * {@inheritDoc} 060 */ 061 @Override 062 public int getAvailableRows() 063 { 064 final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 065 066 CriteriaQuery<Long> criteria = builder.createQuery(Long.class); 067 068 final Root<E> root = criteria.from(entityType); 069 070 criteria = criteria.select(builder.count(root)); 071 072 applyAdditionalConstraints(criteria, root, builder); 073 074 return entityManager.createQuery(criteria).getSingleResult().intValue(); 075 } 076 077 /** 078 * {@inheritDoc} 079 */ 080 @Override 081 public void prepare(final int startIndex, final int endIndex, 082 final List<SortConstraint> sortConstraints) 083 { 084 final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 085 086 final CriteriaQuery<E> criteria = builder.createQuery(entityType); 087 088 final Root<E> root = criteria.from(entityType); 089 090 applyAdditionalConstraints(criteria.select(root), root, builder); 091 092 for (final SortConstraint constraint : sortConstraints) 093 { 094 095 final String propertyName = constraint.getPropertyModel().getPropertyName(); 096 097 final Path<Object> propertyPath = root.get(propertyName); 098 099 switch (constraint.getColumnSort()) 100 { 101 102 case ASCENDING: 103 104 criteria.orderBy(builder.asc(propertyPath)); 105 break; 106 107 case DESCENDING: 108 criteria.orderBy(builder.desc(propertyPath)); 109 break; 110 111 default: 112 } 113 } 114 115 final TypedQuery<E> query = entityManager.createQuery(criteria); 116 117 query.setFirstResult(startIndex); 118 query.setMaxResults(endIndex - startIndex + 1); 119 120 this.startIndex = startIndex; 121 122 preparedResults = query.getResultList(); 123 124 } 125 126 protected void applyAdditionalConstraints(final CriteriaQuery<?> criteria, final Root<E> root, 127 final CriteriaBuilder builder) 128 { 129 } 130 131 /** 132 * {@inheritDoc} 133 */ 134 @Override 135 public Object getRowValue(final int index) 136 { 137 return preparedResults.get(index - startIndex); 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public Class<E> getRowType() 145 { 146 return entityType; 147 } 148 149}