    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    }