Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* Version 1.0 based on Apache Software License 1.1
*
* Copyright (c) 2003 Piotr Maj and DBMonster developers. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any,
* must include the following acknowledgment:
*
* "This product includes software developed by DBMonster developers
* (http://dbmonster.kernelpanic.pl/)."
*
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "DBMonster" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [email protected].
*
* 5. Products derived from this software may not be called "DBMonster",
* nor may "DBMonster" appear in their name, without prior written
* permission of Piotr Maj.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE DBMONSTER DEVELOPERS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package pl.kernelpanic.dbmonster;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import pl.kernelpanic.dbmonster.connection.ConnectionProvider;
import pl.kernelpanic.dbmonster.connection.DBCPConnectionProvider;
import pl.kernelpanic.dbmonster.connection.Transaction;
import pl.kernelpanic.dbmonster.generator.BinaryGenerator;
import pl.kernelpanic.dbmonster.generator.BooleanGenerator;
import pl.kernelpanic.dbmonster.generator.DataGenerator;
import pl.kernelpanic.dbmonster.generator.DateTimeGenerator;
import pl.kernelpanic.dbmonster.generator.ForeignKeyGenerator;
import pl.kernelpanic.dbmonster.generator.KeyGenerator;
import pl.kernelpanic.dbmonster.generator.MaxKeyGenerator;
import pl.kernelpanic.dbmonster.generator.NullGenerator;
import pl.kernelpanic.dbmonster.generator.NumberGenerator;
import pl.kernelpanic.dbmonster.generator.StringGenerator;
import pl.kernelpanic.dbmonster.generator.StringKeyGenerator;
import pl.kernelpanic.dbmonster.schema.Column;
import pl.kernelpanic.dbmonster.schema.Key;
import pl.kernelpanic.dbmonster.schema.Schema;
import pl.kernelpanic.dbmonster.schema.SchemaException;
import pl.kernelpanic.dbmonster.schema.SchemaUtil;
import pl.kernelpanic.dbmonster.schema.Table;
import pl.kernelpanic.dbmonster.sql.ExtendedTypes;
/**
* Schema Grabber.
*
* @author Piotr Maj <[email protected]>
*
* @version $Id: SchemaGrabber.java,v 1.3 2006/01/05 16:29:37 majek Exp $
*/
public class SchemaGrabber {
/**
* Logger.
*/
private Log log = LogFactory.getLog(SchemaGrabber.class);
/**
* Connection provider.
*/
private ConnectionProvider connectionProvider = null;
/**
* Specifies the tables we want to grab. If set to null
* all tables will be grabbed.
*/
private Vector tables = null;
/**
* Output stream.
*/
private OutputStream output = System.out;
/**
* Properties.
*/
private Properties properties = new Properties();
/**
* Database schema used in grabbing table. Useful for Oracle,
* and other databases that support schema.
*/
private String dbSchema = null;
/**
* Number of rows to generate.
*/
private int numRows = 1000;
/**
* Constructs new SchemaGrabber.
*/
public SchemaGrabber() {
}
/**
* Starts SchemaGrabber
*
* @param args command line arguments
*
* @throws Exception on errors
*/
public static void main(String[] args) throws Exception {
SchemaGrabber sg = new SchemaGrabber();
ConnectionProvider cp = new DBCPConnectionProvider();
sg.setConnectionProvider(cp);
Schema schema = sg.grabSchema();
OutputStream os = sg.getOutput();
SchemaUtil.serializeSchema(new PrintWriter(os), schema);
}
/**
* Starts schema grabber.
*
* @throws Exception on errors
*/
public void doTheJob() throws Exception {
Schema schema = grabSchema();
SchemaUtil.serializeSchema(new PrintWriter(output), schema);
}
/**
* Returns the output stream where the serialized schema should
* be pushed.
*
* @return output stream
*/
public OutputStream getOutput() {
return output;
}
/**
* Grabs the schema.
*
* @return Schema schema
*
* @throws Exception on errors
*/
public Schema grabSchema() throws Exception {
// read needed properties first.
dbSchema = properties.getProperty("dbmonster.jdbc.schema", null);
if (dbSchema != null && "".equals(dbSchema)) {
dbSchema = null;
}
String rows = properties.getProperty("dbmonster.rows", "1000");
try {
numRows = Integer.valueOf(rows).intValue();
} catch (Exception e) {
}
Schema schema = new Schema();
schema.setName("Change me!");
if (tables == null) {
tables = getTableNames();
}
Iterator it = tables.iterator();
int count = tables.size();
int current = 1;
log.info("Grabbing schema from database. "
+ count + " tables to grab.");
while (it.hasNext()) {
String tableName = (String) it.next();
Table t = grabTable(tableName);
schema.addTable(t);
log.info("Grabbing table " + tableName + ". "
+ ((current * 100) / count) + "% done.");
++current;
}
log.info("Grabbing schema from database complete.");
return schema;
}
/**
* Grabs the table.
*
* @param name table name
*
* @return table
*
* @throws SQLException on SQL errors
* @throws SchemaException on schema errors
*/
public Table grabTable(String name)
throws SQLException, SchemaException {
ResultSet rs;
Table t = new Table();
String tableName = name;
if (dbSchema != null) {
tableName = dbSchema + "." + tableName;
}
t.setName(tableName);
t.setRows(numRows);
Transaction tx = null;
try {
tx = new Transaction(connectionProvider);
Connection conn = tx.begin();
DatabaseMetaData md = conn.getMetaData();
// key
Vector keyColumns = new Vector();
rs = md.getPrimaryKeys(null, dbSchema, name);
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
keyColumns.add(columnName);
}
KeyGenerator generator = suggestKeyGenerator(name, keyColumns);
if (generator != null) {
Key key = new Key();
key.setGenerator(generator);
t.setKey(key);
}
else {
// This is to import anyway multiple keys.
keyColumns.clear();
}
//imported keys
HashMap foreignKeys = new HashMap();
rs = md.getImportedKeys(null, null, name);
while (rs.next()) {
String fkColumn = rs.getString("FKCOLUMN_NAME");
String pkColumn = rs.getString("PKCOLUMN_NAME");
String pkTable = rs.getString("PKTABLE_NAME");
/* String pkSchema = rs.getString("PKTABLE_SCHEM");
// Removed! Tables for ForeignKeyGenerator are not found if these lines
// are active!
if (pkSchema != null) {
pkTable = pkSchema + "." + pkTable;
}*/
foreignKeys.put(fkColumn, new PairBean(pkTable, pkColumn));
}
// columns
rs = md.getColumns(null, dbSchema, name, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
if (keyColumns.contains(columnName)) {
continue;
}
Column c = new Column();
c.setName(columnName);
c.setGenerator(suggestGenerator(name, columnName, foreignKeys));
t.addColumn(c);
}
} catch (SQLException e) {
tx.abort();
log.fatal(e.getMessage());
throw e;
} finally {
if (tx != null) {
tx.close();
}
}
return t;
}
/**
* Returns names of the tables in the database.
*
* @return vector of strings
*
* @throws SQLException on errors
*/
public Vector getTableNames() throws SQLException {
Vector v = new Vector();
Transaction tx = null;
try {
tx = new Transaction(connectionProvider);
Connection conn = tx.begin();
DatabaseMetaData md = conn.getMetaData();
ResultSet rs =
md.getTables(null, dbSchema, "%", new String[] {"TABLE"});
while (rs.next()) {
String name = rs.getString("TABLE_NAME");
v.add(name);
}
tx.commit();
} catch (SQLException e) {
log.fatal(e.getMessage());
tx.abort();
throw e;
} finally {
if (tx != null) {
tx.close();
}
}
return v;
}
/**
* Returns a connection provider used by the grabber.
*
* @return connection provider instance
*/
public ConnectionProvider getConnectionProvider() {
return connectionProvider;
}
/**
* Sets the connection provider.
*
* @param provider connection provider
*/
public void setConnectionProvider(ConnectionProvider provider) {
connectionProvider = provider;
}
/**
* Returns the logger.
*
* @return logger
*/
public Log getLog() {
return log;
}
/**
* Sets the logger
*
* @param logger new logger
*/
public void setLog(Log logger) {
log = logger;
}
/**
* Adds a table names to the list of grabbed tables.
*
* @param name name of the table
*
* @throws SQLException if table cannot be found
*/
public void addTable(String name) throws SQLException {
if (tables == null) {
tables = new Vector();
}
String tableName = name;
Transaction tx = null;
try {
tx = new Transaction(connectionProvider);
Connection conn = tx.begin();
DatabaseMetaData md = conn.getMetaData();
if (md.storesLowerCaseIdentifiers()) {
tableName = name.toLowerCase();
} else if (md.storesUpperCaseIdentifiers()) {
tableName = name.toUpperCase();
}
ResultSet rs =
md.getTables(null, dbSchema, tableName, new String[] {"TABLE"});
if (!rs.next()) {
throw new SQLException("No such table <" + name + ">.");
}
tx.commit();
tables.add(tableName);
} catch (SQLException e) {
log.fatal(e.getMessage());
tx.abort();
throw e;
} finally {
if (tx != null) {
tx.close();
}
}
}
/**
* Sets the output file name.
*
* @param file file name
*
* @throws IOException on I/O errors
*/
public void setOutputFile(String file) throws IOException {
File f = new File(file);
output = new FileOutputStream(f);
}
/**
* Sets the properties for the SchemaGrabber
* @param p
*/
public void setProperties(Properties p) {
properties = p;
}
/**
* Suggests which key generator should be used. In current implementation
* it only check if the key consists of only one table and if so it uses
* MaxKeyGenerator (it the type of the column allow it).
*
* @param tableName the name ot the table
* @param columns columns
*
* @return key generator or null
*
* @throws SQLException on errors
*/
private KeyGenerator suggestKeyGenerator(String tableName, Vector columns) throws SQLException {
KeyGenerator generator = null;
if (columns.size() != 1) {
return generator;
}
String columnName = (String) columns.get(0);
Transaction tx = null;
try {
tx = new Transaction(connectionProvider);
Connection conn = tx.begin();
DatabaseMetaData md = conn.getMetaData();
ResultSet rs = md.getColumns(null, null, tableName, columnName);
rs.next();
int dataType = rs.getInt("DATA_TYPE");
if (isIntegerType(dataType)) {
generator = new MaxKeyGenerator();
((MaxKeyGenerator) generator).setColumnName(columnName);
} else if (isTextType(dataType)) {
generator = new StringKeyGenerator();
((StringKeyGenerator) generator).setStartValue("0");
((StringKeyGenerator) generator).setColumnName(columnName);
} else {
if (log.isWarnEnabled()) {
log.warn("Datatype " + dataType + " for " + columnName
+ " is unknown, no Key Generator in schema.xml");
}
}
tx.commit();
} catch (SQLException e) {
tx.abort();
log.fatal(e.getMessage());
throw e;
} finally {
if (tx != null) {
tx.close();
}
}
return generator;
}
/**
* Suggests the data generator for a column.
*
* @param tableName table name
* @param columnName column name
* @param foreignKeys infomation about foreing keys in this table
*
* @return data generator. Never null.
*
* @throws SQLException on SQL errors
*/
private DataGenerator suggestGenerator(
String tableName,
String columnName,
Map foreignKeys) throws SQLException {
DataGenerator generator = new NullGenerator();
if (foreignKeys.containsKey(columnName)) {
generator = new ForeignKeyGenerator();
PairBean bean = (PairBean) foreignKeys.get(columnName);
((ForeignKeyGenerator) generator).setTableName(bean.getKey());
((ForeignKeyGenerator) generator).setColumnName(bean.getValue());
return generator;
}
Transaction tx = null;
try {
tx = new Transaction(connectionProvider);
Connection conn = tx.begin();
DatabaseMetaData md = conn.getMetaData();
ResultSet rs = md.getColumns(null, null, tableName, columnName);
rs.next();
int dataType = rs.getInt("DATA_TYPE");
String isNullable = rs.getString("IS_NULLABLE");
int nulls = 0;
if (isNullable == null) {
isNullable = "NO";
}
if ("YES".equals(isNullable)) {
nulls = 10;
}
int columnSize = rs.getInt("COLUMN_SIZE");
int decimalDigits = rs.getInt("DECIMAL_DIGITS");
if (isIntegerType(dataType)) {
generator = new NumberGenerator();
NumberGenerator numGen = (NumberGenerator) generator;
numGen.setNulls(nulls);
if (dataType == Types.BIGINT) {
numGen.setReturnedType("long");
} else if (dataType == Types.INTEGER) {
numGen.setReturnedType("integer");
} else if (dataType == Types.SMALLINT
|| dataType == Types.TINYINT) {
numGen.setReturnedType("short");
} else if (dataType == Types.DECIMAL || dataType == Types.NUMERIC) {
if (decimalDigits > 0) {
numGen.setReturnedType("float");
numGen.setScale(decimalDigits);
} else {
numGen.setReturnedType("integer");
}
}
} else if (isDoubleType(dataType)) {
generator = new NumberGenerator();
NumberGenerator numGen = (NumberGenerator) generator;
numGen.setNulls(nulls);
if (decimalDigits > 0) {
numGen.setReturnedType("double");
numGen.setScale(decimalDigits);
} else {
numGen.setReturnedType("long");
}
} else if (isBooleanType(dataType)) {
generator = new BooleanGenerator();
((BooleanGenerator) generator).setNulls(nulls);
} else if (isTextType(dataType)) {
generator = new StringGenerator();
((StringGenerator) generator).setNulls(nulls);
if (columnSize > 0) {
((StringGenerator) generator).setMaxLength(columnSize);
}
} else if (isTimeType(dataType)) {
generator = new DateTimeGenerator();
((DateTimeGenerator) generator).setNulls(nulls);
if (dataType == Types.DATE) {
((DateTimeGenerator) generator).setReturnedType("date");
} else if (dataType == Types.TIME) {
((DateTimeGenerator) generator).setReturnedType("time");
} else if (dataType == Types.TIMESTAMP) {
((DateTimeGenerator) generator)
.setReturnedType("timestamp");
}
} else if (isBinaryType(dataType)) {
generator = new BinaryGenerator();
((BinaryGenerator) generator).setNulls(nulls);
if (columnSize > 0) {
((BinaryGenerator) generator).setMaxLength(columnSize);
}
} else {
if (log.isWarnEnabled()) {
log.warn("Unknown datatype. No generator created.");
}
}
tx.commit();
} finally {
if (tx != null) {
tx.close();
}
}
return generator;
}
/**
* Checks if the type is one of numeric type.
*
* @param type type to check
*
* @return true if type accepts numbers
*/
private boolean isIntegerType(int type) {
int tempType;
tempType = ExtendedTypes.getInstance().
getStandardAlias(properties.getProperty(
"dbmonster.jdbc.driver"), type);
return (tempType == Types.BIGINT)
|| (tempType == Types.INTEGER)
|| (tempType == Types.SMALLINT)
|| (tempType == Types.TINYINT)
|| (tempType == Types.DECIMAL)
|| (tempType == Types.NUMERIC);
}
/**
* Checks if the type is one of double type.
*
* @param type type to check
*
* @return true if type accepts numbers;
* false otherwise
*/
private boolean isDoubleType(int type) {
return type == Types.DOUBLE;
}
/**
* Checks if the type is one of text or character type.
*
* @param type type to check
*
* @return true if type accepts strings
*/
private boolean isTextType(int type) {
int tempType;
tempType = ExtendedTypes.getInstance().
getStandardAlias(properties.getProperty(
"dbmonster.jdbc.driver"), type);
return (tempType == Types.CHAR)
|| (tempType == Types.LONGVARCHAR)
|| (tempType == Types.VARCHAR);
}
/**
* Checks if the type is one of text or date/time type.
*
* @param type type to check
*
* @return true if type accepts dates
*/
private boolean isTimeType(int type) {
int tempType;
tempType = ExtendedTypes.getInstance().
getStandardAlias(properties.getProperty(
"dbmonster.jdbc.driver"), type);
return (tempType == Types.DATE)
|| (tempType == Types.TIME)
|| (tempType == Types.TIMESTAMP);
}
/**
* Checks if the type is boolean
*
* @param type type to check
*
* @return true if type is boolean
*/
private boolean isBooleanType(int type) {
int tempType;
tempType = ExtendedTypes.getInstance().
getStandardAlias(properties.getProperty(
"dbmonster.jdbc.driver"), type);
return (tempType == Types.BIT)
|| (tempType == Types.BOOLEAN);
}
/**
* Checks if the type is binary, blob, longvarbinary or varbinary
*
* @param type type to check
*
* @return true if type is boolean;
* false otherwise
*/
private boolean isBinaryType(int type) {
if (type == Types.BINARY
|| type == Types.BLOB
|| type == Types.LONGVARBINARY
|| type == Types.VARBINARY)
{
return true;
} else {
return false;
}
}
}
/**
* Simple maps a key to a value.
*/
final class PairBean {
/**
* Key.
*/
private String key = null;
/**
* Value.
*/
private String value = null;
/**
* Constructs new PairBean
*
* @param k key
* @param v value
*/
public PairBean(String k, String v) {
key = k;
value = v;
}
/**
* Returns the key.
*
* @return key
*/
public String getKey() {
return key;
}
/**
* Sets the key.
*
* @param k key
*/
public void setKey(String k) {
key = k;
}
/**
* Returns the value.
*
* @return value
*/
public String getValue() {
return value;
}
/**
* Sets the value
*
* @param v value to set
*/
public void setValue(String v) {
value = v;
}
}