/* * Copyright 2010, Andrew M Gibson * * www.andygibson.net * * This file is part of DataValve. * * DataValve 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 3 of the License, or * (at your option) any later version. * * DataValve 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 DataValve. If not, see <http://www.gnu.org/licenses/>. * */ package org.fluttercode.datavalve.provider; import java.util.List; import org.fluttercode.datavalve.Paginator; import org.fluttercode.datavalve.provider.util.DataQuery; /** * Base class for any data provider that is driven by a Query Language. This * class implements the fundamentals of generating a {@link DataQuery} object * that can then be used to query data in the different query language providers * (Hql, Ejbql, Sql etc). * <p> * By using an internal query to hold the statement and the parameters, we can * utilize that in different ways in different sub classes for different data * access mechanisms * * @author Andy Gibson * */ public abstract class AbstractQLDataProvider<T> extends AbstractParameterizedDataProvider<T> { private static final long serialVersionUID = 1L; private String selectStatement; private String countStatement; public String getSelectStatement() { return selectStatement; } public void setSelectStatement(String selectStatement) { this.selectStatement = selectStatement; } public String getCountStatement() { return countStatement; } public void setCountStatement(String countStatement) { this.countStatement = countStatement; } @Override protected Integer doFetchResultCount() { DataQuery query = buildDataQuery(getCountStatement(), false, null); return queryForCount(query); } @Override protected List<T> doFetchResults(Paginator paginator) { // fetch the results by building the data query and handing it off to a // query execution method. DataQuery query = buildDataQuery(getSelectStatement(), true, paginator); Integer count = paginator.includeAllResults() ? null : paginator .getMaxRows() + 1; List<T> temp = queryForResults(query, paginator.getFirstResult(), count); // if we returned more than maxRows, then we have more data to fetch boolean nextAvailable = (!paginator.includeAllResults()) && temp.size() > paginator.getMaxRows(); paginator.setNextAvailable(nextAvailable); if (paginator.includeAllResults() || temp.size() < paginator.getMaxRows()) { return temp; } // create a sublist containing maxRows number of rows. return temp.subList(0, paginator.getMaxRows()); } /** * Go fetch the results from the database using the defined query and first * result and result size information. * <p/> * Override in subclasses to provide different implementations for fetching * the results * * @param query * The {@link DataQuery} instance containing the statement and * parameters * @param firstResult * indicates the first row that is to be returned or null if we * are fetching from the first row. * @param count * the number of rows to return or null if we are to return them * all. * @return List of data */ protected abstract List<T> queryForResults(DataQuery query, Integer firstResult, Integer count); /** * Query for the actual result count value using the information defined in * the {@link DataQuery} reference passed in. In most cases, the statement * needs executing and the count value retrieved from the query. * <p/> * Override in subclasses to provide different implementations for fetching * the count * * @param query * @return */ protected abstract Integer queryForCount(DataQuery query); /** * Builds the {@link DataQuery} object from the base query statement and the * provider information. Pass the {@link Paginator} for order information as * well as a flag indicating whether ordering is included. We don't want * ordering on count statements so make sure it is false for those. * <p> * This method is all about taking the provider statements and restrictions * and assembling the final query including parameterizing the restrictions * and adding the order by clause if needed. * <p/> * Override in subclasses to provide different implementations for * generating the query, althought a default implementation is provided in * the {@link AbstractQueryDataProvider} which most Query Language based * providers should subclass. * <p/> * In most final subclasses for JPA, SQL, Hibernate etc, you should just * need to implement the <code>queryForCount</code> and * <code>queryForResults</code> methods since these are specific to the * actual data connectivity mechanism whereas more general code has been * pulled up into parent classes to be inherited. * * @param baseStatement * Initial statement to use for selecting data * @param includeOrdering * indicates whether the order clause should be added to the * final statement * @param paginator * Paginator for determining the order clause. * @return {@link DataQuery} reference that contains the final QL and * parameters for obtaining the data. */ protected abstract DataQuery buildDataQuery(String baseStatement, boolean includeOrdering, Paginator paginator); }