    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
    015package org.apache.tapestry5.hibernate;
    016
    017import java.util.List;
    018
    019import org.apache.tapestry5.grid.GridDataSource;
    020import org.apache.tapestry5.grid.SortConstraint;
    021import org.hibernate.Criteria;
    022import org.hibernate.Session;
    023import org.hibernate.criterion.Order;
    024import 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 */
    035public 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    @Override
    057    public int getAvailableRows()
    058    {
    059        Criteria criteria = session.createCriteria(entityType);
    060
    061        applyAdditionalConstraints(criteria);
    062
    063        criteria.setProjection(Projections.rowCount());
    064
    065        Number result = (Number) criteria.uniqueResult();
    066
    067        return result.intValue();
    068    }
    069
    070    /**
    071     * Prepares the results, performing a query (applying the sort results, and the provided start and end index). The
    072     * results can later be obtained from {@link #getRowValue(int)} }.
    073     *
    074     * @param startIndex      index, from zero, of the first item to be retrieved
    075     * @param endIndex        index, from zero, of the last item to be retrieved
    076     * @param sortConstraints zero or more constraints used to set the order of the returned values
    077     */
    078    @Override
    079    public void prepare(int startIndex, int endIndex, List<SortConstraint> sortConstraints)
    080    {
    081        assert sortConstraints != null;
    082        Criteria crit = session.createCriteria(entityType);
    083
    084        crit.setFirstResult(startIndex).setMaxResults(endIndex - startIndex + 1);
    085
    086        for (SortConstraint constraint : sortConstraints)
    087        {
    088
    089            String propertyName = constraint.getPropertyModel().getPropertyName();
    090
    091            switch (constraint.getColumnSort())
    092            {
    093
    094                case ASCENDING:
    095
    096                    crit.addOrder(Order.asc(propertyName));
    097                    break;
    098
    099                case DESCENDING:
    100                    crit.addOrder(Order.desc(propertyName));
    101                    break;
    102
    103                default:
    104            }
    105        }
    106
    107        applyAdditionalConstraints(crit);
    108
    109        this.startIndex = startIndex;
    110
    111        preparedResults = crit.list();
    112    }
    113
    114    /**
    115     * Invoked after the main criteria has been set up (firstResult, maxResults and any sort contraints). This gives
    116     * subclasses a chance to apply additional constraints before the list of results is obtained from the criteria.
    117     * This implementation does nothing and may be overridden.
    118     */
    119    protected void applyAdditionalConstraints(Criteria crit)
    120    {
    121    }
    122
    123    /**
    124     * Returns a row value at the given index (which must be within the range defined by the call to {@link
    125     * #prepare(int, int, java.util.List)} ).
    126     *
    127     * @param index of object
    128     * @return object at that index
    129     */
    130    @Override
    131    public Object getRowValue(int index)
    132    {
    133        return preparedResults.get(index - startIndex);
    134    }
    135
    136    /**
    137     * Returns the entity type, as provided via the constructor.
    138     */
    139    @Override
    140    public Class getRowType()
    141    {
    142        return entityType;
    143    }
    144}