org.dbunit.dataset.AbstractTableMetaData Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xmlc-wml Show documentation
Show all versions of xmlc-wml Show documentation
old 2002 version of xmlc-xmlc-wml
The newest version!
/*
*
* The DbUnit Database Testing Framework
* Copyright (C)2002-2004, DbUnit.org
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package org.dbunit.dataset;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dbunit.DatabaseUnitRuntimeException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.datatype.IDbProductRelatable;
import org.dbunit.dataset.filter.IColumnFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Manuel Laflamme
* @author Last changed by: $Author$
* @version $Revision$ $Date$
* @since 1.0 (Mar 8, 2002)
*/
public abstract class AbstractTableMetaData implements ITableMetaData
{
private Map _columnsToIndexes;
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(AbstractTableMetaData.class);
/**
* Default constructor
*/
public AbstractTableMetaData()
{
}
/**
* @param columns
* @param keyNames
* @return The primary key columns
* @deprecated since 2.3.0 - use {@link Columns#getColumns(String[], Column[])}
*/
protected static Column[] getPrimaryKeys(Column[] columns, String[] keyNames)
{
logger.debug("getPrimaryKeys(columns={}, keyNames={}) - start", columns, keyNames);
return Columns.getColumns(keyNames, columns);
}
/**
* @param tableName
* @param columns
* @param columnFilter
* @return The filtered primary key columns
* @deprecated since 2.3.0 - use {@link Columns#getColumns(String[], Column[])}
*/
protected static Column[] getPrimaryKeys(String tableName, Column[] columns,
IColumnFilter columnFilter)
{
if (logger.isDebugEnabled())
{
logger.debug("getPrimaryKeys(tableName={}, columns={}, columnFilter={}) - start",
new Object[]{ tableName, columns, columnFilter });
}
return Columns.getColumns(tableName, columns, columnFilter);
}
/**
* Provides the index of the column with the given name within this table.
* Uses method {@link ITableMetaData#getColumns()} to retrieve all available columns.
* @throws DataSetException
* @see org.dbunit.dataset.ITableMetaData#getColumnIndex(java.lang.String)
*/
public int getColumnIndex(String columnName) throws DataSetException
{
logger.debug("getColumnIndex(columnName={}) - start", columnName);
if(this._columnsToIndexes == null)
{
// lazily create the map
this._columnsToIndexes = createColumnIndexesMap(this.getColumns());
}
String columnNameUpperCase = columnName.toUpperCase();
Integer colIndex = (Integer) this._columnsToIndexes.get(columnNameUpperCase);
if(colIndex != null)
{
return colIndex.intValue();
}
else
{
throw new NoSuchColumnException(this.getTableName(), columnNameUpperCase,
" (Non-uppercase input column: "+columnName+") in ColumnNameToIndexes cache map. " +
"Note that the map's column names are NOT case sensitive.");
}
}
/**
* @param columns The columns to be put into the hash table
* @return A map having the key value pair [columnName, columnIndexInInputArray]
*/
private Map createColumnIndexesMap(Column[] columns)
{
Map colsToIndexes = new HashMap(columns.length);
for (int i = 0; i < columns.length; i++)
{
colsToIndexes.put(columns[i].getColumnName().toUpperCase(), new Integer(i));
}
return colsToIndexes;
}
/**
* Validates and returns the datatype factory of the given connection
* @param connection The connection providing the {@link IDataTypeFactory}
* @return The datatype factory of the given connection
* @throws SQLException
*/
public IDataTypeFactory getDataTypeFactory(IDatabaseConnection connection)
throws SQLException
{
DatabaseConfig config = connection.getConfig();
Object factoryObj = config.getProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY);
if(!IDataTypeFactory.class.isAssignableFrom(factoryObj.getClass())) {
String msg = "Invalid datatype factory configured. Class '" +
factoryObj.getClass() + "' does not implement '" + IDataTypeFactory.class + "'.";
if(factoryObj instanceof String){
msg += " Ensure not to specify the fully qualified class name as String but the concrete " +
"instance of the datatype factory (for example 'new OracleDataTypeFactory()').";
}
// TODO Would a "DatabaseUnitConfigurationException make more sense?
throw new DatabaseUnitRuntimeException(msg);
}
IDataTypeFactory dataTypeFactory = (IDataTypeFactory)factoryObj;
// Validate, e.g. oracle metaData + oracleDataTypeFactory ==> OK
Connection jdbcConnection = connection.getConnection();
DatabaseMetaData metaData = jdbcConnection.getMetaData();
String validationMessage = validateDataTypeFactory(dataTypeFactory, metaData);
if(validationMessage!=null){
// Inform the user that we think he could get trouble with the current configuration
logger.warn("Potential problem found: " + validationMessage);
}
return dataTypeFactory;
}
/**
* Verifies that the data type factory supports the database product on the connection.
* If the data type factory is not valid for the connection, a warning is logged.
* @param dataTypeFactory The data type factory to validate.
* @param metaData The {@link DatabaseMetaData} needed to get the DB product name of the connection RDBMS.
* @return A validation message if there is a potential problem or null
if everything is fine.
* @throws java.sql.SQLException A database problem.
*/
String validateDataTypeFactory(IDataTypeFactory dataTypeFactory, DatabaseMetaData metaData)
throws SQLException
{
if (!(dataTypeFactory instanceof IDbProductRelatable))
{
return null;
}
IDbProductRelatable productRelatable = (IDbProductRelatable) dataTypeFactory;
String databaseProductName = metaData.getDatabaseProductName();
Collection validDbProductCollection = productRelatable.getValidDbProducts();
if (validDbProductCollection != null)
{
String lowerCaseDbProductName = databaseProductName.toLowerCase();
for (Iterator iterator = validDbProductCollection.iterator(); iterator.hasNext();) {
String validDbProduct = ((String) iterator.next()).toLowerCase();
if(lowerCaseDbProductName.indexOf(validDbProduct) > -1) {
logger.debug("The current database '{}' fits to the configured data type factory '{}'. Validation successful.",
databaseProductName, dataTypeFactory);
return null;
}
}
}
// If we get here, the validation failed
String validationMessage = "The configured data type factory '" + dataTypeFactory.getClass() +
"' might cause problems with the current database '" + databaseProductName +
"' (e.g. some datatypes may not be supported properly). " +
"In rare cases you might see this message because the list of supported database " +
"products is incomplete (list=" + validDbProductCollection + "). " +
"If so please request a java-class update via the forums." +
"If you are using your own IDataTypeFactory extending " +
"DefaultDataTypeFactory, ensure that you override getValidDbProducts() " +
"to specify the supported database products.";
return validationMessage;
}
}