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    }