package org.infinispan.persistence.jdbc.table.management;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import org.infinispan.commons.CacheConfigurationException;
import org.infinispan.persistence.jdbc.DatabaseType;
import org.infinispan.persistence.jdbc.configuration.AbstractJdbcStoreConfiguration;
import org.infinispan.persistence.jdbc.configuration.JdbcStringBasedStoreConfiguration;
import org.infinispan.persistence.jdbc.configuration.TableManipulationConfiguration;
import org.infinispan.persistence.jdbc.connectionfactory.ConnectionFactory;
import org.infinispan.persistence.jdbc.logging.Log;
import org.infinispan.util.logging.LogFactory;
/**
* @author Ryan Emerson
*/
public class TableManagerFactory {
private static final Log LOG = LogFactory.getLog(TableManagerFactory.class, Log.class);
private static final String UPSERT_DISABLED = "infinispan.jdbc.upsert.disabled";
private static final String INDEXING_DISABLED = "infinispan.jdbc.indexing.disabled";
public static TableManager getManager(ConnectionFactory connectionFactory, JdbcStringBasedStoreConfiguration config) {
DbMetaData metaData = getDbMetaData(connectionFactory, config.dialect(), config.dbMajorVersion(),
config.dbMinorVersion(), isPropertyDisabled(config, UPSERT_DISABLED),
isPropertyDisabled(config, INDEXING_DISABLED));
return getManager(metaData, connectionFactory, config.table());
}
public static TableManager getManager(DbMetaData metaData, ConnectionFactory connectionFactory,
TableManipulationConfiguration tableConfig) {
switch (metaData.getType()) {
case H2:
return new H2TableManager(connectionFactory, tableConfig, metaData);
case MARIA_DB:
case MYSQL:
return new MySQLTableManager(connectionFactory, tableConfig, metaData);
case ORACLE:
return new OracleTableManager(connectionFactory, tableConfig, metaData);
case POSTGRES:
return new PostgresTableManager(connectionFactory, tableConfig, metaData);
case SQLITE:
return new SQLiteTableManager(connectionFactory, tableConfig, metaData);
case SYBASE:
return new SybaseTableManager(connectionFactory, tableConfig, metaData);
case SQL_SERVER:
return new SQLServerTableManager(connectionFactory, tableConfig, metaData);
default:
return new GenericTableManager(connectionFactory, tableConfig, metaData);
}
}
private static DbMetaData getDbMetaData(ConnectionFactory connectionFactory, DatabaseType databaseType,
Integer majorVersion, Integer minorVersion, boolean disableUpsert,
boolean disableIndexing) {
if (databaseType != null && majorVersion != null && minorVersion != null)
return new DbMetaData(databaseType, majorVersion, minorVersion, disableUpsert, disableIndexing);
Connection connection = null;
if (majorVersion == null || minorVersion == null) {
try {
// Try to retrieve major and minor simultaneously, if both aren't available then no use anyway
connection = connectionFactory.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
majorVersion = metaData.getDatabaseMajorVersion();
minorVersion = metaData.getDatabaseMinorVersion();
String version = majorVersion + "." + minorVersion;
if (LOG.isDebugEnabled()) {
LOG.debugf("Guessing database version as '%s'. If this is incorrect, please specify both the correct " +
"major and minor version of your database using the 'databaseMajorVersion' and " +
"'databaseMinorVersion' attributes in your configuration.", version);
}
// If we already know the DatabaseType via User, then don't check
if (databaseType != null)
return new DbMetaData(databaseType, majorVersion, minorVersion, disableUpsert, disableIndexing);
} catch (SQLException e) {
if (LOG.isDebugEnabled())
LOG.debug("Unable to retrieve DB Major and Minor versions from JDBC metadata.", e);
} finally {
connectionFactory.releaseConnection(connection);
}
}
try {
connection = connectionFactory.getConnection();
String dbProduct = connection.getMetaData().getDatabaseProductName();
return new DbMetaData(guessDialect(dbProduct), majorVersion, minorVersion, disableUpsert, disableIndexing);
} catch (Exception e) {
if (LOG.isDebugEnabled())
LOG.debug("Unable to guess dialect from JDBC metadata.", e);
} finally {
connectionFactory.releaseConnection(connection);
}
if (LOG.isDebugEnabled())
LOG.debug("Unable to detect database dialect using connection metadata. Attempting to guess on driver name.");
try {
connection = connectionFactory.getConnection();
String dbProduct = connectionFactory.getConnection().getMetaData().getDriverName();
return new DbMetaData(guessDialect(dbProduct), majorVersion, minorVersion, disableUpsert, disableIndexing);
} catch (Exception e) {
if (LOG.isDebugEnabled())
LOG.debug("Unable to guess database dialect from JDBC driver name.", e);
} finally {
connectionFactory.releaseConnection(connection);
}
if (databaseType == null) {
throw new CacheConfigurationException("Unable to detect database dialect from JDBC driver name or connection metadata. Please provide this manually using the 'dialect' property in your configuration. Supported database dialect strings are " + Arrays.toString(DatabaseType.values()));
}
if (LOG.isDebugEnabled())
LOG.debugf("Guessing database dialect as '%s'. If this is incorrect, please specify the correct dialect using the 'dialect' attribute in your configuration. Supported database dialect strings are %s", databaseType, Arrays.toString(DatabaseType.values()));
return new DbMetaData(databaseType, majorVersion, minorVersion, disableUpsert, disableIndexing);
}
private static DatabaseType guessDialect(String name) {
DatabaseType type = null;
if (name == null)
return null;
name = name.toLowerCase();
if (name.contains("mysql")) {
type = DatabaseType.MYSQL;
} else if (name.contains("postgres")) {
type = DatabaseType.POSTGRES;
} else if (name.contains("derby")) {
type = DatabaseType.DERBY;
} else if (name.contains("hsql") || name.contains("hypersonic")) {
type = DatabaseType.HSQL;
} else if (name.contains("h2")) {
type = DatabaseType.H2;
} else if (name.contains("sqlite")) {
type = DatabaseType.SQLITE;
} else if (name.contains("db2")) {
type = DatabaseType.DB2;
} else if (name.contains("informix")) {
type = DatabaseType.INFORMIX;
} else if (name.contains("interbase")) {
type = DatabaseType.INTERBASE;
} else if (name.contains("firebird")) {
type = DatabaseType.FIREBIRD;
} else if (name.contains("sqlserver") || name.contains("microsoft")) {
type = DatabaseType.SQL_SERVER;
} else if (name.contains("access")) {
type = DatabaseType.ACCESS;
} else if (name.contains("oracle")) {
type = DatabaseType.ORACLE;
} else if (name.contains("adaptive")) {
type = DatabaseType.SYBASE;
}
return type;
}
private static boolean isPropertyDisabled(AbstractJdbcStoreConfiguration config, String propertyName) {
String property = config.properties().getProperty(propertyName);
return property != null && Boolean.parseBoolean(property);
}
}