de.akquinet.jbosscc.guttenbase.tools.TableOrderTool Maven / Gradle / Ivy
package de.akquinet.jbosscc.guttenbase.tools;
import de.akquinet.jbosscc.guttenbase.meta.ForeignKeyMetaData;
import de.akquinet.jbosscc.guttenbase.meta.TableMetaData;
import java.sql.SQLException;
import java.util.*;
/**
* Order tables by foreign key constraints, i.e. the foreign keys of a database schema spawn an directed (possibly cyclic!) graph
* of dependencies. The tool tries to create of sequential order either in top-down (starting at the root nodes) or bottom-up
* (starting at the leaves) manner.
* If there are cycles in the dependencies, we choose the node with the fewest incoming/outgoing edges.
*
* © 2012-2020 akquinet tech@spree
*
*
* @author M. Dahm
*/
@SuppressWarnings("RedundantThrows")
public class TableOrderTool
{
public List getOrderedTables(final List tableMetaData, final boolean topDown) throws SQLException
{
final Map tableNodes = createGraph(tableMetaData);
return orderTables(tableNodes, topDown);
}
private List orderTables(final Map tableNodes, final boolean topDown) throws SQLException
{
final List result = new ArrayList<>();
while (!tableNodes.isEmpty())
{
final TableNode tableNode = findMatchingNode(new ArrayList<>(tableNodes.values()), topDown);
for (final TableNode referencingTable : tableNode.getReferencedByTables())
{
referencingTable.removeReferencedTable(tableNode);
}
for (final TableNode referencedTable : tableNode.getReferencedTables())
{
referencedTable.removeReferencedByTable(tableNode);
}
result.add(tableNode.getTableMetaData());
tableNodes.remove(tableNode.getTableMetaData().getTableName().toUpperCase());
}
return result;
}
private TableNode findMatchingNode(final List tableNodes, final boolean topDown)
{
tableNodes.sort((tn1, tn2) -> {
if (topDown) {
return tn1.getReferencedTables().size() - tn2.getReferencedTables().size();
} else {
return tn1.getReferencedByTables().size() - tn2.getReferencedByTables().size();
}
});
return tableNodes.get(0);
}
private Map createGraph(final List tableMetaData)
{
final Map tableNodes = new LinkedHashMap<>();
for (final TableMetaData table : tableMetaData)
{
final List importedForeignKeys = table.getImportedForeignKeys();
final TableNode tableNode = getTableNode(tableNodes, table);
for (final ForeignKeyMetaData foreignKeyMetaData : importedForeignKeys)
{
final TableNode referencingTable = getTableNode(tableNodes, foreignKeyMetaData.getReferencingColumn().getTableMetaData());
final TableNode referencedTable = getTableNode(tableNodes, foreignKeyMetaData.getReferencedColumn().getTableMetaData());
assert tableNode.equals(referencingTable);
referencingTable.addReferencedTable(referencedTable);
referencedTable.addReferencedByTable(referencingTable);
}
}
return tableNodes;
}
private TableNode getTableNode(final Map tableNodes, final TableMetaData table)
{
final String tableName = table.getTableName().toUpperCase();
if (tableNodes.containsKey(tableName))
{
return tableNodes.get(tableName);
}
else
{
final TableNode result = new TableNode(table);
tableNodes.put(tableName, result);
return result;
}
}
private static class TableNode
{
private final TableMetaData _tableMetaData;
private final List _referencedTables = new ArrayList<>();
private final List _referencedByTables = new ArrayList<>();
public TableNode(final TableMetaData tableMetaData)
{
_tableMetaData = tableMetaData;
}
public void addReferencedTable(final TableNode tableMetaData)
{
_referencedTables.add(tableMetaData);
}
public void removeReferencedTable(final TableNode tableMetaData)
{
_referencedTables.remove(tableMetaData);
}
public void addReferencedByTable(final TableNode tableMetaData)
{
_referencedByTables.add(tableMetaData);
}
public void removeReferencedByTable(final TableNode tableMetaData)
{
_referencedByTables.remove(tableMetaData);
}
public List getReferencedTables()
{
return _referencedTables;
}
public List getReferencedByTables()
{
return _referencedByTables;
}
public TableMetaData getTableMetaData()
{
return _tableMetaData;
}
@Override
public int hashCode()
{
return _tableMetaData.hashCode();
}
@Override
public boolean equals(final Object obj)
{
final TableNode that = (TableNode) obj;
return this.getTableMetaData().equals(that.getTableMetaData());
}
@Override
public String toString()
{
return _tableMetaData.getTableName() + "::referencedTables:"
+ toString(getReferencedTables())
+ ", referencedByTables: "
+ toString(getReferencedByTables());
}
private static String toString(final List referencedTables)
{
List result = new ArrayList<>();
for (TableNode tableNode : referencedTables)
{
result.add(tableNode.getTableMetaData().getTableName());
}
return result.toString();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy