
rapture.postgres.connection.cache.ConnectionCacheLoader Maven / Gradle / Ivy
The newest version!
/**
* 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 {
private static final Logger log = Logger.getLogger(ConnectionCacheLoader.class);
public static final Map 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));
}
}
}