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