Java tutorial
package org.apache.ddlutils.platform; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import org.apache.commons.beanutils.BasicDynaBean; import org.apache.commons.beanutils.BasicDynaClass; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.DynaClass; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.collections.map.ListOrderedMap; import org.apache.ddlutils.DatabaseOperationException; import org.apache.ddlutils.dynabean.SqlDynaBean; import org.apache.ddlutils.dynabean.SqlDynaClass; import org.apache.ddlutils.model.Column; import org.apache.ddlutils.model.Database; import org.apache.ddlutils.model.Table; /** * This is an iterator that is specifically targeted at traversing result sets. * If the query is against a known table, then {@link org.apache.ddlutils.dynabean.SqlDynaBean} instances * are created from the rows, otherwise normal {@link org.apache.commons.beanutils.DynaBean} instances * are created. * * @version $Revision: 289996 $ */ public class ModelBasedResultSetIterator implements Iterator { /** The platform. */ private PlatformImplBase _platform; /** The base result set. */ private ResultSet _resultSet; /** The dyna class to use for creating beans. */ private DynaClass _dynaClass; /** Whether the case of identifiers matters. */ private boolean _caseSensitive; /** Maps column names to table objects as given by the query hints. */ private Map _preparedQueryHints; /** Maps column names to properties. */ private Map _columnsToProperties = new ListOrderedMap(); /** Whether the next call to hasNext or next needs advancement. */ private boolean _needsAdvancing = true; /** Whether we're already at the end of the result set. */ private boolean _isAtEnd = false; /** Whether to close the statement and connection after finishing. */ private boolean _cleanUpAfterFinish; /** * Creates a new iterator. * * @param platform The platform * @param model The database model * @param resultSet The result set * @param queryHints The tables that were queried in the query that produced the given result set * (optional) * @param cleanUpAfterFinish Whether to close the statement and connection after finishing * the iteration, upon on exception, or when this iterator is garbage collected */ public ModelBasedResultSetIterator(PlatformImplBase platform, Database model, ResultSet resultSet, Table[] queryHints, boolean cleanUpAfterFinish) throws DatabaseOperationException { if (resultSet != null) { _platform = platform; _resultSet = resultSet; _cleanUpAfterFinish = cleanUpAfterFinish; _caseSensitive = _platform.isDelimitedIdentifierModeOn(); _preparedQueryHints = prepareQueryHints(queryHints); try { initFromMetaData(model); } catch (SQLException ex) { cleanUp(); throw new DatabaseOperationException("Could not read the metadata of the result set", ex); } } else { _isAtEnd = true; } } /** * Initializes this iterator from the resultset metadata. * * @param model The database model */ private void initFromMetaData(Database model) throws SQLException { ResultSetMetaData metaData = _resultSet.getMetaData(); String tableName = null; boolean singleKnownTable = true; for (int idx = 1; idx <= metaData.getColumnCount(); idx++) { String columnName = metaData.getColumnName(idx); String tableOfColumn = metaData.getTableName(idx); Table table = null; if ((tableOfColumn != null) && (tableOfColumn.length() > 0)) { // jConnect might return a table name enclosed in quotes if (tableOfColumn.startsWith("\"") && tableOfColumn.endsWith("\"") && (tableOfColumn.length() > 1)) { tableOfColumn = tableOfColumn.substring(1, tableOfColumn.length() - 1); } // the JDBC driver gave us enough meta data info table = model.findTable(tableOfColumn, _caseSensitive); } if (table == null) { // not enough info in the meta data of the result set, lets try the // user-supplied query hints table = (Table) _preparedQueryHints.get(_caseSensitive ? columnName : columnName.toLowerCase()); tableOfColumn = (table == null ? null : table.getName()); } if (tableName == null) { tableName = tableOfColumn; } else if (!tableName.equals(tableOfColumn)) { singleKnownTable = false; } String propName = columnName; if (table != null) { Column column = table.findColumn(columnName, _caseSensitive); if (column != null) { propName = column.getName(); } } _columnsToProperties.put(columnName, propName); } if (singleKnownTable && (tableName != null)) { _dynaClass = model.getDynaClassFor(tableName); } else { DynaProperty[] props = new DynaProperty[_columnsToProperties.size()]; int idx = 0; for (Iterator it = _columnsToProperties.values().iterator(); it.hasNext(); idx++) { props[idx] = new DynaProperty((String) it.next()); } _dynaClass = new BasicDynaClass("result", BasicDynaBean.class, props); } } /** * Prepares the query hints by extracting the column names and using them as keys * into the resulting map pointing to the corresponding table. * * @param queryHints The query hints * @return The column name -> table map */ private Map prepareQueryHints(Table[] queryHints) { Map result = new HashMap(); for (int tableIdx = 0; (queryHints != null) && (tableIdx < queryHints.length); tableIdx++) { for (int columnIdx = 0; columnIdx < queryHints[tableIdx].getColumnCount(); columnIdx++) { String columnName = queryHints[tableIdx].getColumn(columnIdx).getName(); if (!_caseSensitive) { columnName = columnName.toLowerCase(); } if (!result.containsKey(columnName)) { result.put(columnName, queryHints[tableIdx]); } } } return result; } /** * {@inheritDoc} */ public boolean hasNext() throws DatabaseOperationException { advanceIfNecessary(); return !_isAtEnd; } /** * {@inheritDoc} */ public Object next() throws DatabaseOperationException { advanceIfNecessary(); if (_isAtEnd) { throw new NoSuchElementException("No more elements in the resultset"); } else { try { DynaBean bean = _dynaClass.newInstance(); Table table = null; if (bean instanceof SqlDynaBean) { SqlDynaClass dynaClass = (SqlDynaClass) ((SqlDynaBean) bean).getDynaClass(); table = dynaClass.getTable(); } for (Iterator it = _columnsToProperties.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String columnName = (String) entry.getKey(); String propName = (String) entry.getValue(); Table curTable = table; if (curTable == null) { curTable = (Table) _preparedQueryHints .get(_caseSensitive ? columnName : columnName.toLowerCase()); } Object value = _platform.getObjectFromResultSet(_resultSet, columnName, curTable); bean.set(propName, value); } _needsAdvancing = true; return bean; } catch (Exception ex) { cleanUp(); throw new DatabaseOperationException("Exception while reading the row from the resultset", ex); } } } /** * Advances the iterator without materializing the object. This is the same effect as calling * {@link #next()} except that no object is created and nothing is read from the result set. */ public void advance() { advanceIfNecessary(); if (_isAtEnd) { throw new NoSuchElementException("No more elements in the resultset"); } else { _needsAdvancing = true; } } /** * Advances the result set if necessary. */ private void advanceIfNecessary() throws DatabaseOperationException { if (_needsAdvancing && !_isAtEnd) { try { _isAtEnd = !_resultSet.next(); _needsAdvancing = false; } catch (SQLException ex) { cleanUp(); throw new DatabaseOperationException("Could not retrieve next row from result set", ex); } if (_isAtEnd) { cleanUp(); } } } /** * {@inheritDoc} */ public void remove() throws DatabaseOperationException { try { _resultSet.deleteRow(); } catch (SQLException ex) { cleanUp(); throw new DatabaseOperationException("Failed to delete current row", ex); } } /** * Closes the resources (connection, statement, resultset). */ public void cleanUp() { if (_cleanUpAfterFinish && (_resultSet != null)) { Connection conn = null; try { Statement stmt = _resultSet.getStatement(); conn = stmt.getConnection(); // also closes the resultset _platform.closeStatement(stmt); } catch (SQLException ex) { // we ignore it } _platform.returnConnection(conn); _resultSet = null; } } /** * {@inheritDoc} */ protected void finalize() throws Throwable { cleanUp(); } /** * Determines whether the connection is still open. * * @return <code>true</code> if the connection is still open */ public boolean isConnectionOpen() { if (_resultSet == null) { return false; } try { Statement stmt = _resultSet.getStatement(); Connection conn = stmt.getConnection(); return !conn.isClosed(); } catch (SQLException ex) { return false; } } }