001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005//     http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.hibernate;
014
015import org.apache.tapestry5.grid.GridDataSource;
016import org.apache.tapestry5.grid.SortConstraint;
017import org.hibernate.Criteria;
018import org.hibernate.Session;
019import org.hibernate.criterion.Order;
020import org.hibernate.criterion.Projections;
021
022import java.util.List;
023
024/**
025 * A simple implementation of {@link org.apache.tapestry5.grid.GridDataSource} based on a Hibernate Session and a known
026 * entity class.  This implementation does support multiple {@link org.apache.tapestry5.grid.SortConstraint sort
027 * constraints}; however it assumes a direct mapping from sort constraint property to Hibernate property.
028 *
029 * This class is <em>not</em> thread-safe; it maintains internal state.
030 *
031 * Typically, an instance of this object is created fresh as needed (that is, it is not stored between requests).
032 */
033public class HibernateGridDataSource implements GridDataSource
034{
035    private final Session session;
036
037    private final Class entityType;
038
039    private int startIndex;
040
041    private List preparedResults;
042
043    public HibernateGridDataSource(Session session, Class entityType)
044    {
045        assert session != null;
046        assert entityType != null;
047        this.session = session;
048        this.entityType = entityType;
049    }
050
051    /**
052     * Returns the total number of rows for the configured entity type.
053     */
054    @Override
055    public int getAvailableRows()
056    {
057        Criteria criteria = session.createCriteria(entityType);
058
059        applyAdditionalConstraints(criteria);
060
061        criteria.setProjection(Projections.rowCount());
062
063        Number result = (Number) criteria.uniqueResult();
064
065        return result.intValue();
066    }
067
068    /**
069     * Prepares the results, performing a query (applying the sort results, and the provided start and end index). The
070     * results can later be obtained from {@link #getRowValue(int)} }.
071     *
072     * @param startIndex      index, from zero, of the first item to be retrieved
073     * @param endIndex        index, from zero, of the last item to be retrieved
074     * @param sortConstraints zero or more constraints used to set the order of the returned values
075     */
076    @Override
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    @Override
129    public Object getRowValue(int index)
130    {
131        return preparedResults.get(index - startIndex);
132    }
133
134    /**
135     * Returns the entity type, as provided via the constructor.
136     */
137    @Override
138    public Class getRowType()
139    {
140        return entityType;
141    }
142}