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 }