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 015package org.apache.tapestry5.jpa; 016 017import java.util.List; 018 019import javax.persistence.EntityManager; 020import javax.persistence.TypedQuery; 021import javax.persistence.criteria.CriteriaBuilder; 022import javax.persistence.criteria.CriteriaQuery; 023import javax.persistence.criteria.Path; 024import javax.persistence.criteria.Root; 025 026import org.apache.tapestry5.grid.GridDataSource; 027import 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 */ 043public 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 @Override 065 public int getAvailableRows() 066 { 067 final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 068 069 CriteriaQuery<Long> criteria = builder.createQuery(Long.class); 070 071 final Root<E> root = criteria.from(entityType); 072 073 criteria = criteria.select(builder.count(root)); 074 075 applyAdditionalConstraints(criteria, root, builder); 076 077 return entityManager.createQuery(criteria).getSingleResult().intValue(); 078 } 079 080 /** 081 * {@inheritDoc} 082 */ 083 @Override 084 public void prepare(final int startIndex, final int endIndex, 085 final List<SortConstraint> sortConstraints) 086 { 087 final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 088 089 final CriteriaQuery<E> criteria = builder.createQuery(entityType); 090 091 final Root<E> root = criteria.from(entityType); 092 093 applyAdditionalConstraints(criteria.select(root), root, builder); 094 095 for (final SortConstraint constraint : sortConstraints) 096 { 097 098 final String propertyName = constraint.getPropertyModel().getPropertyName(); 099 100 final Path<Object> propertyPath = root.get(propertyName); 101 102 switch (constraint.getColumnSort()) 103 { 104 105 case ASCENDING: 106 107 criteria.orderBy(builder.asc(propertyPath)); 108 break; 109 110 case DESCENDING: 111 criteria.orderBy(builder.desc(propertyPath)); 112 break; 113 114 default: 115 } 116 } 117 118 final TypedQuery<E> query = entityManager.createQuery(criteria); 119 120 query.setFirstResult(startIndex); 121 query.setMaxResults(endIndex - startIndex + 1); 122 123 this.startIndex = startIndex; 124 125 preparedResults = query.getResultList(); 126 127 } 128 129 protected void applyAdditionalConstraints(final CriteriaQuery<?> criteria, final Root<E> root, 130 final CriteriaBuilder builder) 131 { 132 } 133 134 /** 135 * {@inheritDoc} 136 */ 137 @Override 138 public Object getRowValue(final int index) 139 { 140 return preparedResults.get(index - startIndex); 141 } 142 143 /** 144 * {@inheritDoc} 145 */ 146 @Override 147 public Class<E> getRowType() 148 { 149 return entityType; 150 } 151 152}