package com.zenquery.model.dao.impl;
import com.zenquery.model.*;
import com.zenquery.model.dao.DatabaseConnectionDAO;
import com.zenquery.model.dao.QueryDAO;
import com.zenquery.util.BasicDataSourceFactory;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import javax.sql.DataSource;
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 java.util.Properties;
/**
* Created by willy on 13.04.14.
*/
public class JdbcDatabaseConnectionDAO implements DatabaseConnectionDAO {
private static final Logger logger = Logger.getLogger(JdbcDatabaseConnectionDAO.class);
private Properties databaseDriverProperties;
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
private QueryDAO queryDAO;
private BasicDataSourceFactory dataSourceFactory;
public void setDatabaseDriverProperties(Properties databaseDriverProperties) {
this.databaseDriverProperties = databaseDriverProperties;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void setQueryDAO(QueryDAO queryDAO) {
this.queryDAO = queryDAO;
}
public void setDataSourceFactory(BasicDataSourceFactory dataSourceFactory) {
this.dataSourceFactory = dataSourceFactory;
}
public DatabaseConnection find(Integer id) {
String sql = "SELECT * FROM database_connections WHERE id = ?";
jdbcTemplate = new JdbcTemplate(dataSource);
DatabaseConnection databaseConnection =
jdbcTemplate.query(sql, new Object[] { id }, new DatabaseConnectionMapper()).get(0);
return databaseConnection;
}
public List<DatabaseConnection> findAll() {
String sql = "SELECT * FROM database_connections";
jdbcTemplate = new JdbcTemplate(dataSource);
List<DatabaseConnection> databaseConnections =
jdbcTemplate.query(sql, new DatabaseConnectionMapper());
return databaseConnections;
}
public Number insert(final DatabaseConnection databaseConnection) {
final String sql = "INSERT INTO database_connections (name, url, username, password) VALUES (?, ?, ?, ?)";
jdbcTemplate = new JdbcTemplate(dataSource);
KeyHolder keyHolder = new GeneratedKeyHolder();
PreparedStatementCreator preparedStatementCreator = new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(sql, new String[] { "id" });
preparedStatement.setString(1, databaseConnection.getName());
preparedStatement.setString(2, databaseConnection.getUrl());
preparedStatement.setString(3, databaseConnection.getUsername());
preparedStatement.setString(4, databaseConnection.getPassword());
return preparedStatement;
}
};
jdbcTemplate.update(
preparedStatementCreator,
keyHolder
);
BasicDataSource dataSource = dataSourceFactory.getBasicDataSource(
databaseConnection.getUrl(),
databaseConnection.getUsername(),
databaseConnection.getPassword()
);
Map<String, Long> singleEntityQueries = new HashMap<String, Long>();
Map<String, String> tablePrimaryKeys = new HashMap<String, String>();
Map<String, List<ForeignKey>> tableForeignKeys = new HashMap<String, List<ForeignKey>>();
Map<String, String> tableReferences = new HashMap<String, String>();
String selectAllUserTablesSql = databaseDriverProperties.getProperty(dataSource.getDriverClassName() + ".queries.selectAllUserTables");
jdbcTemplate = new JdbcTemplate(dataSource);
List<Table> tables =
jdbcTemplate.query(selectAllUserTablesSql, new TableMapper());
try {
for (Table table : tables) {
String tableName = table.getName();
String selectPrimaryKeyForTable = databaseDriverProperties.getProperty(dataSource.getDriverClassName() + ".queries.selectPrimaryKeyForTable");
jdbcTemplate = new JdbcTemplate(dataSource);
List<PrimaryKey> primaryKeys = jdbcTemplate.query(selectPrimaryKeyForTable, new Object[] { tableName }, new PrimaryKeyMapper());
if (primaryKeys.size() > 0) {
String primaryKeyColumnName = jdbcTemplate.query(selectPrimaryKeyForTable, new Object[] { tableName }, new PrimaryKeyMapper()).get(0).getColumnName();
tablePrimaryKeys.put(tableName, primaryKeyColumnName);
Query queryForSingleEntity = new Query();
queryForSingleEntity.setDatabaseConnectionId(keyHolder.getKey().intValue());
queryForSingleEntity.setContent("SELECT * FROM " + tableName + " WHERE " + primaryKeyColumnName + " = ?");
Number tableQueryId = queryDAO.insert(queryForSingleEntity);
singleEntityQueries.put(tableName, tableQueryId.longValue());
}
String selectAllForeignKeysForTable = databaseDriverProperties.getProperty(dataSource.getDriverClassName() + ".queries.selectAllForeignKeysForTable");
jdbcTemplate = new JdbcTemplate(dataSource);
tableForeignKeys.put(tableName, jdbcTemplate.query(selectAllForeignKeysForTable, new Object[] { tableName }, new ForeignKeyMapper()));
}
for (String tableName : tableForeignKeys.keySet()) {
List<ForeignKey> foreignKeys = tableForeignKeys.get(tableName);
String tableReference = "";
if (foreignKeys.size() > 0) {
for (ForeignKey foreignKey : foreignKeys) {
Long queryId = singleEntityQueries.get(foreignKey.getTargetTable());
String resultSetForQueryUrl = "/api/v1/resultSetForQuery/" + queryId;
tableReference += ", '" + resultSetForQueryUrl + "/' "
+ databaseDriverProperties.getProperty(dataSource.getDriverClassName() + ".queries.concatOperator")
+ " " + foreignKey.getSourceKey() + " " + foreignKey.getTargetTable() + "_entity";
}
}
tableReferences.put(tableName, tableReference);
}
} catch (Exception e) {
logger.debug(e);
}
for (Table table : tables) {
String tableName = table.getName();
String tableReference = tableReferences.get(tableName) != null ? tableReferences.get(tableName) : "";
String primaryKeyColumnName = tablePrimaryKeys.get(tableName);
Query query = new Query();
query.setDatabaseConnectionId(keyHolder.getKey().intValue());
query.setContent("SELECT " + tableName + ".*" + tableReference + " FROM " + tableName);
queryDAO.insert(query);
try {
Number tableQueryId = singleEntityQueries.get(tableName);
if (tableQueryId != null) {
Query queryForSingleEntity = queryDAO.find(tableQueryId.intValue());
queryForSingleEntity.setContent("SELECT " + tableName + ".*" + tableReference + " FROM " + tableName + " WHERE " + primaryKeyColumnName + " = ?");
queryDAO.update(singleEntityQueries.get(tableName).intValue(), queryForSingleEntity);
}
} catch (Exception e) {
logger.debug(e);
}
}
return keyHolder.getKey();
}
public void update(Integer id, DatabaseConnection databaseConnection) {
String sql = "UPDATE database_connections SET name = ?, url = ?, username = ?, password = ? WHERE id = ?";
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(
sql,
new Object[] {
databaseConnection.getName(),
databaseConnection.getUrl(),
databaseConnection.getUsername(),
databaseConnection.getPassword(),
id
}
);
}
public void delete(Integer id) {
queryDAO.deleteByDatabaseConnectionId(id);
String sql = "DELETE FROM database_connections WHERE id = ?";
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(sql, new Object[] { id });
}
private static class DatabaseConnectionMapper implements RowMapper<DatabaseConnection> {
public DatabaseConnection mapRow(ResultSet rs, int rowNum) throws SQLException {
DatabaseConnection databaseConnection = new DatabaseConnection();
databaseConnection.setId(rs.getInt("id"));
databaseConnection.setName(rs.getString("name"));
databaseConnection.setUrl(rs.getString("url"));
databaseConnection.setUsername(rs.getString("username"));
databaseConnection.setPassword(rs.getString("password"));
return databaseConnection;
}
}
private static class TableMapper implements RowMapper<Table> {
public Table mapRow(ResultSet rs, int rowNum) throws SQLException {
Table table = new Table();
table.setName(rs.getString("table_name"));
return table;
}
}
private static class ForeignKeyMapper implements RowMapper<ForeignKey> {
public ForeignKey mapRow(ResultSet rs, int rowNum) throws SQLException {
ForeignKey foreignKey = new ForeignKey();
foreignKey.setSourceTable(rs.getString("source_table"));
foreignKey.setSourceKey(rs.getString("source_key"));
foreignKey.setTargetTable(rs.getString("target_table"));
foreignKey.setTargetKey(rs.getString("target_key"));
return foreignKey;
}
}
private static class PrimaryKeyMapper implements RowMapper<PrimaryKey> {
public PrimaryKey mapRow(ResultSet rs, int rowNum) throws SQLException {
PrimaryKey primaryKey = new PrimaryKey();
primaryKey.setColumnName(rs.getString("column_name"));
return primaryKey;
}
}
}