Java tutorial
/** * Copyright (C) 2011-2015 Incapture Technologies LLC * * This is an autogenerated license statement. When copyright notices appear below * this one that copyright supercedes this statement. * * Unless required by applicable law or agreed to in writing, software is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. * * Unless explicit permission obtained in writing this software cannot be distributed. */ package rapture.postgres.connection.cache; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.jdbc.support.DatabaseMetaDataCallback; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; import rapture.common.connection.ConnectionType; import rapture.common.connection.PostgresConnectionInfoConfigurer; import rapture.common.exception.ExceptionToString; import rapture.common.exception.RaptureExceptionFactory; import rapture.kernel.ContextFactory; import rapture.kernel.Kernel; import rapture.postgres.connection.DataSourceMonitor; import rapture.repo.jdbc.TransactionAwareDataSource; import rapture.repo.postgres.PostgresSanitizer; import com.google.common.cache.CacheLoader; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * @author bardhi * @since 3/30/15. */ public class ConnectionCacheLoader extends CacheLoader<String, ConnectionInfo> { private static final Logger log = Logger.getLogger(ConnectionCacheLoader.class); public static final Map<String, Integer> DEFAULT_OPTIONS = new HashMap<>(); static { DEFAULT_OPTIONS.put("initialPoolSize", 10); DEFAULT_OPTIONS.put("minPoolSize", 10); DEFAULT_OPTIONS.put("maxPoolSize", 50); DEFAULT_OPTIONS.put("maxIdleTimeExcessConnections", 600); DEFAULT_OPTIONS.put("maxStatements", 10); DEFAULT_OPTIONS.put("statementCacheNumDeferredCloseThreads", 0); DEFAULT_OPTIONS.put("idleConnectionTestPeriod", 600); } private final DataSourceMonitor monitor; public ConnectionCacheLoader(DataSourceMonitor monitor) { this.monitor = monitor; } @Override public ConnectionInfo load(String instanceName) throws Exception { ConnectionInfo info = new ConnectionInfo(); TransactionAwareDataSource dataSource = createDataSource(instanceName); info.setDataSource(dataSource); info.setSanitizer(createSanitizer(dataSource)); return info; } private TransactionAwareDataSource createDataSource(String instanceName) { rapture.common.ConnectionInfo info = Kernel.getSys() .getConnectionInfo(ContextFactory.getKernelUser(), ConnectionType.POSTGRES.toString()) .get(instanceName); if (info == null) { throw RaptureExceptionFactory.create("Postgres instance is not defined: " + instanceName); } log.info("connection info = " + info); try { return createFromConfig(instanceName, info); } catch (PropertyVetoException e) { throw RaptureExceptionFactory.create("Connection to Postgres failed: " + ExceptionToString.format(e)); } } private static final String DRIVER_CLASS = "org.postgresql.Driver"; private static final int DEFAULT_CHECKOUT_TIMEOUT = 3000; // milliseconds private TransactionAwareDataSource createFromConfig(String instanceName, rapture.common.ConnectionInfo info) throws PropertyVetoException { String url = PostgresConnectionInfoConfigurer.getUrl(info); String user = info.getUsername(); validateConfig(url, user); log.info("Host is " + url); ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDataSourceName(createDataSourceName(instanceName)); dataSource.setDriverClass(DRIVER_CLASS); // loads the jdbc driver dataSource.setJdbcUrl(url); dataSource.setUser(user); dataSource.setCheckoutTimeout(DEFAULT_CHECKOUT_TIMEOUT); String password = info.getPassword(); if (!StringUtils.isBlank(password)) { dataSource.setPassword(password); } else { throw RaptureExceptionFactory.create("Password cannot be null!"); } // pool size configuration dataSource.setInitialPoolSize(getOptionAsInt(info, "initialPoolSize")); dataSource.setMinPoolSize(getOptionAsInt(info, "minPoolSize")); dataSource.setMaxPoolSize(getOptionAsInt(info, "maxPoolSize")); dataSource.setMaxIdleTimeExcessConnections(getOptionAsInt(info, "maxIdleTimeExcessConnections")); // statement size configuration dataSource.setMaxStatements(getOptionAsInt(info, "maxStatements")); dataSource.setStatementCacheNumDeferredCloseThreads( getOptionAsInt(info, "statementCacheNumDeferredCloseThreads")); // connection testing dataSource.setIdleConnectionTestPeriod(getOptionAsInt(info, "idleConnectionTestPeriod")); boolean testConnectionOnCheckin = true; if (info.getOption("testConnectionOnCheckin") != null) { testConnectionOnCheckin = (boolean) info.getOption("testConnectionOnCheckin"); } dataSource.setTestConnectionOnCheckin(testConnectionOnCheckin); monitor.monitor(dataSource); try { Connection connection = DriverManager.getConnection(url, user, password); connection.close(); } catch (SQLException e) { throw RaptureExceptionFactory.create(ExceptionToString.format(e)); } return new TransactionAwareDataSource(dataSource); } private int getOptionAsInt(rapture.common.ConnectionInfo info, String key) { if (info.getOption(key) != null) { return (int) info.getOption(key); } else { return DEFAULT_OPTIONS.get(key); } } private String createDataSourceName(String instanceName) { return "Postgres-" + instanceName; } private void validateConfig(String postgresUrl, String user) { if (StringUtils.isBlank(postgresUrl)) { throw RaptureExceptionFactory.create("postgres url must be defined in the config"); } else if (StringUtils.isBlank(user)) { throw RaptureExceptionFactory.create("postgres user must be defined in the config"); } } public static PostgresSanitizer createSanitizer(DataSource dataSource) { DatabaseMetaDataCallback callback = new DatabaseMetaDataCallback() { @Override public String processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException { return dbmd.getIdentifierQuoteString(); } }; try { return new PostgresSanitizer(JdbcUtils.extractDatabaseMetaData(dataSource, callback).toString()); } catch (MetaDataAccessException e) { throw RaptureExceptionFactory.create("Unable to get quote identifier: " + ExceptionToString.format(e)); } } }