/*
* Databinder: a simple bridge from Wicket to Hibernate
* Copyright (C) 2006 Nathan Hamblen nathan@technically.us
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.databinder.models.hib;
import java.util.Iterator;
import net.databinder.hib.Databinder;
import net.databinder.models.PropertyDataProvider;
import org.apache.wicket.model.IModel;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
/**
* Provides query results to DataView and related components. Like the Hibernate model classes,
* the results of this provider can be altered by query binders and criteria builders. By default
* this provider wraps items in a compound property model in addition to a Hibernate model.
* This is convenient for mapping DataView subcomponents as bean properties (as with
* PropertyListView). However, <b>DataTable will not work with a compound property model.</b>
* Call setWrapWithPropertyModel(false) when using with DataTable, DataGridView, or any
* other time you do not want a compound property model.
* @author Nathan Hamblen
*/
public class HibernateProvider<T> extends PropertyDataProvider<T> {
private Class objectClass;
private OrderingCriteriaBuilder criteriaBuilder;
private QueryBuilder queryBuilder, countQueryBuilder;
private Object factoryKey;
/**
* Provides all entities of the given class.
*/
public HibernateProvider(Class objectClass) {
this.objectClass = objectClass;
}
/**
* Provides all entities of the given class using a distinct criteria builder for the order query.
* @param objectClass
* @param criteriaBuilder base criteria builder
* @param criteriaOrderer add ordering information ONLY, base criteria will be called first
*/
public HibernateProvider(Class objectClass, final CriteriaBuilder criteriaBuilder, final CriteriaBuilder criteriaOrderer) {
this(objectClass);
this.criteriaBuilder = new OrderingCriteriaBuilder() {
public void buildOrdered(Criteria criteria) {
criteriaBuilder.build(criteria);
criteriaOrderer.build(criteria);
}
public void buildUnordered(Criteria criteria) {
criteriaBuilder.build(criteria);
}
};
}
/**
* Provides all entities of the given class.
* @param objectClass
* @param criteriaBuider builds different criteria objects for iterator() and size()
*/
public HibernateProvider(Class objectClass, OrderingCriteriaBuilder criteriaBuider) {
this(objectClass);
this.criteriaBuilder = criteriaBuider;
}
/** Provides entities of the given class meeting the supplied criteria. */
public HibernateProvider(Class objectClass, final CriteriaBuilder criteriaBuilder) {
this(objectClass, new OrderingCriteriaBuilder() {
public void buildOrdered(Criteria criteria) {
criteriaBuilder.build(criteria);
}
public void buildUnordered(Criteria criteria) {
criteriaBuilder.build(criteria);
}
});
}
/**
* Provides entities matching the given query. The count query
* is derived by prefixing "select count(*)" to the given query; this will fail if
* the supplied query has a select clause.
*/
public HibernateProvider(String query) {
this(query, makeCount(query));
}
/**
* Provides entities matching the given queries.
*/
public HibernateProvider(final String query, final String countQuery) {
this(new QueryBinderBuilder(query), new QueryBinderBuilder(countQuery));
}
/**
* Provides entities matching the given query with bound parameters. The count query
* is derived by prefixing "select count(*)" to the given query; this will fail if
* the supplied query has a select clause.
* @deprecated because the derived count query is often non-standard, even if it works. Use the longer constructor.
*/
public HibernateProvider(String query, QueryBinder queryBinder) {
this(query, queryBinder, makeCount(query), queryBinder);
}
/**
* Provides entities matching the given queries with bound parameters.
* @param query query to return entities
* @param queryBinder binder for the standard query
* @param countQuery query to return count of entities
* @param countQueryBinder binder for the count query (may be same as queryBinder)
*/
public HibernateProvider(final String query, final QueryBinder queryBinder, final String countQuery, final QueryBinder countQueryBinder) {
this(new QueryBinderBuilder(query, queryBinder), new QueryBinderBuilder(countQuery, countQueryBinder));
}
public HibernateProvider(QueryBuilder queryBuilder, QueryBuilder countQueryBuilder) {
this.queryBuilder = queryBuilder;
this.countQueryBuilder = countQueryBuilder;
}
/**
* @deprecated
* @return query with select count(*) prepended
*/
static protected String makeCount(String query) {
return "select count(*) " + query;
}
/** @return session factory key, or null for the default factory */
public Object getFactoryKey() {
return factoryKey;
}
/**
* Set a factory key other than the default (null).
* @param key session factory key
* @return this, for chaining
*/
public HibernateProvider setFactoryKey(Object key) {
this.factoryKey = key;
return this;
}
/**
* It should not normally be necessary to override (or call) this default implementation.
*/
@SuppressWarnings("unchecked")
public Iterator<T> iterator(int first, int count) {
Session sess = Databinder.getHibernateSession(factoryKey);
if(queryBuilder != null) {
org.hibernate.Query q = queryBuilder.build(sess);
q.setFirstResult(first);
q.setMaxResults(count);
return q.iterate();
}
Criteria crit = sess.createCriteria(objectClass);
if (criteriaBuilder != null)
criteriaBuilder.buildOrdered(crit);
crit.setFirstResult(first);
crit.setMaxResults(count);
return crit.list().iterator();
}
/**
* Only override this method if a single count query or
* criteria projection is not possible.
*/
public int size() {
Session sess = Databinder.getHibernateSession(factoryKey);
if(countQueryBuilder != null) {
org.hibernate.Query q = countQueryBuilder.build(sess);
Object obj = q.uniqueResult();
return ((Number) obj).intValue();
}
Criteria crit = sess.createCriteria(objectClass);
if (criteriaBuilder != null)
criteriaBuilder.buildUnordered(crit);
crit.setProjection(Projections.rowCount());
Integer size = (Integer) crit.uniqueResult();
return size == null ? 0 : size;
}
@Override
protected IModel<T> dataModel(T object) {
return new HibernateObjectModel<T>(object);
}
/** does nothing */
public void detach() {
}
}