    001    // Copyright 2008, 2010 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.hibernate;
    016
    017    import java.util.List;
    018
    019    import org.apache.tapestry5.grid.GridDataSource;
    020    import org.apache.tapestry5.grid.SortConstraint;
    021    import org.hibernate.Criteria;
    022    import org.hibernate.Session;
    023    import org.hibernate.criterion.Order;
    024    import org.hibernate.criterion.Projections;
    025
    026    /**
    027     * A simple implementation of {@link org.apache.tapestry5.grid.GridDataSource} based on a Hibernate Session and a known
    028     * entity class.  This implementation does support multiple {@link org.apache.tapestry5.grid.SortConstraint sort
    029     * constraints}; however it assumes a direct mapping from sort constraint property to Hibernate property.
    030     * <p/>
    031     * This class is <em>not</em> thread-safe; it maintains internal state.
    032     * <p/>
    033     * Typically, an instance of this object is created fresh as needed (that is, it is not stored between requests).
    034     */
    035    public class HibernateGridDataSource implements GridDataSource
    036    {
    037        private final Session session;
    038
    039        private final Class entityType;
    040
    041        private int startIndex;
    042
    043        private List preparedResults;
    044
    045        public HibernateGridDataSource(Session session, Class entityType)
    046        {
    047            assert session != null;
    048            assert entityType != null;
    049            this.session = session;
    050            this.entityType = entityType;
    051        }
    052
    053        /**
    054         * Returns the total number of rows for the configured entity type.
    055         */
    056        public int getAvailableRows()
    057        {
    058            Criteria criteria = session.createCriteria(entityType);
    059
    060            applyAdditionalConstraints(criteria);
    061
    062            criteria.setProjection(Projections.rowCount());
    063
    064            Number result = (Number) criteria.uniqueResult();
    065
    066            return result.intValue();
    067        }
    068
    069        /**
    070         * Prepares the results, performing a query (applying the sort results, and the provided start and end index). The
    071         * results can later be obtained from {@link #getRowValue(int)} }.
    072         *
    073         * @param startIndex      index, from zero, of the first item to be retrieved
    074         * @param endIndex        index, from zero, of the last item to be retrieved
    075         * @param sortConstraints zero or more constraints used to set the order of the returned values
    076         */
    077        public void prepare(int startIndex, int endIndex, List<SortConstraint> sortConstraints)
    078        {
    079            assert sortConstraints != null;
    080            Criteria crit = session.createCriteria(entityType);
    081
    082            crit.setFirstResult(startIndex).setMaxResults(endIndex - startIndex + 1);
    083
    084            for (SortConstraint constraint : sortConstraints)
    085            {
    086
    087                String propertyName = constraint.getPropertyModel().getPropertyName();
    088
    089                switch (constraint.getColumnSort())
    090                {
    091
    092                    case ASCENDING:
    093
    094                        crit.addOrder(Order.asc(propertyName));
    095                        break;
    096
    097                    case DESCENDING:
    098                        crit.addOrder(Order.desc(propertyName));
    099                        break;
    100
    101                    default:
    102                }
    103            }
    104
    105            applyAdditionalConstraints(crit);
    106
    107            this.startIndex = startIndex;
    108
    109            preparedResults = crit.list();
    110        }
    111
    112        /**
    113         * Invoked after the main criteria has been set up (firstResult, maxResults and any sort contraints). This gives
    114         * subclasses a chance to apply additional constraints before the list of results is obtained from the criteria.
    115         * This implementation does nothing and may be overridden.
    116         */
    117        protected void applyAdditionalConstraints(Criteria crit)
    118        {
    119        }
    120
    121        /**
    122         * Returns a row value at the given index (which must be within the range defined by the call to {@link
    123         * #prepare(int, int, java.util.List)} ).
    124         *
    125         * @param index of object
    126         * @return object at that index
    127         */
    128        public Object getRowValue(int index)
    129        {
    130            return preparedResults.get(index - startIndex);
    131        }
    132
    133        /**
    134         * Returns the entity type, as provided via the constructor.
    135         */
    136        public Class getRowType()
    137        {
    138            return entityType;
    139        }
    140    }