package org.tynamo.hibernate; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.tapestry5.grid.GridDataSource; import org.apache.tapestry5.grid.SortConstraint; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hibernate.search.FullTextQuery; import org.tynamo.descriptor.TynamoPropertyDescriptor; import org.tynamo.search.SearchFilterPredicate; public class SearchableHibernateGridDataSource implements GridDataSource { private FullTextQuery fullTextQuery; private Map<TynamoPropertyDescriptor, SearchFilterPredicate> propertySearchFilterMap; private Session session; private Class entityType; private int startIndex; private List preparedResults; public SearchableHibernateGridDataSource(Session session, Class entityType, Map<TynamoPropertyDescriptor, SearchFilterPredicate> propertySearchFilterMap) { this(session, entityType, null, propertySearchFilterMap); } public SearchableHibernateGridDataSource(Session session, Class entityType, FullTextQuery fullTextQuery, Map<TynamoPropertyDescriptor, SearchFilterPredicate> propertySearchFilterMap) { this.session= session; this.entityType = entityType; this.fullTextQuery = fullTextQuery; this.propertySearchFilterMap = propertySearchFilterMap; } /** * Returns the total number of rows for the configured entity type. */ public int getAvailableRows() { Criteria criteria = session.createCriteria(entityType); applyAdditionalConstraints(criteria); if (fullTextQuery == null) { criteria.setProjection(Projections.rowCount()); Number result = (Number) criteria.uniqueResult(); return result.intValue(); } fullTextQuery.setCriteriaQuery(criteria); // calling getResultSize() causes HSEARCH000105: Cannot safely compute getResultSize() when a Criteria with restriction is used // return fullTextQuery.getResultSize();T return fullTextQuery.list().size(); } /** * Prepares the results, performing a query (applying the sort results, and the provided start and end index). The * results can later be obtained from {@link #getRowValue(int)} }. * * @param startIndex index, from zero, of the first item to be retrieved * @param endIndex index, from zero, of the last item to be retrieved * @param sortConstraints zero or more constraints used to set the order of the returned values */ public void prepare(int startIndex, int endIndex, List<SortConstraint> sortConstraints) { assert sortConstraints != null; Criteria crit = session.createCriteria(entityType); crit.setFirstResult(startIndex).setMaxResults(endIndex - startIndex + 1); for (SortConstraint constraint : sortConstraints) { String propertyName = constraint.getPropertyModel().getPropertyName(); switch (constraint.getColumnSort()) { case ASCENDING: crit.addOrder(Order.asc(propertyName)); break; case DESCENDING: crit.addOrder(Order.desc(propertyName)); break; default: } } applyAdditionalConstraints(crit); this.startIndex = startIndex; if (fullTextQuery == null) { preparedResults = crit.list(); return; } fullTextQuery.setCriteriaQuery(crit); preparedResults = fullTextQuery.list(); } /** * Invoked after the main criteria has been set up (firstResult, maxResults and any sort contraints). This gives * subclasses a chance to apply additional constraints before the list of results is obtained from the criteria. * This implementation does nothing and may be overridden. */ protected void applyAdditionalConstraints(Criteria crit) { if (propertySearchFilterMap == null || propertySearchFilterMap.size() <= 0) return; for (Entry<TynamoPropertyDescriptor, SearchFilterPredicate> entry : propertySearchFilterMap.entrySet()) crit.add(createCriterion(entry.getKey().getName(), entry.getValue())); } private Criterion createCriterion(String propertyName, SearchFilterPredicate predicate) { switch (predicate.getOperator()) { case eq: return Restrictions.eq(propertyName, predicate.getLowValue()); case ne: return Restrictions.ne(propertyName, predicate.getLowValue()); case gt: return Restrictions.gt(propertyName, predicate.getLowValue()); case ge: return Restrictions.ge(propertyName, predicate.getLowValue()); case lt: return Restrictions.lt(propertyName, predicate.getLowValue()); case le: return Restrictions.le(propertyName, predicate.getLowValue()); default: throw new IllegalArgumentException("Search filtering for operator '" + predicate.getOperator() + "' is not yet supported"); } } /** * Returns a row value at the given index (which must be within the range defined by the call to {@link * #prepare(int, int, java.util.List)} ). * * @param index of object * @return object at that index */ public Object getRowValue(int index) { return preparedResults.get(index - startIndex); } /** * Returns the entity type, as provided via the constructor. */ public Class getRowType() { return entityType; } }