package de.visualdependencies.plugin.mysql.util;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.Assert;
import de.visualdependencies.data.entity.Schema;
import de.visualdependencies.data.entity.SchemaTable;
import de.visualdependencies.data.entity.SchemaTrigger;
import de.visualdependencies.data.entity.SchemaView;
import de.visualdependencies.data.entity.TableTriggerDependency;
import de.visualdependencies.plugin.DataStore;
import de.visualdependencies.plugin.helper.MetadataWorkerParameters;
import de.visualdependencies.util.translator.ConnectionDataTranslator;
import de.visualdependencies.util.translator.TableTriggerDependencyDataTranslator;
import de.visualdependencies.util.translator.TriggerDataTranslator;
import edu.umd.cs.findbugs.annotations.NonNull;
public class MySqlJdbcMetadataUtil {
private static final String SQL_STATEMENT = "action_statement";
private static final String TRIGGER_SQL = "SELECT trigger_name, event_manipulation, definer, event_object_table, action_statement, action_timing FROM information_schema.triggers WHERE trigger_schema = ?";
private static final String TABLE_TRIGGER_SQL = "SHOW TRIGGERS";
private static final String JDBC_TRIGGER_NAME = "trigger_name";
private final Logger logger = Logger.getLogger(getClass());
private final MetadataWorkerParameters parameters;
@SuppressWarnings("unused")
private final ConnectionDataTranslator connectionDataTranslator;
/**
* Creates a new MySql jdbc metadata utility instance.
*
* Note: This constructor checks if the following objects are available: connection, data store and schema.
*
* @param parameters
* @return
*/
public static MySqlJdbcMetadataUtil createInstance(@NonNull final MetadataWorkerParameters parameters) {
Assert.notNull(parameters, "The metadata worker parameters must be set.");
Assert.notNull(parameters.getConnection(), "The metadata worker parameters must have a connection.");
Assert.notNull(parameters.getDataStore(), "The metadata worker parameters must have a datastore.");
Assert.notNull(parameters.getSchema(), "The metadata worker parameters must have a schema.");
Assert.notNull(parameters.getSchemaConnection(),
"The metadata worker parameters must have a valid schema connection.");
return new MySqlJdbcMetadataUtil(parameters);
}
protected SchemaTrigger buildSchemaTrigger(final ResultSet rs, final DataStore dataStore, Schema schema)
throws SQLException {
final SchemaTrigger trigger = dataStore.createSchemaTrigger(schema);
trigger.setName(rs.getString(JDBC_TRIGGER_NAME));
TriggerDataTranslator translator = TriggerDataTranslator.create(trigger);
translator.setSqlDefinition(rs.getString(SQL_STATEMENT));
if (logger.isInfoEnabled()) {
logger.info("Trigger has been built: " + trigger.getName());
}
return trigger;
}
private MySqlJdbcMetadataUtil(final MetadataWorkerParameters parameters) {
this.parameters = parameters;
connectionDataTranslator = ConnectionDataTranslator.create(parameters.getSchemaConnection());
}
public void loadTriggers() {
final Schema schema = parameters.getSchema();
final Connection connection = parameters.getConnection();
final DataStore dataStore = parameters.getDataStore();
PreparedStatement pstm = null;
ResultSet rs = null;
try {
final String catalog = connection.getCatalog();
if (logger.isDebugEnabled()) {
logger.debug(String.format("Loading MySQL.Information_schema.triggers (%s)...", catalog));
}
pstm = connection.prepareStatement(TRIGGER_SQL);
pstm.setString(1, catalog);
rs = pstm.executeQuery();
while (rs.next()) {
/**
* From the TRIGGER_SQL javadoc:
*
* 0 trigger_name,
* 1 event_manipulation,
* 2 definer,
* 3 event_object_table,
* 4 action_statement,
* 5 action_timing
*/
SchemaTrigger trigger = buildSchemaTrigger(rs, dataStore, schema);
dataStore.save(trigger);
}
logger.info("#loadTriggers has finished.");
} catch (final SQLException e) {
logger.error("#loadTriggers could not be finished.", e);
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(pstm);
}
}
public void loadTableTriggerDependencies() {
final Schema schema = parameters.getSchema();
final Connection connection = parameters.getConnection();
final DataStore dataStore = parameters.getDataStore();
List<TableTriggerDependency> dependencies = dataStore.loadTableTriggerDependencies(schema);
// Create shortcut cache
Map<String, SchemaTable> tables = new HashMap<String, SchemaTable>();
for (SchemaTable table : dataStore.loadTables(schema)) {
tables.put(table.getName(), table);
}
Map<String, SchemaView> views = new HashMap<String, SchemaView>();
for (SchemaView view : dataStore.loadViews(schema)) {
views.put(view.getName(), view);
}
Map<String, SchemaTrigger> triggers = new HashMap<String, SchemaTrigger>();
for (SchemaTrigger trigger : dataStore.loadTriggers(schema)) {
triggers.put(trigger.getName(), trigger);
}
CallableStatement cstm = null;
ResultSet rs = null;
try {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Loading MySQL.Show_triggers..."));
}
cstm = connection.prepareCall(TABLE_TRIGGER_SQL);
rs = cstm.executeQuery();
while (rs.next()) {
/**
* From the SHOW_TRIGGERS javadoc:
*
*/
TableTriggerDependency dependency = buildTableTriggerDependency(rs, dataStore, schema, tables, views,
triggers);
dataStore.save(dependency);
dependencies.add(dependency);
}
logger.info("#loadTriggers has finished.");
} catch (final SQLException e) {
logger.error("#loadTriggers could not be finished.", e);
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(cstm);
}
}
protected TableTriggerDependency buildTableTriggerDependency(ResultSet rs, DataStore dataStore, Schema schema,
Map<String, SchemaTable> tables, Map<String, SchemaView> views, Map<String, SchemaTrigger> triggers)
throws SQLException {
TableTriggerDependency dependency = dataStore.createTableTriggerDependency(schema);
String triggerName = rs.getString("Trigger");
String tableName = rs.getString("Table");
dependency.setName(triggerName);
SchemaTable table = tables.get(tableName);
SchemaTrigger trigger = triggers.get(triggerName);
dependency.setTable(table);
dependency.setTrigger(trigger);
TableTriggerDependencyDataTranslator translator = TableTriggerDependencyDataTranslator.create(dependency);
translator.setStatement(rs.getString("Statement"));
translator.setEvent(rs.getString("Event"));
if (logger.isInfoEnabled()) {
logger.info("TableTriggerDependency has been built: " + dependency.getName());
}
return dependency;
}
}