org.riversun.d6.core.D6Crud.java Source code

Java tutorial

Introduction

Here is the source code for org.riversun.d6.core.D6Crud.java

Source

/*  d6 Lightweight O/R mapper for java with ease of use 
 *
 *  Copyright (c) 2006- Tom Misawa, riversun.org@gmail.com
 *  
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *  
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *  
 */
package org.riversun.d6.core;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.riversun.d6.D6Model;
import org.riversun.d6.DBConnCreator;
import org.riversun.d6.DBConnInfo;
import org.riversun.d6.annotation.DBTable;

/**
 * Class with crud methods
 * 
 * @author Tom Misawa (riversun.org@gmail.com)
 *
 */
public class D6Crud {

    DBConnInfo mConnInfo;
    String mDbcpPropertyFile;

    /**
     * Constructor
     * 
     * @param connInfo
     */
    public D6Crud(DBConnInfo connInfo) {
        this.mConnInfo = connInfo;
    }

    /**
     * Constructor
     * 
     * @param dbcpPropertyFile
     *          property file name of DBCP library on classpath<br>
     */
    public D6Crud(String dbcpPropertyFile) {
        mDbcpPropertyFile = dbcpPropertyFile;
    }

    // Methods_of_DELETE///////////////////////////////////////////////////

    /**
     * Delete the appropriate line in the specified model object
     * 
     * @param modelObj
     * @return true:DB operation success false:failure
     */
    public boolean execDelete(Class<? extends D6Model> modelObj) {

        boolean retVal = false;

        final D6CrudDeleteHelper dh = new D6CrudDeleteHelper(modelObj);
        final String updateSQL = dh.createDeleteAllPreparedSQLStatement();

        log("#execDelete model=" + modelObj + " deleteSQL=" + updateSQL);

        final Connection conn = createConnection();

        try {

            PreparedStatement preparedStmt = null;

            // There is a possibility that the error occurs in one single delete
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            preparedStmt = conn.prepareStatement(updateSQL);

            // execute SQL
            preparedStmt.executeUpdate();

            // Finally, commit.
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execDelete", e);
            retVal = false;

        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execDelete", e);
            }
        }
        return retVal;

    }

    /**
     * Delete the appropriate lines in the specified model object
     * 
     * @param modelObj
     * @return true:DB operation success false:failure
     */
    public boolean execDelete(D6Model modelObj) {
        return execDelete(new D6Model[] { modelObj });
    }

    /**
     * Delete the appropriate lines in specified model objects
     * 
     * @param modelObjs
     * @return true:DB operation success false:failure
     */
    public boolean execDelete(D6Model[] modelObjs) {

        if (modelObjs == null || modelObjs.length == 0) {
            return false;
        }

        boolean retVal = false;

        final D6CrudDeleteHelper dh = new D6CrudDeleteHelper(modelObjs[0].getClass());
        final String deleteSQL = dh.createDeletePreparedSQLStatement();

        log("#execDelete modelObjs=" + modelObjs + " delete SQL=" + deleteSQL);

        final Connection conn = createConnection();

        try {

            PreparedStatement preparedStmt = null;

            // There is a possibility that the error occurs in one single delete
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            preparedStmt = conn.prepareStatement(deleteSQL);

            for (D6Model modelObj : modelObjs) {
                dh.map(modelObj, preparedStmt);

                // execute SQL
                preparedStmt.executeUpdate();
            }

            // Finally, commit.
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execDelete", e);
            retVal = false;

        } catch (D6Exception e) {

            // catch from helper
            loge("#execDelete", e);
            retVal = false;

        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execDelete", e);
            }
        }
        return retVal;

    }

    /**
     * Update Model Object
     * 
     * @param modelObj
     * @return true:DB operation success false:failure
     */
    public boolean execUpdate(D6Model modelObj) {
        final D6Inex includeExcludeColumnNames = null;
        return execUpdate(modelObj, includeExcludeColumnNames);
    }

    /**
     * Update Model Object
     * 
     * @param modelObj
     * @param includeExcludeColumnNames
     * @return true:DB operation success false:failure
     */
    public boolean execUpdate(D6Model modelObj, D6Inex includeExcludeColumnNames) {

        boolean retVal = false;

        if (modelObj == null) {
            return retVal;
        }

        final D6CrudUpdateHelper d6CrudUpdateHelper = new D6CrudUpdateHelper(modelObj.getClass());

        final String updateSQL = d6CrudUpdateHelper.createUpdatePreparedSQLStatement(includeExcludeColumnNames);

        log("#execUpdate updateSQL=" + updateSQL);

        final Connection conn = createConnection();

        try {

            PreparedStatement preparedStmt = null;

            // There is a possibility that the error occurs in one single update
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            preparedStmt = conn.prepareStatement(updateSQL);

            d6CrudUpdateHelper.map(modelObj, preparedStmt, includeExcludeColumnNames);

            // execute SQL
            preparedStmt.executeUpdate();

            // finally commit
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execUpdate", e);
            retVal = false;

        } catch (D6Exception e) {

            // catch from helper
            loge("#execUpdate", e);
            retVal = false;

        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execUpdate", e);
            }
        }
        return retVal;

    }

    /**
     * Update Model Objects
     * 
     * @param modelObj
     * @param includeExcludeColumnNames
     * @return true:DB operation success false:failure
     */
    public boolean execUpdate(D6Model[] modelObjs, D6Inex includeExcludeColumnNames) {

        boolean retVal = false;

        if (modelObjs == null || modelObjs.length == 0) {
            return retVal;
        }

        final D6CrudUpdateHelper d6CrudUpdateHelper = new D6CrudUpdateHelper(modelObjs[0].getClass());

        final String updateSQL = d6CrudUpdateHelper.createUpdatePreparedSQLStatement(includeExcludeColumnNames);

        log("#execUpdate updateSQL=" + updateSQL);

        final Connection conn = createConnection();

        try {

            PreparedStatement preparedStmt = null;

            // There is a possibility that the error occurs in one single update
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            for (D6Model modelObj : modelObjs) {
                // loop
                preparedStmt = conn.prepareStatement(updateSQL);
                d6CrudUpdateHelper.map(modelObj, preparedStmt, includeExcludeColumnNames);

                // execute SQL
                preparedStmt.executeUpdate();
            }

            // finally commit
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execUpdate", e);
            retVal = false;

        } catch (D6Exception e) {

            // catch from helper
            loge("#execUpdate", e);
            retVal = false;

        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execUpdate", e);
            }
        }
        return retVal;

    }

    /**
     * Update by raw SQL
     * 
     * @param preparedSQL
     * @param preparedValues
     * @return
     */
    public boolean execUpdateByRawSQL(String preparedSQL, Object[] preparedValues) {

        boolean retVal = false;

        final Connection conn = createConnection();

        try {

            PreparedStatement preparedStmt = null;

            // There is a possibility that the error occurs in one single update
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            preparedStmt = conn.prepareStatement(preparedSQL);

            final StringBuilder logSb = new StringBuilder();

            if (preparedValues != null) {
                logSb.append("/ ");
                for (int i = 0; i < preparedValues.length; i++) {

                    setObject((i + 1), preparedStmt, preparedValues[i]);

                    logSb.append("key(" + (i + 1) + ")=" + preparedValues[i]);
                    logSb.append(" ");
                }
            }

            log("#execUpdateWithRawSQL SQL=" + preparedSQL + " " + logSb.toString());

            // execute SQL
            preparedStmt.executeUpdate();

            // finally commit
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execUpdate", e);
            retVal = false;

        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execUpdate", e);
            }
        }
        return retVal;

    }

    /**
     * Execute raw SQL for update
     * 
     * @param modelObj
     * @param includeExcludeColumnNames
     * @return true:DB operation success false:failure
     */
    public boolean execUpdateByRawSQL(String updateRawSQL) {

        boolean retVal = false;

        log("#execUpdateByRawSQL updateRawSQL=" + updateRawSQL);

        final Connection conn = createConnection();

        try {

            Statement stmt = null;

            // There is a possibility that the error occurs in one single update
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            stmt = conn.createStatement();
            stmt.executeUpdate(updateRawSQL);

            // finally,commit
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execUpdateByRawSQL", e);
            retVal = false;

        } finally {

            try {
                conn.close();
            } catch (SQLException e) {
                retVal = false;
                loge("#execUpdateByRawSQL", e);
            }
        }
        return retVal;

    }

    /**
     * Insert the specified model object into the DB
     * 
     * @param modelObjects
     * @return true:DB operation success false:failure
     */
    public boolean execInsert(D6Model[] modelObjects) {
        final D6Inex includeExcludeColumnNames = null;
        return execInsert(modelObjects, includeExcludeColumnNames, false);
    }

    /**
     * Insert the specified model object into the DB ignoring duplicated entry
     * 
     * @param modelObjects
     * @return true:DB operation success false:failure
     */
    public boolean execInsertIgnoreDuplicate(D6Model[] modelObjects) {
        final D6Inex includeExcludeColumnNames = null;
        return execInsert(modelObjects, includeExcludeColumnNames, true);
    }

    /**
     * Insert the specified model object into the DB
     * 
     * @param modelObjects
     * @param includeExcludeColumnNames
     *          You can select either 'the column name you want to reflected
     *          in the database' AND 'the column name you don't want to
     *          reflect in the database'. When omitted (null specified)
     *          ,reflects all properties in the model class has to be
     *          reflected to the database.
     * 
     * @return true:DB operation success false:failure
     */
    public boolean execInsert(D6Model[] modelObjects, D6Inex includeExcludeColumnNames) {
        boolean ignoreDuplicate = false;
        return execInsert(modelObjects, includeExcludeColumnNames, ignoreDuplicate);
    }

    /**
     * Insert the specified model object into the DB
     * 
     * @param modelObjects
     * @param includeExcludeColumnNames
     *          You can select either 'the column name you want to reflected
     *          in the database' AND 'the column name you don't want to
     *          reflect in the database'. When omitted (null specified)
     *          ,reflects all properties in the model class has to be
     *          reflected to the database.
     * @param ignoreDuplicate
     *          if ignore duplicated entry
     * @return true:DB operation success false:failure
     */
    public boolean execInsert(D6Model[] modelObjects, D6Inex includeExcludeColumnNames, boolean ignoreDuplicate) {
        log("#execInsert");
        boolean retVal = false;

        if (modelObjects == null) {
            return retVal;
        }

        final int numOfModelObjects = modelObjects.length;

        if (numOfModelObjects == 0) {
            return retVal;
        }

        final D6Model firstModelObject = modelObjects[0];

        final D6CrudInsertHelper d6CrudInsertHelper = new D6CrudInsertHelper(firstModelObject.getClass());

        final String insertSQL = d6CrudInsertHelper.createInsertPreparedSQLStatement(includeExcludeColumnNames,
                ignoreDuplicate);

        Connection conn = null;

        try {

            PreparedStatement preparedStmt = null;

            conn = createConnection();

            // There is a possibility that the error occurs in one single insert
            // statement.
            // Therefore, turn the auto commit off.
            conn.setAutoCommit(false);

            preparedStmt = conn.prepareStatement(insertSQL);

            for (int i = 0; i < modelObjects.length; i++) {

                D6Model model = modelObjects[i];

                d6CrudInsertHelper.map(model, preparedStmt, includeExcludeColumnNames);

                // execute SQL
                preparedStmt.executeUpdate();

            }

            // finally commit
            conn.commit();

            retVal = true;

        } catch (SQLException e) {

            loge("#execInsert", e);
            retVal = false;

        } catch (D6Exception e) {

            // catch from helper
            loge("#execInsert", e);
            retVal = false;
        } finally {
            if (conn != null) {
                try {

                    conn.close();
                } catch (SQLException e) {
                    loge("#execInsert", e);
                    retVal = false;
                }
            }
        }
        return retVal;

    }

    // Methods_of_SELECT///////////////////////////////////////////////////
    /**
     * Returns the total number of the lines of rows corresponding to the
     * specified model class
     * 
     * @param modelClazz
     * @return true:DB operation success false:failure
     */
    public int execSelectCount(Class<? extends D6Model> modelClazz) {

        final D6CrudSelectHelper d6CrudSelectHelper = new D6CrudSelectHelper(modelClazz);
        final String sqlForSelectCount = d6CrudSelectHelper.getSQLForSelectCount();

        return execSelectCount(sqlForSelectCount);
    }

    /**
     * Returns the total number of the lines of rows corresponding to the
     * specified model class
     * 
     * @param modelClazz
     * @param whereCondition
     * @return
     */
    public int execSelectCount(Class<? extends D6Model> modelClazz, WhereCondition whereCondition) {

        final D6CrudSelectHelper d6CrudSelectHelper = new D6CrudSelectHelper(modelClazz);
        final String sqlForSelectCount = d6CrudSelectHelper.getSQLForSelectCount();

        String sql = sqlForSelectCount + " " + whereCondition.toSql();

        return execSelectCount(sql);
    }

    /**
     * Returns the total number of the lines of rows corresponding to the
     * specified model class
     * 
     * @param modelClazz
     * @param whereCondition
     * @return
     */
    public int execSelectCount(Class<? extends D6Model> modelClazz, WhereCondition whereCondition,
            Object[] searchKeys) {

        final D6CrudSelectHelper d6CrudSelectHelper = new D6CrudSelectHelper(modelClazz);
        final String sqlForSelectCount = d6CrudSelectHelper.getSQLForSelectCount();

        String sql = sqlForSelectCount + " " + whereCondition.toSql();

        return execSelectCount(sql, searchKeys);
    }

    /**
     * Execute the SQL for number search<br>
     * ex.SELECT COUNT(*) FROM table;
     * 
     * @param preparedSql
     * @param searchKeys
     * @return number of result
     */
    public int execSelectCount(String preparedSql) {
        return execSelectCount(preparedSql, null);
    }

    /**
     * Execute the SQL for number search<br>
     * 
     * @param preparedSql
     * @param searchKeys
     * @return number of result
     */
    public int execSelectCount(String preparedSql, Object[] searchKeys) {
        log("#execSelectCount preparedSql=" + preparedSql + " searchKeys=" + searchKeys);
        int retVal = 0;

        PreparedStatement preparedStmt = null;
        ResultSet rs = null;

        final Connection conn = createConnection();

        try {

            preparedStmt = conn.prepareStatement(preparedSql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);

            final StringBuilder logSb = new StringBuilder();

            if (searchKeys != null) {
                logSb.append("/ ");
                for (int i = 0; i < searchKeys.length; i++) {

                    setObject((i + 1), preparedStmt, searchKeys[i]);

                    logSb.append("key(" + (i + 1) + ")=" + searchKeys[i]);
                    logSb.append(" ");
                }
            }

            log("#execSelectCount SQL=" + preparedSql + " " + logSb.toString());

            // execute SQL
            rs = preparedStmt.executeQuery();

            while (rs.next()) {
                retVal = rs.getInt(1);
            }

        } catch (Exception e) {
            loge("#execSelectCount", e);

        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (preparedStmt != null) {
                    preparedStmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {

                loge("#execSelectCount", e);
            }
        }
        return retVal;

    }

    /**
     * Execute select statement and returns the all lines of rows corresponding
     * to the specified model class as array of Objects
     * 
     * @param modelClazz
     * @return
     */
    public <T extends D6Model> T[] execSelectTable(Class<T> modelClazz) {

        final DBTable dbTable = modelClazz.getAnnotation(DBTable.class);
        final String dbTableName = dbTable.tableName();
        return (T[]) execSelectTable("SELECT * FROM " + dbTableName, modelClazz);
    }

    public Object[] execSelectTable(Class<? extends D6Model> modelClazz, WhereCondition whereCondition) {
        return execSelectTable(modelClazz, whereCondition, null);
    }

    public Object[] execSelectTable(Class<? extends D6Model> modelClazz, WhereCondition whereCondition,
            Object[] searchKeys) {

        final DBTable dbTable = modelClazz.getAnnotation(DBTable.class);
        final String dbTableName = dbTable.tableName();

        final String preparedSql = "SELECT * FROM " + dbTableName + " " + whereCondition.toSql();

        final Map<Class<?>, List<Object>> result = execSelectTableWithJoin(preparedSql, searchKeys, modelClazz);

        final List<Object> rowList = result.get(modelClazz);

        return toArray(rowList, modelClazz);
    }

    /**
     * Execute select statement for the single table.
     * 
     * @param preparedSql
     * @param modelClazz
     * @return
     */
    public <T extends D6Model> T[] execSelectTable(String preparedSql, Class<T> modelClazz) {
        return execSelectTable(preparedSql, null, modelClazz);
    }

    /**
     * Execute select statement for the single table. <br>
     * <br>
     * -About SQL<br>
     * You can use prepared SQL.<br>
     * <br>
     * In addition,you can also use non-wildcard ('?') SQL (=raw SQL).In this
     * case searchKeys must be null or empty array(size 0 array).<br>
     * When you use a wildcard('?'), you must not include the "'"(=>single
     * quotes) to preparedSQL.<br>
     * 
     * <br>
     * -About processing<br>
     * Used when you execute the SQL that is JOIN multiple tables.<br>
     * 
     * In this method, you can specify more than one model class.<br>
     * 
     * When the column name specified in the annotation of the model classes is
     * included in the resultSet,<br>
     * a value corresponding to the column name is set to the corresponding
     * field of model objects.<br>
     * 
     * In other words, if multiple model class has the same column name, values
     * in the resultSet is set in the same manner for each mode class.<br>
     * 
     * <br>
     * 
     * @param preparedSql
     * @param searchKeys
     * @param modelClazz
     * @return
     */
    public <T extends D6Model> T[] execSelectTable(String preparedSql, Object[] searchKeys, Class<T> modelClazz) {

        @SuppressWarnings("unchecked")
        final Map<Class<?>, List<Object>> result = execSelectTableWithJoin(preparedSql, searchKeys, modelClazz);

        final List<Object> rowList = result.get(modelClazz);

        return toArray(rowList, modelClazz);
    }

    /**
     * 
     * Execute select statement for the joined multiple table.<br>
     * 
     * {@see #execSelectTableWithJoin(String, String[], Class...)}<br>
     * 
     * @param preparedSql
     * @param modelClazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public Map<Class<?>, List<Object>> execSelectTableWithJoin(String preparedSql,
            Class<? extends D6Model>... modelClazz) {
        return execSelectTableWithJoin(preparedSql, null, modelClazz);
    }

    /**
     * Execute select statement for the joined multiple table.<br>
     * <br>
     * <br>
     * -About SQL<br>
     * You can use prepared SQL.<br>
     * <br>
     * In addition,you can also use non-wildcard ('?') SQL (=raw SQL).In this
     * case searchKeys must be null or empty array(size 0 array).<br>
     * When you use a wildcard('?'), you must not include the "'"(=>single
     * quotes) to preparedSQL.<br>
     * 
     * <br>
     * -About processing<br>
     * Used when you execute the SQL that is JOIN multiple tables.<br>
     * 
     * In this method, you can specify more than one model class.<br>
     * 
     * When the column name specified in the annotation of the model classes is
     * included in the resultSet,<br>
     * a value corresponding to the column name is set to the corresponding
     * field of model objects.<br>
     * 
     * In other words, if multiple model class has the same column name, values
     * in the resultSet is set in the same manner for each mode class.<br>
     * 
     * 
     * @param preparedSql
     * @param searchKeys
     *          If the prepared SQL includes a wild card (?), Here is list of
     *          the string to be substituted for wild card.
     * 
     *          The order of value to be included in the array must be the
     *          same as order of appearance of the wild card.
     * 
     * @param modelClazz
     *          More than one model class in a comma-separated manner for
     *          mapping the results
     * 
     * @return SQL execution result is returned as MAP. <br>
     *         MAP,key is the model class, value is of instance of the model
     *         class specified as key.
     * 
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public Map<Class<?>, List<Object>> execSelectTableWithJoin(String preparedSql, Object[] searchKeys,
            Class<? extends D6Model>... modelClazz) {
        log("#execSelectTableWithJoin preparedSql=" + preparedSql + " searchKeys=" + searchKeys + " modelClazz="
                + modelClazz);
        final Map<Class<?>, List<Object>> resultMap = new HashMap<Class<?>, List<Object>>();

        final List<ModelWrapper> modelList = new ArrayList<ModelWrapper>();

        for (int i = 0; i < modelClazz.length; i++) {

            @SuppressWarnings("unchecked")
            final ModelWrapper model = new ModelWrapper(modelClazz[i]);
            modelList.add(model);
        }

        PreparedStatement preparedStmt = null;
        ResultSet rs = null;

        final Connection conn = createConnection();

        try {

            preparedStmt = conn.prepareStatement(preparedSql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);

            final StringBuilder logSb = new StringBuilder();
            if (searchKeys != null) {
                logSb.append("/ ");
                for (int i = 0; i < searchKeys.length; i++) {
                    //
                    Object object = searchKeys[i];

                    setObject((i + 1), preparedStmt, object);

                    logSb.append("key(" + (i + 1) + ")=" + searchKeys[i]);
                    logSb.append(" ");
                }
            }

            log("#execSelectTableWithJoin SQL=" + preparedSql + " " + logSb.toString());

            // execute SQL
            rs = preparedStmt.executeQuery();

            final ResultSetMetaData rsMetaData = rs.getMetaData();
            final int numberOfColumns = rsMetaData.getColumnCount();
            final List<String> columnNameList = new ArrayList<String>();

            // cache column names of this result set
            for (int i = 0; i < numberOfColumns; i++) {
                String columnName = rsMetaData.getColumnName(i + 1);
                columnNameList.add(columnName);
            }

            while (rs.next()) {

                // Processing of a single resultset[begin]=============

                for (int i = 0; i < numberOfColumns; i++) {

                    // Get from the current resultSet
                    final String columnName = columnNameList.get(i);

                    final Object value = rs.getObject(i + 1);

                    // Set the values to all the properties of model class (You
                    // know property is corresponding to each column of the DB)
                    // via modelWrapper
                    for (ModelWrapper model : modelList) {
                        // set value to model wrapper
                        model.setValue(columnName, value);
                    }
                }

                // Processing of a single resultset[end]=============

                for (ModelWrapper model : modelList) {

                    final Class<?> modelClazzName = model.getClazz();

                    List<Object> modelObjectList = resultMap.get(modelClazzName);

                    // Generate the result list corresponding to a certain model
                    // class if the list have not been generated.
                    if (modelObjectList == null) {
                        modelObjectList = new ArrayList<Object>();
                        resultMap.put(modelClazzName, modelObjectList);
                    }

                    // Generates a model object having a property value held in
                    // the model wrapper, and stores the model object in the
                    // modelObjectList
                    final Object resultModelObject = model.getAsObject();
                    modelObjectList.add(resultModelObject);

                    model.initializeFieldMap();
                }

            }

        } catch (Exception e) {
            loge("#execSelectTableWithJoin General ", e);

        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (preparedStmt != null) {
                    preparedStmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                loge("#execSelectTableWithJoin SQLException ", e);
            }
        }

        return resultMap;

    }

    /**
     * Set object to the preparedStatement
     * 
     * @param parameterIndex
     * @param preparedStmt
     * @param value
     * @throws SQLException
     */
    private void setObject(int parameterIndex, PreparedStatement preparedStmt, Object value) throws SQLException {

        preparedStmt.setObject(parameterIndex, value);
    }

    /**
     * returns Object array from Object List
     * 
     * @param objectList
     * @param modelClazz
     * @return
     */
    private <T extends D6Model> T[] toArray(List<Object> objectList, Class<T> modelClazz) {

        if (objectList == null) {
            return (T[]) Array.newInstance(modelClazz, 0);
        }

        final T[] resultObjects = objectList.toArray((T[]) Array.newInstance(modelClazz, 0));

        return resultObjects;
    }

    /**
     * convert result into ModelObject from the result of execSelectWithJoin
     * 
     * @param o
     * @param modelClazz
     * @return
     */
    public Object[] getAsModel(Map<Class<?>, List<Object>> o, Class<? extends D6Model> modelClazz) {

        return toArray(o.get(modelClazz), modelClazz);
    }

    /**
     * Get the DB connection
     * 
     * @return
     */
    private Connection createConnection() {

        if (mConnInfo != null) {
            DBConnCreator dbConnCreator = new DBConnCreator(mConnInfo);
            Connection conn = dbConnCreator.createDBConnection();
            return conn;
        } else if (mDbcpPropertyFile != null) {
            Properties properties = new Properties();
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(mDbcpPropertyFile);
            try {
                properties.load(is);
                DataSource ds;
                ds = BasicDataSourceFactory.createDataSource(properties);
                Connection conn = ds.getConnection();
                return conn;
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return null;

    }

    /**
     * Get raw crud for raw SQL handling
     * 
     * @return
     */
    public RawCrud getRawCrud() {
        return new RawCrud();
    }

    /**
     * 
     * Class of Raw Crud
     *
     */
    public final class RawCrud {

        public Connection createConnection() {
            return D6Crud.this.createConnection();
        }

        public void setObject(int parameterIndex, PreparedStatement preparedStmt, Object value)
                throws SQLException {
            D6Crud.this.setObject(parameterIndex, preparedStmt, value);
        }
    }

    void log(String msg) {
        D6Logger.log(this.getClass(), msg);
    }

    void loge(String msg, Exception... e) {

        D6Logger.loge(this.getClass(), msg, e);
    }
}