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