org.rimudb.generic.IterativeQuery.java Source code

Java tutorial

Introduction

Here is the source code for org.rimudb.generic.IterativeQuery.java

Source

/*
 * Copyright (c) 2008-2011 Simon Ritchie.
 * All rights reserved. 
 * 
 * This program 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.
 * 
 * This program 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 program.  If not, see http://www.gnu.org/licenses/>.
 */
package org.rimudb.generic;

import java.sql.*;

import org.apache.commons.logging.*;
import org.rimudb.*;
import org.rimudb.exception.*;
import org.rimudb.generic.binders.*;

/**
 * This class is used to allow the caller to iterate over the result set. It is designed for
 * handling large result sets where the entire set may be too large to be held in memory.
 * 
 * @author Simon Ritchie
 *
 */
public class IterativeQuery extends AbstractGenericBase {
    private static Log log = LogFactory.getLog(IterativeQuery.class);
    private Class<? extends DataObject>[] dataObjectClasses = null;
    private Class<? extends DataObject> dataObjectClass = null;
    private IIterativeResultSetBinder binder;

    /**
     * Create an IterativeQuery.
     * 
     * @param database Database
     * @throws RimuDBException
     */
    public IterativeQuery(Database database) throws RimuDBException {
        super(database);
    }

    /**
     * Create an IterativeQuery.
     * 
     * @param database Database
     * @param sql String
     * @throws RimuDBException
     */
    public IterativeQuery(Database database, String sql) throws RimuDBException {
        super(database, sql);
    }

    /**
     * Create an IterativeQuery.
     * 
     * @param database Database
     * @param dataObjectClasses Class<? extends DataObject>[]
     * @param sql String
     * @throws RimuDBException
     */
    public IterativeQuery(Database database, Class<? extends DataObject>[] dataObjectClasses, String sql)
            throws RimuDBException {
        super(database, sql);
        this.dataObjectClasses = dataObjectClasses;
    }

    /**
     * Create an IterativeQuery.
     * 
     * @param database Database
     * @param dataObjectClass Class<? extends DataObject>
     * @param sql String
     * @throws RimuDBException
     */
    public IterativeQuery(Database database, Class<? extends DataObject> dataObjectClass, String sql)
            throws RimuDBException {
        super(database, sql);
        this.dataObjectClass = dataObjectClass;
    }

    /**
     * Create an IterativeQuery.
     * 
     * @param database Database
     * @param binder IIterativeResultSetBinder
     * @param sql String
     * @throws RimuDBException
     */
    public IterativeQuery(Database database, IIterativeResultSetBinder binder, String sql) throws RimuDBException {
        super(database, sql);
        this.binder = binder;
    }

    /**
     * Use this method to return an Iterator that will return multiple rows each containing 
     * multiple Data Objects. If the SQL statement contains a join of two or more tables then
     * multiple Data Objects can be returned.
     * 
     * Note that in order for this to work, the select statement must return all the columns
     * required by the Data Objects.
     * 
     * @param parameters
     * @return DataObjectArrayIterator
     * @throws RimuDBException
     */
    public DataObjectArrayIterator createDataObjectArrayIterator(Object... parameters) throws RimuDBException {
        if (dataObjectClasses == null) {
            throw new IllegalArgumentException(
                    "Cannot use this method unless an array of Data Object class has been configured for the query");
        }
        binder = new IterativeDataObjectListArrayBinder(dataObjectClasses);
        binder.initialize(getDatabase());
        DataObjectArrayIterator iterator = new DataObjectArrayIterator();
        iterator.setResultSetBinder(binder);
        loadIterator(iterator, parameters);
        return iterator;
    }

