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 }