package squill.mgen; import java.sql.*; import java.util.*; /** * @author Michael Hunger * @since 27.08.2008 */ public class DatabaseInfoReader { private final String driver; private final String url; private final String user; private final String password; private final String schema; private final MessageLogger logger; public DatabaseInfoReader(final String driver, final String url, final String user, final String password, final String schema, final MessageLogger logger) { this.driver = driver; this.url = url; this.user = user; this.password = password; this.schema = schema; this.logger = logger; } /** * Read in the information about the underlying database. * * @return List of tables * @throws Exception */ public Collection<DbTable> gatherDatabaseInfo() throws Exception { Class.forName(driver); // Load Database driver info("Database driver init - OK"); Collection<DbTable> dbTableList; Connection con = null; try { con = DriverManager.getConnection(url, user, password); info("Database connection - OK to " + url + " with user " + user); // Get the database Metadata. final DatabaseMetaData dbMetaData = con.getMetaData(); // Get list of database tables and views dbTableList = getTables(dbMetaData); if (dbTableList.size() > 0) { info("Reading in columns, primary keys, foreign keys..."); for (final DbTable curTable : dbTableList) { readTableColumns(dbMetaData, curTable); readTablePrimaryKeys(dbMetaData, curTable); readTableForeignKeys(dbMetaData, curTable); } } else { info("Skipping table processing because none was found"); } } catch (SQLException e) { logger.error("Unable to connect to database URL=" + url + " with user=" + user + " and password=" + password, e); throw e; } finally { if (con != null) { con.close(); con = null; } } return dbTableList; } private void info(final String message) { logger.info(message); } /** * Get all the table names in the current database that are not system * tables. * * @param metaData JDBC metadata about database * @return The list of all the tables in a database. * @throws SQLException */ public List<DbTable> getTables(final DatabaseMetaData metaData) throws SQLException { info("Getting table list..."); final List<DbTable> tables = new ArrayList<DbTable>(); ResultSet tableNamesRs = null; // these are the entity types we want from the database final String[] types = { "TABLE", "VIEW" }; try { tableNamesRs = metaData.getTables(null, schema, "%", types); while (tableNamesRs.next()) { final String name = tableNamesRs.getString("TABLE_NAME"); final String type = tableNamesRs.getString("TABLE_TYPE"); if (name.matches(".*[\\$=/].*")) { // skip temporary tables info("Skipping temporary table:" + name); continue; } else { info("Found table " + name); } final DbTable table = new DbTable(name, "VIEW".equalsIgnoreCase(type)); tables.add(table); } info("Found " + tables.size() + " tables."); } finally { if (tableNamesRs != null) { tableNamesRs.close(); } } return tables; } /** * Read table column information * * @param metaData Database Metadata * @param table Table to obtain information about * @throws SQLException */ public void readTableColumns(final DatabaseMetaData metaData, final DbTable table) throws SQLException { ResultSet columnRs = null; try { columnRs = metaData.getColumns(null, schema, table.getName(), null); while (columnRs.next()) { final String name = columnRs.getString("COLUMN_NAME"); final Integer sqlType = columnRs.getInt("DATA_TYPE"); final Integer size = columnRs.getInt("COLUMN_SIZE"); final Integer decimalDigits = columnRs.getInt("DECIMAL_DIGITS"); final Integer nullType = columnRs.getInt("NULLABLE"); final String defValue = columnRs.getString("COLUMN_DEF"); final DbColumn col = new DbColumn(table, name); col.setSqlType(sqlType); col.setSize(size); col.setScale(decimalDigits); col.setNullType(nullType); col.setDefaultValue(defValue); table.addColumn(col); } } finally { if (columnRs != null) { columnRs.close(); } } } /** * Retrieves a list of the columns composing the primary key of table * * @param metaData Database metadata * @param table Table * @throws SQLException */ public void readTablePrimaryKeys(final DatabaseMetaData metaData, final DbTable table) throws SQLException { ResultSet primaryKeyRs = null; try { primaryKeyRs = metaData.getPrimaryKeys(null, schema, table.getName()); while (primaryKeyRs.next()) { final String prk = (primaryKeyRs.getString("COLUMN_NAME")); info("Table " + table.getName() + " has primary key: " + prk); table.setPrimaryKey(prk); } } finally { if (primaryKeyRs != null) { primaryKeyRs.close(); } } } /** * Read in foreign keys of table * * @param metaData Database metadata * @param table Table object * @throws SQLException */ public void readTableForeignKeys(final DatabaseMetaData metaData, final DbTable table) throws SQLException { final Collection<DbForeignKey> keys = new HashSet<DbForeignKey>(); ResultSet foreignKeyRs = null; try { foreignKeyRs = metaData.getImportedKeys(null, schema, table.getName()); while (foreignKeyRs.next()) { final DbForeignKey fKey = new DbForeignKey(); fKey.setRefTableName(foreignKeyRs.getString("PKTABLE_NAME")); fKey.setKeyName(foreignKeyRs.getString("FK_NAME")); // if FK has no name - make it up (use refered table name // instead) if (fKey.getKeyName() == null) { fKey.setKeyName(fKey.getRefTableName()); } fKey.setRefColName(foreignKeyRs.getString("PKCOLUMN_NAME")); fKey.setColName(foreignKeyRs.getString("FKCOLUMN_NAME")); keys.add(fKey); info("Table " + table.getName() + " has foreign key: " + fKey.getColName()); } } catch (SQLException e) { logger.error("Could not table " + table.getName() + " foreign keys: ", e); } finally { if (foreignKeyRs != null) { foreignKeyRs.close(); } } table.setForeignKeys(keys); } }