package com.thinkbiganalytics.jdbc.util; /*- * #%L * thinkbig-commons-jdbc * %% * Copyright (C) 2017 ThinkBig Analytics * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; import java.sql.Connection; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; /** * Common DatabaseType defining some of the major databases and validationQuery strings */ public enum DatabaseType { DERBY("Apache Derby", "jdbc:derby:", "select 1"), DB2("DB2", "jdbc:db2", "select 1 from sysibm.sysdummy1"), FIREBIRD("Firebird", "jdbc:firebird", "select 1 from rdb$database"), H2("H2", "jdbc:h2", "select 1"), HSQL("HSQL Database Engine", "jdbc:hsqldb", "select 1 from INFORMATION_SCHEMA.SYSTEM_USERS"), MYSQL("MySQL", "jdbc:mysql", "select 1"), ORACLE("Oracle", "jdbc:oracle", "select 1"), POSTGRES("PostgreSQL", "jdbc:postgressql", "select 1"), SQLITE("SQLite", "jdbc:sqlite", "select 1"), SQLSERVER("Microsoft SQL Server", "jdbc:sqlserver", "select 1"), SYBASE("Sybase", "jdbc:sybase", "select 1"), TERADATA("Teradata", "jdbc:teradata", "select 1"); private static final Map<String, DatabaseType> databaseProductNameMap; /** * lookup map based upon the jdbc connectoin string identifier */ private static final Map<String, DatabaseType> jdbcConnectionStringMap; /** * Build up the lookup maps */ static { databaseProductNameMap = new HashMap<>(); jdbcConnectionStringMap = new HashMap<>(); DatabaseType[] databaseTypes = values(); for (DatabaseType dbType : databaseTypes) { databaseProductNameMap.put(dbType.getProductName(), dbType); for (String jdbcConnectionId : dbType.getJdbcConnectionStringIdentifiers()) { jdbcConnectionStringMap.put(jdbcConnectionId, dbType); } } } /** * The database name obtained from the connection.getDatabaseProductName */ private final String productName; /** * unique string of jdbc connection to identify the database */ private final String[] jdbcConnectionStringIdentifiers; /** * The validation Query needed to reconnect */ private final String validationQuery; private DatabaseType(String productName, String jdbcUrlIdentifier, String validationQuery) { this(productName, new String[]{jdbcUrlIdentifier}, validationQuery); } private DatabaseType(String productName, String[] jdbcConnectionStringIdentifiers, String validationQuery) { this.productName = productName; this.jdbcConnectionStringIdentifiers = jdbcConnectionStringIdentifiers; this.validationQuery = validationQuery; } /** * Return the DatabaseType from the known Database Product name. * * @return the DatabaseType matching the product name */ public static DatabaseType fromProductName(String productName) throws IllegalArgumentException { if (!databaseProductNameMap.containsKey(productName)) { throw new IllegalArgumentException("DatabaseType not found for product name: " + productName); } else { return databaseProductNameMap.get(productName); } } /** * Return the DatabaseType containing the first match to the jdbc connection string * * @param connectionString a jdbc url connection string * @return the DatabaseType matching the connection String */ public static DatabaseType fromJdbcConnectionString(String connectionString) throws IllegalArgumentException { return jdbcConnectionStringMap.entrySet().stream() .filter(entry -> connectionString.toLowerCase().contains(entry.getKey())).map(entry -> entry.getValue()) .findFirst() .orElseThrow(() -> new IllegalArgumentException("DatabaseType not found for jdbc connection String: " + connectionString)); } /** * Parse the Database ProductName from the DataSource and return the matching DatabaseType */ public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException { String databaseProductName = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString(); databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName); try { return fromProductName(databaseProductName); } catch (IllegalArgumentException e) { throw new MetaDataAccessException(e.getMessage()); } } /** * Parse the Database ProductName from the Connection and return the matching DatabaseType */ public static DatabaseType fromMetaData(Connection connection) throws MetaDataAccessException { String databaseProductName = null; try { databaseProductName = connection.getMetaData().getDatabaseProductName(); } catch (SQLException e) { throw new MetaDataAccessException(e.getMessage()); } if (databaseProductName != null) { databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName); try { return fromProductName(databaseProductName); } catch (IllegalArgumentException e) { throw new MetaDataAccessException(e.getMessage()); } } else { throw new MetaDataAccessException("Database Type not found for connection"); } } /** * Get the database product name * * @return the database product name */ public String getProductName() { return this.productName; } /** * get the array of connection identifiers for this database type * * @return the array of unique jdbc connection identifiers */ public String[] getJdbcConnectionStringIdentifiers() { return this.jdbcConnectionStringIdentifiers; } /** * get the validation query for this database * * @return the validation query for the database */ public String getValidationQuery() { return validationQuery; } }