    /**
     * Use this method if the SQL statement will return multiple rows each containing a DataObject.
     * 
     * Note that in order for this to work, the select statement must return all the columns
     * required by the Data Object.
     * 
     * @param parameters
     * @return DataObjectIterator
     * @throws RimuDBException
     */
    public DataObjectIterator createDataObjectIterator(Object... parameters) throws RimuDBException {
        if (dataObjectClass == null) {
            throw new IllegalArgumentException(
                    "Cannot use this method unless a Data Object class has been configured for the query");
        }
        binder = new IterativeDataObjectListBinder(dataObjectClass);
        binder.initialize(getDatabase());
        DataObjectIterator iterator = new DataObjectIterator();
        iterator.setResultSetBinder(binder);
        loadIterator(iterator, parameters);
        return iterator;
    }

    /**
     * Use this method if the SQL statement will return multiple rows each containing a selection 
     * of the available columns or scalar results. This is the most flexible form of the methods, 
     * allowing any any values that can be returned by a select statement to be returned. It does 
     * however, require that a bean class and a binder class are created for handling the selection. 
     * The bean class must implement IResultSetBean and the binder must implement 
     * IIterativeResultSetBinder.
     * 
     * @param parameters
     * @return ObjectIterator
     * @throws RimuDBException
     */
    public ObjectIterator createObjectIteratorWithBinder(Object... parameters) throws RimuDBException {
        if (getBinder() == null) {
            throw new IllegalArgumentException(
                    "Cannot use this method unless a binder has been configured for the query");
        }
        ObjectIterator iterator = new ObjectIterator();
        iterator.setResultSetBinder(binder);
        loadIterator(iterator, parameters);
        return iterator;
    }

    /**
     * Use this method if the SQL statement will return multiple rows each containing a single column.
     * 
     * @param parameters
     * @return ObjectIterator
     * @throws RimuDBException
     */
    public ObjectIterator createObjectIterator(Object... parameters) throws RimuDBException {
        binder = new IterativeSingleValueBinder();
        return createObjectIteratorWithBinder(parameters);
    }

    /**
     * Load the iterator with the SQL Statement and fetch the result set.
     * 
     * @param queryIterator AbstractQueryIterator
     * @param parameters Object[]
     * @throws RimuDBException
     */
    private void loadIterator(AbstractQueryIterator queryIterator, Object parameters[]) throws RimuDBException {
        if (getSQL() == null || getSQL().trim().length() == 0) {
            throw new RimuDBException("SQL statement has not been set");
        }
        Connection con = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        // Parse the SQL to replace table names
        String psql = parse(getSQL());

        try {
            con = getDatabase().getDatabaseConnection();
            queryIterator.setConnection(con);

            stmt = con.prepareStatement(psql);

            stmt.setFetchSize(getFetchSize());

            queryIterator.setPreparedStatement(stmt);

            if (parameters != null) {
                boolean charUsesSetObject = getDatabase().getSQLAdapter().isCharUsesSetObject();
                for (int i = 0; i < parameters.length; i++) {
                    RecordBinder.bindValue(stmt, i + 1, parameters[i], charUsesSetObject);
                }
            }

            rs = stmt.executeQuery();
            queryIterator.setResultSet(rs);

        } catch (Exception e) {

            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException sqle) {
                }
                rs = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException sqle) {
                }
                stmt = null;
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException sqle) {
                }
                con = null;
            }

            StringBuilder sb = new StringBuilder();
            sb.append("SQL statement=");
            sb.append(psql);
            // Log the parameters for the SQL statement that failed
            if (parameters != null) {
                for (int i = 0; i < parameters.length; i++) {
                    sb.append(" Parameters[" + i + "]=" + parameters[i]);
                }
            }
            sb.append(" ");
            // Include all the sql info in the exception
            throw new RimuDBException(e, sb.toString());

        }

    }

    /**
     * Return the binder.
     * 
     * @return IIterativeResultSetBinder
     */
    public IIterativeResultSetBinder getBinder() {
        return binder;
    }

    /**
     * Set the binder.
     * 
     * @param binder IIterativeResultSetBinder
     */
    public void setBinder(IIterativeResultSetBinder binder) {
        this.binder = binder;
    }

}