
org.dbunit.database.search.AbstractMetaDataBasedSearchCallback Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jtidy Show documentation
Show all versions of jtidy Show documentation
old 2002 version of xmlc-jtidy
The newest version!
/*
*
* The DbUnit Database Testing Framework
* Copyright (C)2005, 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.database.search;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.SortedSet;
import java.util.TreeSet;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.IMetadataHandler;
import org.dbunit.dataset.NoSuchTableException;
import org.dbunit.util.QualifiedTableName;
import org.dbunit.util.SQLHelper;
import org.dbunit.util.search.AbstractNodesFilterSearchCallback;
import org.dbunit.util.search.IEdge;
import org.dbunit.util.search.SearchException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Super-class for the ISearchCallback that implements the
* getEdges()
method using the database meta-data.
*
* @author Felipe Leme ([email protected])
* @version $Revision$
* @since Aug 25, 2005
*/
public abstract class AbstractMetaDataBasedSearchCallback extends AbstractNodesFilterSearchCallback {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(AbstractMetaDataBasedSearchCallback.class);
private final IDatabaseConnection connection;
/**
* Default constructor.
* @param connection connection where the edges will be calculated from
*/
public AbstractMetaDataBasedSearchCallback(IDatabaseConnection connection) {
this.connection = connection;
}
/**
* Get the connection where the edges will be calculated from.
* @return the connection where the edges will be calculated from
*/
public IDatabaseConnection getConnection() {
return connection;
}
protected static final int IMPORT = 0;
protected static final int EXPORT = 1;
/**
* indexes of the column names on the MetaData result sets.
*/
protected static final int[] TABLENAME_INDEXES = { 3, 7 };
protected static final int[] SCHEMANAME_INDEXES = { 2, 6 };
protected static final int[] PK_INDEXES = { 4, 4 };
protected static final int[] FK_INDEXES = { 8, 8 };
/**
* Get the nodes using the direct foreign key dependency, i.e, if table A has
* a FK for a table B, then getNodesFromImportedKeys(A) will return B.
* @param node table name
* @return tables with direct FK dependency from node
* @throws SearchException
*/
protected SortedSet getNodesFromImportedKeys(Object node)
throws SearchException {
logger.debug("getNodesFromImportedKeys(node={}) - start", node);
return getNodes(IMPORT, node);
}
/**
* Get the nodes using the reverse foreign key dependency, i.e, if table C has
* a FK for a table A, then getNodesFromExportedKeys(A) will return C.
*
* NOTE: this method should be used only as an auxiliary
* method for sub-classes that also use getNodesFromImportedKeys()
* or something similar, otherwise the generated sequence of tables might not
* work when inserted in the database (as some tables might be missing).
*
* @param node table name
* @return tables with reverse FK dependency from node
* @throws SearchException
*/
protected SortedSet getNodesFromExportedKeys(Object node)
throws SearchException {
logger.debug("getNodesFromExportedKeys(node={}) - start", node);
return getNodes(EXPORT, node);
}
/**
* Get the nodes using the both direct and reverse foreign key dependency, i.e,
* if table C has a FK for a table A and table A has a FK for a table B, then
* getNodesFromImportAndExportedKeys(A) will return B and C.
* @param node table name
* @return tables with reverse and direct FK dependency from node
* @throws SearchException
*/
protected SortedSet getNodesFromImportAndExportKeys(Object node)
throws SearchException {
logger.debug("getNodesFromImportAndExportKeys(node={}) - start", node);
SortedSet importedNodes = getNodesFromImportedKeys( node );
SortedSet exportedNodes = getNodesFromExportedKeys( node );
importedNodes.addAll( exportedNodes );
return importedNodes;
}
private SortedSet getNodes(int type, Object node) throws SearchException {
if(logger.isDebugEnabled())
logger.debug("getNodes(type={}, node={}) - start", Integer.toString(type), node);
try {
Connection conn = this.connection.getConnection();
String schema = this.connection.getSchema();
DatabaseMetaData metaData = conn.getMetaData();
SortedSet edges = new TreeSet();
getNodes(type, node, conn, schema, metaData, edges);
return edges;
} catch (SQLException e) {
throw new SearchException(e);
} catch (NoSuchTableException e) {
throw new SearchException(e);
}
}
private void getNodes(int type, Object node, Connection conn,
String schema, DatabaseMetaData metaData, SortedSet edges)
throws SearchException, NoSuchTableException
{
if (logger.isDebugEnabled())
{
logger.debug("getNodes(type={}, node={}, conn={}, schema={}, metaData={}, edges={}) - start",
new Object[] {String.valueOf(type), node, conn, schema, metaData, edges});
logger.debug("Getting edges for node " + node);
}
if (!(node instanceof String)) {
throw new IllegalArgumentException("node '" + node + "' should be a String, not a "
+ node.getClass().getName());
}
String tableName = (String) node;
QualifiedTableName qualifiedTableName = new QualifiedTableName(tableName, schema);
schema = qualifiedTableName.getSchema();
tableName = qualifiedTableName.getTable();
ResultSet rs = null;
try {
IMetadataHandler metadataHandler = (IMetadataHandler)
this.connection.getConfig().getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
// Validate if the table exists
if(!metadataHandler.tableExists(metaData, schema, tableName))
{
throw new NoSuchTableException("The table '"+tableName+"' does not exist in schema '"+schema+"'");
}
switch (type) {
case IMPORT:
rs = metaData.getImportedKeys(null, schema, tableName);
break;
case EXPORT:
rs = metaData.getExportedKeys(null, schema, tableName);
break;
}
DatabaseConfig dbConfig = this.connection.getConfig();
while (rs.next()) {
int index = TABLENAME_INDEXES[type];
int schemaindex = SCHEMANAME_INDEXES[type];
String dependentTableName = rs.getString(index);
String dependentSchemaName = rs.getString(schemaindex);
String pkColumn = rs.getString( PK_INDEXES[type] );
String fkColumn = rs.getString( FK_INDEXES[type] );
// set the schema in front if there is none ("SCHEMA.TABLE") - depending on the "qualified table names" feature
tableName = new QualifiedTableName(tableName, schema).getQualifiedNameIfEnabled(dbConfig);
dependentTableName = new QualifiedTableName(dependentTableName, dependentSchemaName).getQualifiedNameIfEnabled(dbConfig);
IEdge edge = newEdge(rs, type, tableName, dependentTableName, fkColumn, pkColumn );
if ( logger.isDebugEnabled() ) {
logger.debug("Adding edge " + edge);
}
edges.add(edge);
}
}
catch (SQLException e) {
throw new SearchException(e);
}
finally
{
try {
SQLHelper.close(rs);
} catch (SQLException e) {
throw new SearchException(e);
}
}
}
/**
* Creates an edge representing a foreign key relationship between 2 tables.
* @param rs database meta-data result set
* @param type type of relationship (IMPORT or EXPORT)
* @param from name of the table representing the 'from' node
* @param to name of the table representing the 'to' node
* @param fkColumn name of the foreign key column
* @param pkColumn name of the primary key column
* @return edge representing the relationship between the 2 tables, according to
* the type
* @throws SearchException not thrown in this method (but might on sub-classes)
*/
protected static ForeignKeyRelationshipEdge createFKEdge(ResultSet rs, int type,
String from, String to, String fkColumn, String pkColumn)
throws SearchException {
if (logger.isDebugEnabled()) {
logger.debug("createFKEdge(rs={}, type={}, from={}, to={}, fkColumn={}, pkColumn={}) - start",
new Object[] {rs, String.valueOf(type), from, to, fkColumn, pkColumn});
}
return type == IMPORT ?
new ForeignKeyRelationshipEdge( from, to, fkColumn, pkColumn ) :
new ForeignKeyRelationshipEdge( to, from, fkColumn, pkColumn );
}
/**
* This method can be overwritten by the sub-classes if they need to decorate
* the edge (for instance, providing an Edge that contains the primary and
* foreign keys used).
* @param rs database meta-data result set
* @param type type of relationship (IMPORT or EXPORT)
* @param from name of the table representing the 'from' node
* @param to name of the table representing the 'to' node
* @param fkColumn name of the foreign key column
* @param pkColumn name of the primary key column
* @return edge representing the relationship between the 2 tables, according to
* the type
* @throws SearchException not thrown in this method (but might on sub-classes)
*/
protected IEdge newEdge(ResultSet rs, int type, String from, String to, String fkColumn, String pkColumn)
throws SearchException {
if (logger.isDebugEnabled()) {
logger.debug("newEdge(rs={}, type={}, from={}, to={}, fkColumn={}, pkColumn={}) - start",
new Object[] {rs, String.valueOf(type), from, to, fkColumn, pkColumn});
}
return createFKEdge( rs, type, from, to, fkColumn, pkColumn );
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy