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}