diff --git a/pom.xml b/pom.xml index 456cd8079..cb4001070 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,24 @@ 1.0 + + org.avaje + avaje-datasource-api + 1.1 + + + + org.avaje + avaje-datasource + 1.1.1 + + + + + + + + org.slf4j slf4j-api diff --git a/src/main/java/com/avaje/ebean/config/DataSourceConfig.java b/src/main/java/com/avaje/ebean/config/DataSourceConfig.java deleted file mode 100644 index 648138210..000000000 --- a/src/main/java/com/avaje/ebean/config/DataSourceConfig.java +++ /dev/null @@ -1,556 +0,0 @@ -package com.avaje.ebean.config; - -import java.sql.Connection; -import java.util.Map; -import java.util.Properties; - -import com.avaje.ebean.Transaction; -import com.avaje.ebean.util.StringHelper; - -/** - * Used to config a DataSource when using the internal Ebean DataSource - * implementation. - *

- * If a DataSource instance is already defined via - * {@link ServerConfig#setDataSource(javax.sql.DataSource)} or defined as JNDI - * dataSource via {@link ServerConfig#setDataSourceJndiName(String)} then those - * will used and not this DataSourceConfig. - *

- */ -public class DataSourceConfig { - - private String url; - - private String username; - - private String password; - - private String driver; - - private int minConnections = 2; - - private int maxConnections = 20; - - private int isolationLevel = Transaction.READ_COMMITTED; - - private boolean autoCommit; - - private String heartbeatSql; - - private int heartbeatFreqSecs = 30; - - private int heartbeatTimeoutSeconds = 3; - - private boolean captureStackTrace; - - private int maxStackTraceSize = 5; - - private int leakTimeMinutes = 30; - - private int maxInactiveTimeSecs = 720; - - private int maxAgeMinutes = 0; - - private int trimPoolFreqSecs = 59; - - private int pstmtCacheSize = 20; - - private int cstmtCacheSize = 20; - - private int waitTimeoutMillis = 1000; - - private String poolListener; - - private boolean offline; - - protected Map customProperties; - - /** - * Return the connection URL. - */ - public String getUrl() { - return url; - } - - /** - * Set the connection URL. - */ - public void setUrl(String url) { - this.url = url; - } - - /** - * Return the database username. - */ - public String getUsername() { - return username; - } - - /** - * Set the database username. - */ - public void setUsername(String username) { - this.username = username; - } - - /** - * Return the database password. - */ - public String getPassword() { - return password; - } - - /** - * Set the database password. - */ - public void setPassword(String password) { - this.password = password; - } - - /** - * Return the database driver. - */ - public String getDriver() { - return driver; - } - - /** - * Set the database driver. - */ - public void setDriver(String driver) { - this.driver = driver; - } - - /** - * Return the transaction isolation level. - */ - public int getIsolationLevel() { - return isolationLevel; - } - - /** - * Set the transaction isolation level. - */ - public void setIsolationLevel(int isolationLevel) { - this.isolationLevel = isolationLevel; - } - - /** - * Return autoCommit setting. - */ - public boolean isAutoCommit() { - return autoCommit; - } - - /** - * Set to true to turn on autoCommit. - */ - public void setAutoCommit(boolean autoCommit) { - this.autoCommit = autoCommit; - } - - /** - * Return the minimum number of connections the pool should maintain. - */ - public int getMinConnections() { - return minConnections; - } - - /** - * Set the minimum number of connections the pool should maintain. - */ - public void setMinConnections(int minConnections) { - this.minConnections = minConnections; - } - - /** - * Return the maximum number of connections the pool can reach. - */ - public int getMaxConnections() { - return maxConnections; - } - - /** - * Set the maximum number of connections the pool can reach. - */ - public void setMaxConnections(int maxConnections) { - this.maxConnections = maxConnections; - } - - /** - * Return a SQL statement used to test the database is accessible. - *

- * Note that if this is not set then it can get defaulted from the - * DatabasePlatform. - *

- */ - public String getHeartbeatSql() { - return heartbeatSql; - } - - /** - * Set a SQL statement used to test the database is accessible. - *

- * Note that if this is not set then it can get defaulted from the - * DatabasePlatform. - *

- */ - public void setHeartbeatSql(String heartbeatSql) { - this.heartbeatSql = heartbeatSql; - } - - - /** - * Return the heartbeat frequency in seconds. - *

- * This is the expected frequency in which the DataSource should be checked to - * make sure it is healthy and trim idle connections. - *

- */ - public int getHeartbeatFreqSecs() { - return heartbeatFreqSecs; - } - - /** - * Set the expected heartbeat frequency in seconds. - */ - public void setHeartbeatFreqSecs(int heartbeatFreqSecs) { - this.heartbeatFreqSecs = heartbeatFreqSecs; - } - - /** - * Return the heart beat timeout in seconds. - */ - public int getHeartbeatTimeoutSeconds() { - return heartbeatTimeoutSeconds; - } - - /** - * Set the heart beat timeout in seconds. - */ - public void setHeartbeatTimeoutSeconds(int heartbeatTimeoutSeconds) { - this.heartbeatTimeoutSeconds = heartbeatTimeoutSeconds; - } - - /** - * Return true if a stack trace should be captured when obtaining a connection - * from the pool. - *

- * This can be used to diagnose a suspected connection pool leak. - *

- *

- * Obviously this has a performance overhead. - *

- */ - public boolean isCaptureStackTrace() { - return captureStackTrace; - } - - /** - * Set to true if a stack trace should be captured when obtaining a connection - * from the pool. - *

- * This can be used to diagnose a suspected connection pool leak. - *

- *

- * Obviously this has a performance overhead. - *

- */ - public void setCaptureStackTrace(boolean captureStackTrace) { - this.captureStackTrace = captureStackTrace; - } - - /** - * Return the max size for reporting stack traces on busy connections. - */ - public int getMaxStackTraceSize() { - return maxStackTraceSize; - } - - /** - * Set the max size for reporting stack traces on busy connections. - */ - public void setMaxStackTraceSize(int maxStackTraceSize) { - this.maxStackTraceSize = maxStackTraceSize; - } - - /** - * Return the time in minutes after which a connection could be considered to - * have leaked. - */ - public int getLeakTimeMinutes() { - return leakTimeMinutes; - } - - /** - * Set the time in minutes after which a connection could be considered to - * have leaked. - */ - public void setLeakTimeMinutes(int leakTimeMinutes) { - this.leakTimeMinutes = leakTimeMinutes; - } - - /** - * Return the size of the PreparedStatement cache (per connection). - */ - public int getPstmtCacheSize() { - return pstmtCacheSize; - } - - /** - * Set the size of the PreparedStatement cache (per connection). - */ - public void setPstmtCacheSize(int pstmtCacheSize) { - this.pstmtCacheSize = pstmtCacheSize; - } - - /** - * Return the size of the CallableStatement cache (per connection). - */ - public int getCstmtCacheSize() { - return cstmtCacheSize; - } - - /** - * Set the size of the CallableStatement cache (per connection). - */ - public void setCstmtCacheSize(int cstmtCacheSize) { - this.cstmtCacheSize = cstmtCacheSize; - } - - /** - * Return the time in millis to wait for a connection before timing out once - * the pool has reached its maximum size. - */ - public int getWaitTimeoutMillis() { - return waitTimeoutMillis; - } - - /** - * Set the time in millis to wait for a connection before timing out once the - * pool has reached its maximum size. - */ - public void setWaitTimeoutMillis(int waitTimeoutMillis) { - this.waitTimeoutMillis = waitTimeoutMillis; - } - - /** - * Return the time in seconds a connection can be idle after which it can be - * trimmed from the pool. - *

- * This is so that the pool after a busy period can trend over time back - * towards the minimum connections. - *

- */ - public int getMaxInactiveTimeSecs() { - return maxInactiveTimeSecs; - } - - /** - * Return the maximum age a connection is allowed to be before it is closed. - *

- * This can be used to close really old connections. - *

- */ - public int getMaxAgeMinutes() { - return maxAgeMinutes; - } - - /** - * Set the maximum age a connection can be in minutes. - */ - public void setMaxAgeMinutes(int maxAgeMinutes) { - this.maxAgeMinutes = maxAgeMinutes; - } - - /** - * Set the time in seconds a connection can be idle after which it can be - * trimmed from the pool. - *

- * This is so that the pool after a busy period can trend over time back - * towards the minimum connections. - *

- */ - public void setMaxInactiveTimeSecs(int maxInactiveTimeSecs) { - this.maxInactiveTimeSecs = maxInactiveTimeSecs; - } - - - /** - * Return the minimum time gap between pool trim checks. - *

- * This defaults to 59 seconds meaning that the pool trim check will run every - * minute assuming the heart beat check runs every 30 seconds. - *

- */ - public int getTrimPoolFreqSecs() { - return trimPoolFreqSecs; - } - - /** - * Set the minimum trim gap between pool trim checks. - */ - public void setTrimPoolFreqSecs(int trimPoolFreqSecs) { - this.trimPoolFreqSecs = trimPoolFreqSecs; - } - - /** - * Return the pool listener. - */ - public String getPoolListener() { - return poolListener; - } - - /** - * Set a pool listener. - */ - public void setPoolListener(String poolListener) { - this.poolListener = poolListener; - } - - /** - * Return true if the DataSource should be left offline. - *

- * This is to support DDL generation etc without having a real database. - *

- */ - public boolean isOffline() { - return offline; - } - - /** - * Set to true if the DataSource should be left offline. - *

- * This is to support DDL generation etc without having a real database. - *

- *

- * Note that you MUST specify the database platform name (oracle, postgres, - * h2, mysql etc) using {@link ServerConfig#setDatabasePlatformName(String)} - * when you do this. - *

- */ - public void setOffline(boolean offline) { - this.offline = offline; - } - - /** - * Return a map of custom properties for the jdbc driver connection. - */ - public Map getCustomProperties() { - return customProperties; - } - - /** - * Set custom properties for the jdbc driver connection. - * - * @param customProperties - */ - public void setCustomProperties(Map customProperties) { - this.customProperties = customProperties; - } - - /** - * Load the settings by reading the ebean.properties file. - * - * @param serverName name of the server - */ - public void loadSettings(String serverName) { - loadSettings(new PropertiesWrapper("datasource", serverName, PropertyMap.defaultProperties())); - } - - /** - * Load the settings from the properties supplied. - *

- * You can use this when you have your own properties to use for configuration. - *

- * - * @param properties the properties to configure the datasource - * @param serverName the name of the specific datasource (optional) - */ - public void loadSettings(Properties properties, String serverName) { - PropertiesWrapper dbProps = new PropertiesWrapper("datasource", serverName, properties); - loadSettings(dbProps); - } - - /** - * Load the settings from the PropertiesWrapper. - */ - public void loadSettings(PropertiesWrapper properties) { - - username = properties.get("username", username); - password = properties.get("password", password); - driver = properties.get("driver", properties.get("databaseDriver", driver)); - url = properties.get("url", properties.get("databaseUrl", url)); - - autoCommit = properties.getBoolean("autoCommit", autoCommit); - captureStackTrace = properties.getBoolean("captureStackTrace", captureStackTrace); - maxStackTraceSize = properties.getInt("maxStackTraceSize", maxStackTraceSize); - leakTimeMinutes = properties.getInt("leakTimeMinutes", leakTimeMinutes); - maxInactiveTimeSecs = properties.getInt("maxInactiveTimeSecs", maxInactiveTimeSecs); - trimPoolFreqSecs = properties.getInt("trimPoolFreqSecs", trimPoolFreqSecs); - maxAgeMinutes = properties.getInt("maxAgeMinutes", maxAgeMinutes); - - minConnections = properties.getInt("minConnections", minConnections); - maxConnections = properties.getInt("maxConnections", maxConnections); - pstmtCacheSize = properties.getInt("pstmtCacheSize", pstmtCacheSize); - cstmtCacheSize = properties.getInt("cstmtCacheSize", cstmtCacheSize); - - waitTimeoutMillis = properties.getInt("waitTimeout", waitTimeoutMillis); - - heartbeatSql = properties.get("heartbeatSql", heartbeatSql); - heartbeatTimeoutSeconds = properties.getInt("heartbeatTimeoutSeconds", heartbeatTimeoutSeconds); - poolListener = properties.get("poolListener", poolListener); - offline = properties.getBoolean("offline", offline); - - String isoLevel = properties.get("isolationlevel", getTransactionIsolationLevel(isolationLevel)); - this.isolationLevel = getTransactionIsolationLevel(isoLevel); - - String customProperties = properties.get("customProperties", null); - if (customProperties != null && customProperties.length() > 0) { - this.customProperties = StringHelper.delimitedToMap(customProperties, ";", "="); - } - - } - - /** - * Return the isolation level description from the associated Connection int value. - */ - public String getTransactionIsolationLevel(int level) { - switch (level) { - case Connection.TRANSACTION_NONE : return "NONE"; - case Connection.TRANSACTION_READ_COMMITTED : return "READ_COMMITTED"; - case Connection.TRANSACTION_READ_UNCOMMITTED : return "READ_UNCOMMITTED"; - case Connection.TRANSACTION_REPEATABLE_READ : return "REPEATABLE_READ"; - case Connection.TRANSACTION_SERIALIZABLE : return "SERIALIZABLE"; - default: throw new RuntimeException("Transaction Isolation level [" + level + "] is not known."); - } - } - - /** - * Return the isolation level for a given string description. - */ - public int getTransactionIsolationLevel(String level) { - level = level.toUpperCase(); - if (level.startsWith("TRANSACTION")) { - level = level.substring("TRANSACTION".length()); - } - level = level.replace("_", ""); - if ("NONE".equalsIgnoreCase(level)) { - return Connection.TRANSACTION_NONE; - } - if ("READCOMMITTED".equalsIgnoreCase(level)) { - return Connection.TRANSACTION_READ_COMMITTED; - } - if ("READUNCOMMITTED".equalsIgnoreCase(level)) { - return Connection.TRANSACTION_READ_UNCOMMITTED; - } - if ("REPEATABLEREAD".equalsIgnoreCase(level)) { - return Connection.TRANSACTION_REPEATABLE_READ; - } - if ("SERIALIZABLE".equalsIgnoreCase(level)) { - return Connection.TRANSACTION_SERIALIZABLE; - } - - throw new RuntimeException("Transaction Isolation level [" + level + "] is not known."); - } -} diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index cd6e5e755..e51f81cfd 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -22,6 +22,7 @@ import com.avaje.ebean.event.readaudit.ReadAuditLogger; import com.avaje.ebean.event.readaudit.ReadAuditPrepare; import com.avaje.ebean.meta.MetaInfoManager; import com.fasterxml.jackson.core.JsonFactory; +import org.avaje.datasource.DataSourceConfig; import javax.sql.DataSource; import java.util.ArrayList; @@ -1391,8 +1392,6 @@ public class ServerConfig { *

* Values are oracle, h2, postgres, mysql, mssqlserver2005. *

- * - * @see DataSourceConfig#setOffline(boolean) */ public void setDatabasePlatformName(String databasePlatformName) { this.databasePlatformName = databasePlatformName; @@ -2246,7 +2245,7 @@ public class ServerConfig { * @param p - The defined property source passed to load settings */ protected void loadDataSourceSettings(PropertiesWrapper p) { - dataSourceConfig.loadSettings(p.withPrefix("datasource")); + dataSourceConfig.loadSettings(p.properties, name); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/jdbc/ConnectionDelegator.java b/src/main/java/com/avaje/ebeaninternal/jdbc/ConnectionDelegator.java deleted file mode 100644 index 382728c2a..000000000 --- a/src/main/java/com/avaje/ebeaninternal/jdbc/ConnectionDelegator.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.avaje.ebeaninternal.jdbc; - -import java.sql.Array; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.NClob; -import java.sql.PreparedStatement; -import java.sql.SQLClientInfoException; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.sql.SQLXML; -import java.sql.Savepoint; -import java.sql.Statement; -import java.sql.Struct; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Executor; - -public class ConnectionDelegator implements Connection { - - private final Connection delegate; - - public ConnectionDelegator(Connection delegate) { - this.delegate = delegate; - } - - @Override - public void setSchema(String schema) throws SQLException { - delegate.setSchema(schema); - } - - @Override - public String getSchema() throws SQLException { - return delegate.getSchema(); - } - - @Override - public void abort(Executor executor) throws SQLException { - delegate.abort(executor); - } - - @Override - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - delegate.setNetworkTimeout(executor, milliseconds); - } - - @Override - public int getNetworkTimeout() throws SQLException { - return delegate.getNetworkTimeout(); - } - - public Statement createStatement() throws SQLException { - return delegate.createStatement(); - } - - public PreparedStatement prepareStatement(String sql) throws SQLException { - return delegate.prepareStatement(sql); - } - - public CallableStatement prepareCall(String sql) throws SQLException { - return delegate.prepareCall(sql); - } - - public String nativeSQL(String sql) throws SQLException { - return delegate.nativeSQL(sql); - } - - public void setAutoCommit(boolean autoCommit) throws SQLException { - delegate.setAutoCommit(autoCommit); - } - - public boolean getAutoCommit() throws SQLException { - return delegate.getAutoCommit(); - } - - public void commit() throws SQLException { - delegate.commit(); - } - - public void rollback() throws SQLException { - delegate.rollback(); - } - - public void close() throws SQLException { - delegate.close(); - } - - public boolean isClosed() throws SQLException { - return delegate.isClosed(); - } - - public DatabaseMetaData getMetaData() throws SQLException { - return delegate.getMetaData(); - } - - public void setReadOnly(boolean readOnly) throws SQLException { - delegate.setReadOnly(readOnly); - } - - public boolean isReadOnly() throws SQLException { - return delegate.isReadOnly(); - } - - public void setCatalog(String catalog) throws SQLException { - delegate.setCatalog(catalog); - } - - public String getCatalog() throws SQLException { - return delegate.getCatalog(); - } - - public void setTransactionIsolation(int level) throws SQLException { - delegate.setTransactionIsolation(level); - } - - public int getTransactionIsolation() throws SQLException { - return delegate.getTransactionIsolation(); - } - - public SQLWarning getWarnings() throws SQLException { - return delegate.getWarnings(); - } - - public void clearWarnings() throws SQLException { - delegate.clearWarnings(); - } - - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - return delegate.createStatement(resultSetType, resultSetConcurrency); - } - - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) - throws SQLException { - return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency); - } - - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) - throws SQLException { - return delegate.prepareCall(sql, resultSetType, resultSetConcurrency); - } - - public Map> getTypeMap() throws SQLException { - return delegate.getTypeMap(); - } - - public void setTypeMap(Map> map) throws SQLException { - delegate.setTypeMap(map); - } - - public void setHoldability(int holdability) throws SQLException { - delegate.setHoldability(holdability); - } - - public int getHoldability() throws SQLException { - return delegate.getHoldability(); - } - - public Savepoint setSavepoint() throws SQLException { - return delegate.setSavepoint(); - } - - public Savepoint setSavepoint(String name) throws SQLException { - return delegate.setSavepoint(name); - } - - public void rollback(Savepoint savepoint) throws SQLException { - delegate.rollback(savepoint); - } - - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - delegate.releaseSavepoint(savepoint); - } - - public Statement createStatement(int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - } - - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - return delegate.prepareStatement(sql, autoGeneratedKeys); - } - - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - return delegate.prepareStatement(sql, columnIndexes); - } - - public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - return delegate.prepareStatement(sql, columnNames); - } - - public Clob createClob() throws SQLException { - return delegate.createClob(); - } - - public Blob createBlob() throws SQLException { - return delegate.createBlob(); - } - - public NClob createNClob() throws SQLException { - return delegate.createNClob(); - } - - public SQLXML createSQLXML() throws SQLException { - return delegate.createSQLXML(); - } - - public boolean isValid(int timeout) throws SQLException { - return delegate.isValid(timeout); - } - - public void setClientInfo(String name, String value) throws SQLClientInfoException { - delegate.setClientInfo(name, value); - } - - public void setClientInfo(Properties properties) throws SQLClientInfoException { - delegate.setClientInfo(properties); - } - - public String getClientInfo(String name) throws SQLException { - return delegate.getClientInfo(name); - } - - public Properties getClientInfo() throws SQLException { - return delegate.getClientInfo(); - } - - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - return delegate.createArrayOf(typeName, elements); - } - - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - return delegate.createStruct(typeName, attributes); - } - - public T unwrap(Class iface) throws SQLException { - return delegate.unwrap(iface); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return delegate.isWrapperFor(iface); - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/jdbc/PreparedStatementDelegator.java b/src/main/java/com/avaje/ebeaninternal/jdbc/PreparedStatementDelegator.java deleted file mode 100644 index 47295e583..000000000 --- a/src/main/java/com/avaje/ebeaninternal/jdbc/PreparedStatementDelegator.java +++ /dev/null @@ -1,435 +0,0 @@ -package com.avaje.ebeaninternal.jdbc; - -import java.io.InputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Connection; -import java.sql.Date; -import java.sql.NClob; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.Calendar; - -public class PreparedStatementDelegator implements PreparedStatement { - - private final PreparedStatement delegate; - - public PreparedStatementDelegator(PreparedStatement delegate) { - this.delegate = delegate; - } - - @Override - public void closeOnCompletion() throws SQLException { - delegate.closeOnCompletion(); - } - - @Override - public boolean isCloseOnCompletion() throws SQLException { - return delegate.isCloseOnCompletion(); - } - - public ResultSet executeQuery() throws SQLException { - return delegate.executeQuery(); - } - - public int executeUpdate() throws SQLException { - return delegate.executeUpdate(); - } - - public void setNull(int parameterIndex, int sqlType) throws SQLException { - delegate.setNull(parameterIndex, sqlType); - } - - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - delegate.setBoolean(parameterIndex, x); - } - - public void setByte(int parameterIndex, byte x) throws SQLException { - delegate.setByte(parameterIndex, x); - } - - public void setShort(int parameterIndex, short x) throws SQLException { - delegate.setShort(parameterIndex, x); - } - - public void setInt(int parameterIndex, int x) throws SQLException { - delegate.setInt(parameterIndex, x); - } - - public void setLong(int parameterIndex, long x) throws SQLException { - delegate.setLong(parameterIndex, x); - } - - public void setFloat(int parameterIndex, float x) throws SQLException { - delegate.setFloat(parameterIndex, x); - } - - public void setDouble(int parameterIndex, double x) throws SQLException { - delegate.setDouble(parameterIndex, x); - } - - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { - delegate.setBigDecimal(parameterIndex, x); - } - - public void setString(int parameterIndex, String x) throws SQLException { - delegate.setString(parameterIndex, x); - } - - public void setBytes(int parameterIndex, byte[] x) throws SQLException { - delegate.setBytes(parameterIndex, x); - } - - public void setDate(int parameterIndex, Date x) throws SQLException { - delegate.setDate(parameterIndex, x); - } - - public void setTime(int parameterIndex, Time x) throws SQLException { - delegate.setTime(parameterIndex, x); - } - - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - delegate.setTimestamp(parameterIndex, x); - } - - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - delegate.setAsciiStream(parameterIndex, x, length); - } - - @SuppressWarnings("deprecation") - public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { - delegate.setUnicodeStream(parameterIndex, x, length); - } - - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - delegate.setBinaryStream(parameterIndex, x, length); - } - - public void clearParameters() throws SQLException { - delegate.clearParameters(); - } - - public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { - delegate.setObject(parameterIndex, x, targetSqlType); - } - - public void setObject(int parameterIndex, Object x) throws SQLException { - delegate.setObject(parameterIndex, x); - } - - public boolean execute() throws SQLException { - return delegate.execute(); - } - - public void addBatch() throws SQLException { - delegate.addBatch(); - } - - public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { - delegate.setCharacterStream(parameterIndex, reader, length); - } - - public void setRef(int parameterIndex, Ref x) throws SQLException { - delegate.setRef(parameterIndex, x); - } - - public void setBlob(int parameterIndex, Blob x) throws SQLException { - delegate.setBlob(parameterIndex, x); - } - - public void setClob(int parameterIndex, Clob x) throws SQLException { - delegate.setClob(parameterIndex, x); - } - - public void setArray(int parameterIndex, Array x) throws SQLException { - delegate.setArray(parameterIndex, x); - } - - public ResultSetMetaData getMetaData() throws SQLException { - return delegate.getMetaData(); - } - - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - delegate.setDate(parameterIndex, x, cal); - } - - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { - delegate.setTime(parameterIndex, x, cal); - } - - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - delegate.setTimestamp(parameterIndex, x, cal); - } - - public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { - delegate.setNull(parameterIndex, sqlType, typeName); - } - - public void setURL(int parameterIndex, URL x) throws SQLException { - delegate.setURL(parameterIndex, x); - } - - public ParameterMetaData getParameterMetaData() throws SQLException { - return delegate.getParameterMetaData(); - } - - public void setRowId(int parameterIndex, RowId x) throws SQLException { - delegate.setRowId(parameterIndex, x); - } - - public void setNString(int parameterIndex, String value) throws SQLException { - delegate.setNString(parameterIndex, value); - } - - public void setNCharacterStream(int parameterIndex, Reader value, long length) - throws SQLException { - delegate.setNCharacterStream(parameterIndex, value, length); - } - - public void setNClob(int parameterIndex, NClob value) throws SQLException { - delegate.setNClob(parameterIndex, value); - } - - public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { - delegate.setClob(parameterIndex, reader, length); - } - - public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { - delegate.setBlob(parameterIndex, inputStream, length); - } - - public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { - delegate.setNClob(parameterIndex, reader, length); - } - - public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { - delegate.setSQLXML(parameterIndex, xmlObject); - } - - public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) - throws SQLException { - delegate.setObject(parameterIndex, x, targetSqlType, scaleOrLength); - } - - public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { - delegate.setAsciiStream(parameterIndex, x, length); - } - - public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { - delegate.setBinaryStream(parameterIndex, x, length); - } - - public void setCharacterStream(int parameterIndex, Reader reader, long length) - throws SQLException { - delegate.setCharacterStream(parameterIndex, reader, length); - } - - public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { - delegate.setAsciiStream(parameterIndex, x); - } - - public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { - delegate.setBinaryStream(parameterIndex, x); - } - - public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { - delegate.setCharacterStream(parameterIndex, reader); - } - - public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { - delegate.setNCharacterStream(parameterIndex, value); - } - - public void setClob(int parameterIndex, Reader reader) throws SQLException { - delegate.setClob(parameterIndex, reader); - } - - public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { - delegate.setBlob(parameterIndex, inputStream); - } - - public void setNClob(int parameterIndex, Reader reader) throws SQLException { - delegate.setNClob(parameterIndex, reader); - } - - public ResultSet executeQuery(String sql) throws SQLException { - return delegate.executeQuery(sql); - } - - public int executeUpdate(String sql) throws SQLException { - return delegate.executeUpdate(sql); - } - - public void close() throws SQLException { - delegate.close(); - } - - public int getMaxFieldSize() throws SQLException { - return delegate.getMaxFieldSize(); - } - - public void setMaxFieldSize(int max) throws SQLException { - delegate.setMaxFieldSize(max); - } - - public int getMaxRows() throws SQLException { - return delegate.getMaxRows(); - } - - public void setMaxRows(int max) throws SQLException { - delegate.setMaxRows(max); - } - - public void setEscapeProcessing(boolean enable) throws SQLException { - delegate.setEscapeProcessing(enable); - } - - public int getQueryTimeout() throws SQLException { - return delegate.getQueryTimeout(); - } - - public void setQueryTimeout(int seconds) throws SQLException { - delegate.setQueryTimeout(seconds); - } - - public void cancel() throws SQLException { - delegate.cancel(); - } - - public SQLWarning getWarnings() throws SQLException { - return delegate.getWarnings(); - } - - public void clearWarnings() throws SQLException { - delegate.clearWarnings(); - } - - public void setCursorName(String name) throws SQLException { - delegate.setCursorName(name); - } - - public boolean execute(String sql) throws SQLException { - return delegate.execute(sql); - } - - public ResultSet getResultSet() throws SQLException { - return delegate.getResultSet(); - } - - public int getUpdateCount() throws SQLException { - return delegate.getUpdateCount(); - } - - public boolean getMoreResults() throws SQLException { - return delegate.getMoreResults(); - } - - public void setFetchDirection(int direction) throws SQLException { - delegate.setFetchDirection(direction); - } - - public int getFetchDirection() throws SQLException { - return delegate.getFetchDirection(); - } - - public void setFetchSize(int rows) throws SQLException { - delegate.setFetchSize(rows); - } - - public int getFetchSize() throws SQLException { - return delegate.getFetchSize(); - } - - public int getResultSetConcurrency() throws SQLException { - return delegate.getResultSetConcurrency(); - } - - public int getResultSetType() throws SQLException { - return delegate.getResultSetType(); - } - - public void addBatch(String sql) throws SQLException { - delegate.addBatch(sql); - } - - public void clearBatch() throws SQLException { - delegate.clearBatch(); - } - - public int[] executeBatch() throws SQLException { - return delegate.executeBatch(); - } - - public Connection getConnection() throws SQLException { - return delegate.getConnection(); - } - - public boolean getMoreResults(int current) throws SQLException { - return delegate.getMoreResults(current); - } - - public ResultSet getGeneratedKeys() throws SQLException { - return delegate.getGeneratedKeys(); - } - - public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - return delegate.executeUpdate(sql, autoGeneratedKeys); - } - - public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - return delegate.executeUpdate(sql, columnIndexes); - } - - public int executeUpdate(String sql, String[] columnNames) throws SQLException { - return delegate.executeUpdate(sql, columnNames); - } - - public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - return delegate.execute(sql, autoGeneratedKeys); - } - - public boolean execute(String sql, int[] columnIndexes) throws SQLException { - return delegate.execute(sql, columnIndexes); - } - - public boolean execute(String sql, String[] columnNames) throws SQLException { - return delegate.execute(sql, columnNames); - } - - public int getResultSetHoldability() throws SQLException { - return delegate.getResultSetHoldability(); - } - - public boolean isClosed() throws SQLException { - return delegate.isClosed(); - } - - public void setPoolable(boolean poolable) throws SQLException { - delegate.setPoolable(poolable); - } - - public boolean isPoolable() throws SQLException { - return delegate.isPoolable(); - } - - public T unwrap(Class iface) throws SQLException { - return delegate.unwrap(iface); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return delegate.isWrapperFor(iface); - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java index 57e38a5e3..90a9b7c7f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java @@ -6,7 +6,6 @@ import com.avaje.ebean.cache.ServerCacheManager; import com.avaje.ebean.cache.ServerCacheOptions; import com.avaje.ebean.common.SpiContainer; import com.avaje.ebean.config.ContainerConfig; -import com.avaje.ebean.config.DataSourceConfig; import com.avaje.ebean.config.PropertyMap; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.UnderscoreNamingConvention; @@ -18,10 +17,10 @@ import com.avaje.ebeaninternal.server.cache.DefaultServerCacheFactory; import com.avaje.ebeaninternal.server.cache.DefaultServerCacheManager; import com.avaje.ebeaninternal.server.cluster.ClusterManager; import com.avaje.ebeaninternal.server.lib.ShutdownManager; -import com.avaje.ebeaninternal.server.lib.sql.DataSourceAlert; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePoolListener; -import com.avaje.ebeaninternal.server.lib.sql.SimpleDataSourceAlert; +import org.avaje.datasource.DataSourceAlertFactory; +import org.avaje.datasource.DataSourceConfig; +import org.avaje.datasource.DataSourceFactory; +import org.avaje.datasource.DataSourcePoolListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -295,18 +294,32 @@ public class DefaultContainer implements SpiContainer { return null; } - DataSourceAlert notify = new SimpleDataSourceAlert(); - DataSourcePoolListener listener = createListener(config, dsConfig); + DataSourceFactory factory = config.service(DataSourceFactory.class); + if (factory == null) { + throw new IllegalStateException("No DataSourceFactory service implementation found in class path." + + " Probably missing dependency to avaje-datasource?"); + } - return new DataSourcePool(notify, config.getName(), dsConfig, listener); + DataSourceAlertFactory alertFactory = config.service(DataSourceAlertFactory.class); + if (alertFactory != null) { + dsConfig.setAlert(alertFactory.createAlert()); + } + + attachListener(config, dsConfig); + + return factory.createPool(config.getName(), dsConfig); } /** - * Create and return a DataSourcePoolListener if it has been specified. + * Create and attach a DataSourcePoolListener if it has been specified via properties and there is not one already attached. */ - private DataSourcePoolListener createListener(ServerConfig config, DataSourceConfig dsConfig) { - String poolListener = dsConfig.getPoolListener(); - return poolListener != null ? (DataSourcePoolListener) config.getClassLoadConfig().newInstance(poolListener) : null; + private void attachListener(ServerConfig config, DataSourceConfig dsConfig) { + if (dsConfig.getListener() == null) { + String poolListener = dsConfig.getPoolListener(); + if (poolListener != null) { + dsConfig.setListener((DataSourcePoolListener)config.getClassLoadConfig().newInstance(poolListener)); + } + } } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java index e0e56ef3c..7a792ea43 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java @@ -29,7 +29,7 @@ import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties; import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit; import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil; import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool; +import org.avaje.datasource.DataSourcePool; import com.avaje.ebeaninternal.server.persist.Binder; import com.avaje.ebeaninternal.server.persist.DefaultPersister; import com.avaje.ebeaninternal.server.query.CQueryEngine; @@ -361,7 +361,7 @@ public class InternalConfiguration { return true; } DataSource dataSource = serverConfig.getDataSource(); - return dataSource instanceof DataSourcePool && ((DataSourcePool) dataSource).getAutoCommit(); + return dataSource instanceof DataSourcePool && ((DataSourcePool) dataSource).isAutoCommit(); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java deleted file mode 100644 index 807377612..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/BusyConnectionBuffer.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues; - -/** - * A buffer especially designed for Busy PooledConnections. - *

- * All thread safety controlled externally (by PooledConnectionQueue). - *

- *

- * It has a set of 'slots' and PooledConnections know which slot they went into - * and this allows for fast addition and removal (by slotId without looping). - * The capacity will increase on demand by the 'growBy' amount. - *

- * - * @author rbygrave - */ -class BusyConnectionBuffer { - - private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class); - - private PooledConnection[] slots; - - private final int growBy; - - private int size; - - private int pos = -1; - - /** - * Create the buffer with an initial capacity and fixed growBy. - * We generally do not want the buffer to grow very often. - * - * @param capacity the initial capacity - * @param growBy the fixed amount to grow the buffer by. - */ - protected BusyConnectionBuffer(int capacity, int growBy) { - this.slots = new PooledConnection[capacity]; - this.growBy = growBy; - } - - /** - * We can only grow (not shrink) the capacity. - */ - protected void setCapacity(int newCapacity) { - if (newCapacity > slots.length) { - PooledConnection[] current = this.slots; - this.slots = new PooledConnection[newCapacity]; - System.arraycopy(current, 0, this.slots, 0, current.length); - } - } - - public String toString() { - return Arrays.toString(slots); - } - - protected int getCapacity() { - return slots.length; - } - - protected int size() { - return size; - } - - protected boolean isEmpty() { - return size == 0; - } - - protected int add(PooledConnection pc) { - if (size == slots.length) { - // grow the capacity - setCapacity(slots.length + growBy); - } - int slot = nextEmptySlot(); - pc.setSlotId(slot); - slots[slot] = pc; - return ++size; - } - - protected boolean remove(PooledConnection pc) { - - int slotId = pc.getSlotId(); - if (slots[slotId] != pc) { - PooledConnection heldBy = slots[slotId]; - logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy); - return false; - } - slots[slotId] = null; - --size; - return true; - } - - /** - * Collect the load statistics from all the busy connections. - */ - void collectStatistics(LoadValues values, boolean reset) { - - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null) { - values.plus(slots[i].getStatistics().getValues(reset)); - } - } - } - - /** - * Close connections that should be considered leaked. - */ - void closeBusyConnections(long leakTimeMinutes) { - - long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes * 60000); - - logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes); - - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null) { - //tmp.add(slots[i]); - PooledConnection pc = slots[i]; - //noinspection StatementWithEmptyBody - if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) { - // PooledConnection has been used recently or - // expected to be longRunning so not closing... - } else { - slots[i] = null; - --size; - closeBusyConnection(pc); - } - } - } - } - - private void closeBusyConnection(PooledConnection pc) { - try { - - logger.warn("DataSourcePool closing busy connection? " + pc.getFullDescription()); - System.out.println("CLOSING busy connection: " + pc.getFullDescription()); - - pc.closeConnectionFully(false); - - } catch (Exception ex) { - // this should never actually happen - logger.error("Error when closing potentially leaked connection " + pc.getDescription(), ex); - } - } - - /** - * Returns information describing connections that are currently being used. - */ - String getBusyConnectionInformation(boolean toLogger) { - - if (toLogger) { - logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size()); - } - - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < slots.length; i++) { - if (slots[i] != null) { - PooledConnection pc = slots[i]; - if (toLogger) { - logger.info("Busy Connection - {}", pc.getFullDescription()); - } else { - sb.append(pc.getFullDescription()).append("\r\n"); - } - } - } - - return sb.toString(); - } - - - /** - * Return the position of the next empty slot. - */ - private int nextEmptySlot() { - - // search forward - while (++pos < slots.length) { - if (slots[pos] == null) { - return pos; - } - } - // search from beginning - pos = -1; - while (++pos < slots.length) { - if (slots[pos] == null) { - return pos; - } - } - - // not expecting this - throw new RuntimeException("No Empty Slot Found?"); - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java deleted file mode 100644 index 863defa15..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourceAlert.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -/** - * Listener for notifications about the DataSource such as when the DataSource - * goes down, up or gets close to it's maximum size. - *

- * The intention is to send email notifications to an administrator (or similar) - * when these events occur on the DataSource. - *

- */ -public interface DataSourceAlert { - - /** - * Send an alert to say the dataSource is back up. - */ - void dataSourceUp(String dataSourceName); - - /** - * Send an alert to say the dataSource is down. - */ - void dataSourceDown(String dataSourceName); - - /** - * Send an alert to say the dataSource is getting close to its max size. - */ - void dataSourceWarning(String subject, String msg); -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java deleted file mode 100644 index 4cd196b0b..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePool.java +++ /dev/null @@ -1,1003 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import com.avaje.ebean.config.DataSourceConfig; -import com.avaje.ebeaninternal.api.ClassUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.persistence.PersistenceException; -import javax.sql.DataSource; -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.Statement; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; - -/** - * A robust DataSource. - *

- *

    - *
  • Manages the number of connections closing connections that have been idle - * for some time. - *
  • Notifies when the datasource goes down and comes back up. - *
  • Checks for expected downtime which is useful for schedule db backups. - *
  • Provides PreparedStatement caching - *
  • Knows the busy connections - *
  • Traces connections that have been leaked - *
- *

- */ -public class DataSourcePool implements DataSource { - - private static final Logger logger = LoggerFactory.getLogger(DataSourcePool.class); - - /** - * The name given to this dataSource. - */ - private final String name; - - /** - * Used to notify of changes to the DataSource status. - */ - private final DataSourceAlert notify; - - /** - * Optional listener that can be notified when connections are got from and - * put back into the pool. - */ - private final DataSourcePoolListener poolListener; - - /** - * Properties used to create a Connection. - */ - private final Properties connectionProps; - - /** - * The jdbc connection url. - */ - private final String databaseUrl; - - /** - * The jdbc driver. - */ - private final String databaseDriver; - - /** - * The sql used to test a connection. - */ - private final String heartbeatsql; - - private final int heartbeatFreqSecs; - - private final int heartbeatTimeoutSeconds; - - - private final long trimPoolFreqMillis; - - /** - * The transaction isolation level as per java.sql.Connection. - */ - private final int transactionIsolation; - - /** - * The default autoCommit setting for Connections in this pool. - */ - private final boolean autoCommit; - - /** - * Max idle time in millis. - */ - private final int maxInactiveMillis; - - /** - * Max age a connection is allowed in millis. - * A value of 0 means no limit (no trimming based on max age). - */ - private final long maxAgeMillis; - - /** - * Flag set to true to capture stackTraces (can be expensive). - */ - private boolean captureStackTrace; - - /** - * The max size of the stack trace to report. - */ - private final int maxStackTraceSize; - - /** - * flag to indicate we have sent an alert message. - */ - private boolean dataSourceDownAlertSent; - - /** - * The time the pool was last trimmed. - */ - private long lastTrimTime; - - /** - * Assume that the DataSource is up. heartBeat checking will discover when - * it goes down, and comes back up again. - */ - private boolean dataSourceUp = true; - - /** - * The current alert. - */ - private boolean inWarningMode; - - /** - * The minimum number of connections this pool will maintain. - */ - private int minConnections; - - /** - * The maximum number of connections this pool will grow to. - */ - private int maxConnections; - - /** - * The number of connections to exceed before a warning Alert is fired. - */ - private int warningSize; - - /** - * The time a thread will wait for a connection to become available. - */ - private final int waitTimeoutMillis; - - /** - * The size of the preparedStatement cache; - */ - private int pstmtCacheSize; - - private final PooledConnectionQueue queue; - - /** - * Used to find and close() leaked connections. Leaked connections are - * thought to be busy but have not been used for some time. Each time a - * connection is used it sets it's lastUsedTime. - */ - private long leakTimeMinutes; - - private final Runnable heartbeatRunnable = new HeartBeatRunnable(); - - public DataSourcePool(DataSourceAlert notify, String name, DataSourceConfig params) { - this(notify, name, params, null); - } - - public DataSourcePool(DataSourceAlert notify, String name, DataSourceConfig params, DataSourcePoolListener listener) { - - this.notify = notify; - this.name = name; - this.poolListener = listener; - - this.autoCommit = params.isAutoCommit(); - this.transactionIsolation = params.getIsolationLevel(); - - this.maxInactiveMillis = 1000 * params.getMaxInactiveTimeSecs(); - this.maxAgeMillis = 60000 * params.getMaxAgeMinutes(); - this.leakTimeMinutes = params.getLeakTimeMinutes(); - this.captureStackTrace = params.isCaptureStackTrace(); - this.maxStackTraceSize = params.getMaxStackTraceSize(); - this.databaseDriver = params.getDriver(); - this.databaseUrl = params.getUrl(); - this.pstmtCacheSize = params.getPstmtCacheSize(); - - this.minConnections = params.getMinConnections(); - this.maxConnections = params.getMaxConnections(); - this.waitTimeoutMillis = params.getWaitTimeoutMillis(); - this.heartbeatsql = params.getHeartbeatSql(); - this.heartbeatFreqSecs = params.getHeartbeatFreqSecs(); - this.heartbeatTimeoutSeconds = params.getHeartbeatTimeoutSeconds(); - this.trimPoolFreqMillis = 1000 * params.getTrimPoolFreqSecs(); - - queue = new PooledConnectionQueue(this); - - String un = params.getUsername(); - String pw = params.getPassword(); - if (un == null) { - throw new RuntimeException("DataSource user is null?"); - } - if (pw == null) { - throw new RuntimeException("DataSource password is null?"); - } - this.connectionProps = new Properties(); - this.connectionProps.setProperty("user", un); - this.connectionProps.setProperty("password", pw); - - Map customProperties = params.getCustomProperties(); - if (customProperties != null) { - Set> entrySet = customProperties.entrySet(); - for (Entry entry : entrySet) { - this.connectionProps.setProperty(entry.getKey(), entry.getValue()); - } - } - - try { - initialise(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - class HeartBeatRunnable implements Runnable { - @Override - public void run() { - checkDataSource(); - } - } - - - @Override - public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException("We do not support java.util.logging"); - } - - private void initialise() throws SQLException { - - // Ensure database driver is loaded - try { - ClassUtil.forName(this.databaseDriver); - } catch (Throwable e) { - throw new PersistenceException("Problem loading Database Driver [" + this.databaseDriver + "]: " + e.getMessage(), e); - } - - String transIsolation = TransactionIsolation.getLevelDescription(transactionIsolation); - //noinspection StringBufferReplaceableByString - StringBuilder sb = new StringBuilder(70); - sb.append("DataSourcePool [").append(name); - sb.append("] autoCommit[").append(autoCommit); - sb.append("] transIsolation[").append(transIsolation); - sb.append("] min[").append(minConnections); - sb.append("] max[").append(maxConnections).append("]"); - - logger.info(sb.toString()); - - queue.ensureMinimumConnections(); - } - - /** - * Returns false. - */ - public boolean isWrapperFor(Class arg0) throws SQLException { - return false; - } - - /** - * Not Implemented. - */ - public T unwrap(Class arg0) throws SQLException { - throw new SQLException("Not Implemented"); - } - - /** - * Return the dataSource name. - */ - public String getName() { - return name; - } - - /** - * Return the max size of stack traces used when trying to find connection pool leaks. - *

- * This is only used when {@link #isCaptureStackTrace()} is true. - *

- */ - int getMaxStackTraceSize() { - return maxStackTraceSize; - } - - /** - * Returns false when the dataSource is down. - */ - public boolean isDataSourceUp() { - return dataSourceUp; - } - - /** - * Called when the pool hits the warning level. - */ - protected void notifyWarning(String msg) { - - if (!inWarningMode) { - // send an Error to the event log... - inWarningMode = true; - logger.warn(msg); - if (notify != null) { - String subject = "DataSourcePool [" + name + "] warning"; - notify.dataSourceWarning(subject, msg); - } - } - } - - private void notifyDataSourceIsDown(SQLException ex) { - - if (!dataSourceDownAlertSent) { - logger.error("FATAL: DataSourcePool [" + name + "] is down or has network error!!!", ex); - if (notify != null) { - notify.dataSourceDown(name); - } - dataSourceDownAlertSent = true; - } - if (dataSourceUp) { - reset(); - } - dataSourceUp = false; - } - - private void notifyDataSourceIsUp() { - if (dataSourceDownAlertSent) { - logger.error("RESOLVED FATAL: DataSourcePool [" + name + "] is back up!"); - if (notify != null) { - notify.dataSourceUp(name); - } - dataSourceDownAlertSent = false; - - } else if (!dataSourceUp) { - logger.info("DataSourcePool [" + name + "] is back up!"); - } - - if (!dataSourceUp) { - dataSourceUp = true; - reset(); - } - } - - - /** - * Return the heartbeat frequency in seconds. - *

- * This is the frequency that the heartbeat runnable should be run. - *

- */ - public int getHeartbeatFreqSecs() { - return heartbeatFreqSecs; - } - - /** - * Returns the Runnable used to check the dataSource using a heartbeat query. - */ - public Runnable getHeartbeatRunnable() { - return heartbeatRunnable; - } - - /** - * Trim connections (in the free list) based on idle time and maximum age. - */ - private void trimIdleConnections() { - if (System.currentTimeMillis() > (lastTrimTime + trimPoolFreqMillis)) { - try { - queue.trim(maxInactiveMillis, maxAgeMillis); - lastTrimTime = System.currentTimeMillis(); - } catch (Exception e) { - logger.error("Error trying to trim idle connections", e); - } - } - } - - /** - * Check the dataSource is up. Trim connections. - *

- * This is called by the HeartbeatRunnable which should be scheduled to - * run periodically (every heartbeatFreqSecs seconds actually). - *

- */ - private void checkDataSource() { - - // first trim idle connections - trimIdleConnections(); - - Connection conn = null; - try { - // Get a connection from the pool and test it - conn = getConnection(); - if (testConnection(conn)) { - notifyDataSourceIsUp(); - - } else { - notifyDataSourceIsDown(null); - } - - } catch (SQLException ex) { - notifyDataSourceIsDown(ex); - - } finally { - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ex) { - logger.warn("Can't close connection in checkDataSource!"); - } - } - } - - /** - * Create a Connection that will not be part of the connection pool. - *

- *

- * When this connection is closed it will not go back into the pool. - *

- *

- *

- * If withDefaults is true then the Connection will have the autoCommit and - * transaction isolation set to the defaults for the pool. - *

- */ - public Connection createUnpooledConnection() throws SQLException { - - try { - Connection conn = DriverManager.getConnection(databaseUrl, connectionProps); - conn.setAutoCommit(autoCommit); - conn.setTransactionIsolation(transactionIsolation); - return conn; - - } catch (SQLException ex) { - notifyDataSourceIsDown(null); - throw ex; - } - } - - /** - * Set a new maximum size. The pool should respect this new maximum - * immediately and not require a restart. You may want to increase the - * maxConnections if the pool gets large and hits the warning level. - */ - public void setMaxSize(int max) { - queue.setMaxSize(max); - this.maxConnections = max; - } - - /** - * Return the max size this pool can grow to. - */ - public int getMaxSize() { - return maxConnections; - } - - /** - * Set the min size this pool should maintain. - */ - public void setMinSize(int min) { - queue.setMinSize(min); - this.minConnections = min; - } - - /** - * Return the min size this pool should maintain. - */ - public int getMinSize() { - return minConnections; - } - - /** - * Set a new maximum size. The pool should respect this new maximum - * immediately and not require a restart. You may want to increase the - * maxConnections if the pool gets large and hits the warning and or alert - * levels. - */ - public void setWarningSize(int warningSize) { - queue.setWarningSize(warningSize); - this.warningSize = warningSize; - } - - /** - * Return the warning size. When the pool hits this size it can send a - * notify message to an administrator. - */ - public int getWarningSize() { - return warningSize; - } - - /** - * Return the time in millis that threads will wait when the pool has hit - * the max size. These threads wait for connections to be returned by the - * busy connections. - */ - public int getWaitTimeoutMillis() { - return waitTimeoutMillis; - } - - /** - * Return the time after which inactive connections are trimmed. - */ - public int getMaxInactiveMillis() { - return maxInactiveMillis; - } - - /** - * Return the maximum age a connection is allowed to be before it is trimmed - * out of the pool. This value can be 0 which means there is no maximum age. - */ - public long getMaxAgeMillis() { - return maxAgeMillis; - } - - private boolean testConnection(Connection conn) throws SQLException { - - if (heartbeatsql == null) { - return conn.isValid(heartbeatTimeoutSeconds); - } - Statement stmt = null; - ResultSet rset = null; - try { - // It should only error IF the DataSource is down or a network issue - stmt = conn.createStatement(); - if (heartbeatTimeoutSeconds > 0) { - stmt.setQueryTimeout(heartbeatTimeoutSeconds); - } - rset = stmt.executeQuery(heartbeatsql); - conn.commit(); - - return true; - - } finally { - try { - if (rset != null) { - rset.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } - try { - if (stmt != null) { - stmt.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } - } - } - - /** - * Make sure the connection is still ok to use. If not then remove it from - * the pool. - */ - boolean validateConnection(PooledConnection conn) { - try { - return testConnection(conn); - - } catch (Exception e) { - logger.warn("heartbeatsql test failed on connection[" + conn.getName() + "]"); - return false; - } - } - - /** - * Called by the PooledConnection themselves, returning themselves to the - * pool when they have been finished with. - *

- * Note that connections may not be added back to the pool if returnToPool - * is false or if they where created before the recycleTime. In both of - * these cases the connection is fully closed and not pooled. - *

- * - * @param pooledConnection the returning connection - */ - void returnConnection(PooledConnection pooledConnection) { - - // return a normal 'good' connection - returnTheConnection(pooledConnection, false); - } - - /** - * This is a bad connection and must be removed from the pool's busy list and fully closed. - */ - void returnConnectionForceClose(PooledConnection pooledConnection) { - - returnTheConnection(pooledConnection, true); - } - - /** - * Return connection. If forceClose is true then this is a bad connection that - * must be removed and closed fully. - */ - private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) { - - if (poolListener != null && !forceClose) { - poolListener.onBeforeReturnConnection(pooledConnection); - } - queue.returnPooledConnection(pooledConnection, forceClose); - - if (forceClose) { - // Got a bad connection so check the pool - checkDataSource(); - } - } - - /** - * Collect statistics of a connection that is fully closing - */ - void reportClosingConnection(PooledConnection pooledConnection) { - - queue.reportClosingConnection(pooledConnection); - } - - /** - * Returns information describing connections that are currently being used. - */ - public String getBusyConnectionInformation() { - - return queue.getBusyConnectionInformation(); - } - - /** - * Dumps the busy connection information to the logs. - *

- * This includes the stackTrace elements if they are being captured. This is - * useful when needing to look a potential connection pool leaks. - *

- */ - public void dumpBusyConnectionInformation() { - - queue.dumpBusyConnectionInformation(); - } - - /** - * Close any busy connections that have not been used for some time. - *

- * These connections are considered to have leaked from the connection pool. - *

- *

- * Connection leaks occur when code doesn't ensure that connections are - * closed() after they have been finished with. There should be an - * appropriate try catch finally block to ensure connections are always - * closed and put back into the pool. - *

- */ - public void closeBusyConnections(long leakTimeMinutes) { - - queue.closeBusyConnections(leakTimeMinutes); - } - - /** - * Grow the pool by creating a new connection. The connection can either be - * added to the available list, or returned. - *

- * This method is protected by synchronization in calling methods. - *

- */ - PooledConnection createConnectionForQueue(int connId) throws SQLException { - - try { - Connection c = createUnpooledConnection(); - - PooledConnection pc = new PooledConnection(this, connId, c); - pc.resetForUse(); - - if (!dataSourceUp) { - notifyDataSourceIsUp(); - } - return pc; - - } catch (SQLException ex) { - notifyDataSourceIsDown(ex); - throw ex; - } - } - - /** - * Close all the connections in the pool. - *

- *

    - *
  • Checks that the database is up. - *
  • Resets the Alert level. - *
  • Closes busy connections that have not been used for some time (aka - * leaks). - *
  • This closes all the currently available connections. - *
  • Busy connections are closed when they are returned to the pool. - *
- *

- */ - public void reset() { - queue.reset(leakTimeMinutes); - inWarningMode = false; - } - - /** - * Return a pooled connection. - */ - public Connection getConnection() throws SQLException { - return getPooledConnection(); - } - - /** - * Get a connection from the pool. - *

- * This will grow the pool if all the current connections are busy. This - * will go into a wait if the pool has hit its maximum size. - *

- */ - private PooledConnection getPooledConnection() throws SQLException { - - PooledConnection c = queue.getPooledConnection(); - - if (captureStackTrace) { - c.setStackTrace(Thread.currentThread().getStackTrace()); - } - - if (poolListener != null) { - poolListener.onAfterBorrowConnection(c); - } - return c; - } - - /** - * Send a message to the DataSourceAlertListener to test it. This is so that - * you can make sure the alerter is configured correctly etc. - */ - public void testAlert() { - - String subject = "Test DataSourcePool [" + name + "]"; - String msg = "Just testing if alert message is sent successfully."; - - if (notify != null) { - notify.dataSourceWarning(subject, msg); - } - } - - /** - * This will close all the free connections, and then go into a wait loop, - * waiting for the busy connections to be freed. - *

- *

- * The DataSources's should be shutdown AFTER thread pools. Leaked - * Connections are not waited on, as that would hang the server. - *

- */ - public void shutdown(boolean deregisterDriver) { - queue.shutdown(); - if (deregisterDriver) { - deregisterDriver(); - } - } - - /** - * Return the default autoCommit setting Connections in this pool will use. - * - * @return true if the pool defaults autoCommit to true - */ - public boolean getAutoCommit() { - return autoCommit; - } - - /** - * Return the default transaction isolation level connections in this pool - * should have. - * - * @return the default transaction isolation level - */ - int getTransactionIsolation() { - return transactionIsolation; - } - - /** - * Return true if the connection pool is currently capturing the StackTrace - * when connections are 'got' from the pool. - *

- * This is set to true to help diagnose connection pool leaks. - *

- */ - public boolean isCaptureStackTrace() { - return captureStackTrace; - } - - /** - * Set this to true means that the StackElements are captured every time a - * connection is retrieved from the pool. This can be used to identify - * connection pool leaks. - */ - public void setCaptureStackTrace(boolean captureStackTrace) { - this.captureStackTrace = captureStackTrace; - } - - /** - * Not implemented and shouldn't be used. - */ - public Connection getConnection(String username, String password) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Not implemented and shouldn't be used. - */ - public int getLoginTimeout() throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Not implemented and shouldn't be used. - */ - public void setLoginTimeout(int seconds) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * Returns null. - */ - public PrintWriter getLogWriter() { - return null; - } - - /** - * Not implemented. - */ - public void setLogWriter(PrintWriter writer) throws SQLException { - throw new SQLException("Method not supported"); - } - - /** - * For detecting and closing leaked connections. Connections that have been - * busy for more than leakTimeMinutes are considered leaks and will be - * closed on a reset(). - *

- * If you want to use a connection for that longer then you should consider - * creating an unpooled connection or setting longRunning to true on that - * connection. - *

- */ - public void setLeakTimeMinutes(long leakTimeMinutes) { - this.leakTimeMinutes = leakTimeMinutes; - } - - /** - * Return the number of minutes after which a busy connection could be - * considered leaked from the connection pool. - */ - public long getLeakTimeMinutes() { - return leakTimeMinutes; - } - - /** - * Return the preparedStatement cache size. - */ - public int getPstmtCacheSize() { - return pstmtCacheSize; - } - - /** - * Set the preparedStatement cache size. - */ - public void setPstmtCacheSize(int pstmtCacheSize) { - this.pstmtCacheSize = pstmtCacheSize; - } - - /** - * Return the current status of the connection pool. - *

- * If you pass reset = true then the counters such as - * hitCount, waitCount and highWaterMark are reset. - *

- */ - public Status getStatus(boolean reset) { - return queue.getStatus(reset); - } - - /** - * Return the aggregated load statistics collected on all the connections in the pool. - */ - public DataSourcePoolStatistics getStatistics(boolean reset) { - - return queue.getStatistics(reset); - } - - /** - * Deregister the JDBC driver. - */ - private void deregisterDriver() { - try { - logger.debug("Deregister the JDBC driver " + this.databaseDriver); - DriverManager.deregisterDriver(DriverManager.getDriver(this.databaseUrl)); - } catch (SQLException e) { - logger.warn("Error trying to deregister the JDBC driver " + this.databaseDriver, e); - } - } - - public static class Status { - - private final String name; - private final int minSize; - private final int maxSize; - private final int free; - private final int busy; - private final int waiting; - private final int highWaterMark; - private final int waitCount; - private final int hitCount; - - protected Status(String name, int minSize, int maxSize, int free, int busy, int waiting, int highWaterMark, - int waitCount, int hitCount) { - this.name = name; - this.minSize = minSize; - this.maxSize = maxSize; - this.free = free; - this.busy = busy; - this.waiting = waiting; - this.highWaterMark = highWaterMark; - this.waitCount = waitCount; - this.hitCount = hitCount; - } - - public String toString() { - return "min[" + minSize + "] max[" + maxSize + "] free[" + free + "] busy[" + busy + "] waiting[" + waiting - + "] highWaterMark[" + highWaterMark + "] waitCount[" + waitCount + "] hitCount[" + hitCount + "]"; - } - - /** - * Return the DataSource name. - */ - public String getName() { - return name; - } - - /** - * Return the min pool size. - */ - public int getMinSize() { - return minSize; - } - - /** - * Return the max pool size. - */ - public int getMaxSize() { - return maxSize; - } - - /** - * Return the current number of free connections in the pool. - */ - public int getFree() { - return free; - } - - /** - * Return the current number of busy connections in the pool. - */ - public int getBusy() { - return busy; - } - - /** - * Return the current number of threads waiting for a connection. - */ - public int getWaiting() { - return waiting; - } - - /** - * Return the high water mark of busy connections. - */ - public int getHighWaterMark() { - return highWaterMark; - } - - /** - * Return the total number of times a thread had to wait. - */ - public int getWaitCount() { - return waitCount; - } - - /** - * Return the total number of times there was an attempt to get a - * connection. - *

- * If the attempt to get a connection failed with a timeout or other - * exception those attempts are still included in this hit count. - *

- */ - public int getHitCount() { - return hitCount; - } - - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java deleted file mode 100644 index 485384557..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.Connection; - - -/** - * A {@link DataSourcePool} listener which allows you to hook on the - * borrow/return process of getting or returning connections from the pool. - *

- * In the configuration use the poolListener key to configure which listener to - * use. - *

- *

- * Example: datasource.ora10.poolListener=my.very.fancy.PoolListener - *

- *

- *

- * Notice: This listener only works if you are using the default Avaje - * {@link DataSourcePool}. - *

- */ -public interface DataSourcePoolListener { - - /** - * Called after a connection has been retrieved from the connection pool - */ - void onAfterBorrowConnection(Connection c); - - /** - * Called before a connection will be put back to the connection pool - */ - void onBeforeReturnConnection(Connection c); - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java deleted file mode 100644 index b3c657e83..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/DataSourcePoolStatistics.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -/** - * Represents aggregated statistics collected from the DataSourcePool. - *

- * The goal is to present insight into the overload load of the DataSourcePool. - * These statistics can be collected and reported regularly to show load over - * time. - *

- *

- * Each pooled connection collects statistics. When a pooled connection is fully - * closed it can report it's statistics to the pool to be included as part of - * the collected statistics. - *

- */ -public class DataSourcePoolStatistics { - - private final long collectionStart; - - private final long count; - - private final long errorCount; - - private final long hwmMicros; - - private final long totalMicros; - - /** - * Construct with statistics collected. - */ - DataSourcePoolStatistics(long collectionStart, long count, long errorCount, long hwmMicros, long totalMicros) { - this.collectionStart = collectionStart; - this.count = count; - this.errorCount = errorCount; - this.hwmMicros = hwmMicros; - this.totalMicros = totalMicros; - } - - public String toString() { - return "count[" + count + "] errors[" + errorCount + "] totalMicros[" + totalMicros + "] hwmMicros[" + hwmMicros - + "] avgMicros[" + getAvgMicros() + "]"; - } - - /** - * Return the start time this set of statistics was collected from. - */ - public long getCollectionStart() { - return collectionStart; - } - - /** - * Return the total number of 'get connection' requests. - */ - public long getCount() { - return count; - } - - /** - * Return the number of SQLExceptions reported. - */ - public long getErrorCount() { - return errorCount; - } - - /** - * Return the high water mark for the duration a connection was busy/used. - */ - public long getHwmMicros() { - return hwmMicros; - } - - /** - * Return the aggregate time connections were busy/used. - */ - public long getTotalMicros() { - return totalMicros; - } - - /** - * Return the average time connections were busy/used. - */ - public long getAvgMicros() { - return (totalMicros == 0) ? 0 : totalMicros / count; - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java deleted file mode 100644 index 75aeb60a5..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedPreparedStatement.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.io.InputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Date; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.Calendar; - -/** - * Extended PreparedStatement that supports caching. - *

- * Designed so that it can be cached by the PooledConnection. It additionally - * notes any Exceptions that occur and this is used to ensure bad connections - * are removed from the connection pool. - *

- */ -public class ExtendedPreparedStatement extends ExtendedStatement implements PreparedStatement { - - /** - * The SQL used to create the underlying PreparedStatement. - */ - private final String sql; - - /** - * The key used to cache this in the connection. - */ - private final String cacheKey; - - /** - * Create a wrapped PreparedStatement that can be cached. - */ - public ExtendedPreparedStatement(PooledConnection pooledConnection, PreparedStatement pstmt, String sql, String cacheKey) { - super(pooledConnection, pstmt); - this.sql = sql; - this.cacheKey = cacheKey; - } - - /** - * Return the key used to cache this on the Connection. - */ - String getCacheKey() { - return cacheKey; - } - - /** - * Return the SQL used to create this PreparedStatement. - */ - public String getSql() { - return sql; - } - - /** - * Fully close the underlying PreparedStatement. After this we can no longer - * reuse the PreparedStatement. - */ - void closeDestroy() throws SQLException { - pstmt.close(); - } - - /** - * Returns the PreparedStatement back into the cache. This doesn't fully - * close the underlying PreparedStatement. - */ - public void close() throws SQLException { - // return the connection back into the cache. - pooledConnection.returnPreparedStatement(this); - } - - /** - * Add the last binding for batch execution. - */ - public void addBatch() throws SQLException { - try { - pstmt.addBatch(); - } catch (SQLException e) { - // we got an error... need to check this - // connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Clear parameters. - */ - public void clearParameters() throws SQLException { - try { - pstmt.clearParameters(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * execute the statement. - */ - public boolean execute() throws SQLException { - try { - return pstmt.execute(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Execute teh query. - */ - public ResultSet executeQuery() throws SQLException { - try { - return pstmt.executeQuery(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Execute the dml statement. - */ - public int executeUpdate() throws SQLException { - try { - return pstmt.executeUpdate(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Return the MetaData for the query. - */ - public ResultSetMetaData getMetaData() throws SQLException { - try { - return pstmt.getMetaData(); - } catch (SQLException e) { - // we got an error... need to check - // this connection before returning it - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Standard PreparedStatement method execution. - */ - public ParameterMetaData getParameterMetaData() throws SQLException { - return pstmt.getParameterMetaData(); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setArray(int i, Array x) throws SQLException { - pstmt.setArray(i, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setAsciiStream(parameterIndex, x, length); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { - pstmt.setBigDecimal(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setBinaryStream(parameterIndex, x, length); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setBlob(int i, Blob x) throws SQLException { - pstmt.setBlob(i, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - pstmt.setBoolean(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setByte(int parameterIndex, byte x) throws SQLException { - pstmt.setByte(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setBytes(int parameterIndex, byte[] x) throws SQLException { - pstmt.setBytes(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setCharacterStream(int parameterIndex, Reader reader, int length) - throws SQLException { - pstmt.setCharacterStream(parameterIndex, reader, length); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setClob(int i, Clob x) throws SQLException { - pstmt.setClob(i, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setDate(int parameterIndex, Date x) throws SQLException { - pstmt.setDate(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - pstmt.setDate(parameterIndex, x, cal); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setDouble(int parameterIndex, double x) throws SQLException { - pstmt.setDouble(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setFloat(int parameterIndex, float x) throws SQLException { - pstmt.setFloat(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setInt(int parameterIndex, int x) throws SQLException { - pstmt.setInt(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setLong(int parameterIndex, long x) throws SQLException { - pstmt.setLong(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setNull(int parameterIndex, int sqlType) throws SQLException { - pstmt.setNull(parameterIndex, sqlType); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException { - pstmt.setNull(paramIndex, sqlType, typeName); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x) throws SQLException { - pstmt.setObject(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { - pstmt.setObject(parameterIndex, x, targetSqlType); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) - throws SQLException { - pstmt.setObject(parameterIndex, x, targetSqlType, scale); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setRef(int i, Ref x) throws SQLException { - pstmt.setRef(i, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setShort(int parameterIndex, short x) throws SQLException { - pstmt.setShort(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setString(int parameterIndex, String x) throws SQLException { - pstmt.setString(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setTime(int parameterIndex, Time x) throws SQLException { - pstmt.setTime(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { - pstmt.setTime(parameterIndex, x, cal); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - pstmt.setTimestamp(parameterIndex, x); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - pstmt.setTimestamp(parameterIndex, x, cal); - } - - /** - * Standard PreparedStatement method execution. - * - * @deprecated - */ - public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { - pstmt.setUnicodeStream(parameterIndex, x, length); - } - - /** - * Standard PreparedStatement method execution. - */ - public void setURL(int parameterIndex, URL x) throws SQLException { - pstmt.setURL(parameterIndex, x); - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java deleted file mode 100644 index ec2d484cd..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/ExtendedStatement.java +++ /dev/null @@ -1,327 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLWarning; - -import com.avaje.ebeaninternal.jdbc.PreparedStatementDelegator; - -/** - * Implements the Statement methods for ExtendedPreparedStatement. - *

- * PreparedStatements should always be used and the intention is that there - * should be no use of Statement at all. The implementation here is generally - * for the case where someone uses the Statement api on an ExtendedPreparedStatement. - *

- */ -abstract class ExtendedStatement extends PreparedStatementDelegator { - - /** - * The pooled connection this Statement belongs to. - */ - final PooledConnection pooledConnection; - - /** - * The underlying Statement that this object wraps. - */ - protected final PreparedStatement pstmt; - - /** - * Create the ExtendedStatement for a given pooledConnection. - */ - ExtendedStatement(PooledConnection pooledConnection, PreparedStatement pstmt) { - super(pstmt); - - this.pooledConnection = pooledConnection; - this.pstmt = pstmt; - } - - /** - * Put the statement back into the statement cache. - */ - public abstract void close() throws SQLException; - - /** - * Return the underlying connection. - */ - public Connection getConnection() throws SQLException { - try { - return pstmt.getConnection(); - } catch (SQLException e) { - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Add the sql for batch execution. - */ - public void addBatch(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - pstmt.addBatch(sql); - } catch (SQLException e) { - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Execute the sql. - */ - public boolean execute(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.execute(sql); - } catch (SQLException e) { - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Execute the query. - */ - public ResultSet executeQuery(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.executeQuery(sql); - } catch (SQLException e) { - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Execute the dml sql. - */ - public int executeUpdate(String sql) throws SQLException { - try { - pooledConnection.setLastStatement(sql); - return pstmt.executeUpdate(sql); - } catch (SQLException e) { - pooledConnection.markWithError(); - throw e; - } - } - - /** - * Standard Statement method call. - */ - public int[] executeBatch() throws SQLException { - return pstmt.executeBatch(); - } - - /** - * Standard Statement method call. - */ - public void cancel() throws SQLException { - pstmt.cancel(); - } - - /** - * Standard Statement method call. - */ - public void clearBatch() throws SQLException { - pstmt.clearBatch(); - } - - /** - * Standard Statement method call. - */ - public void clearWarnings() throws SQLException { - pstmt.clearWarnings(); - } - - /** - * Standard Statement method call. - */ - public int getFetchDirection() throws SQLException { - return pstmt.getFetchDirection(); - } - - /** - * Standard Statement method call. - */ - public int getFetchSize() throws SQLException { - return pstmt.getFetchSize(); - } - - /** - * Standard Statement method call. - */ - public int getMaxFieldSize() throws SQLException { - return pstmt.getMaxFieldSize(); - } - - /** - * Standard Statement method call. - */ - public int getMaxRows() throws SQLException { - return pstmt.getMaxRows(); - } - - /** - * Standard Statement method call. - */ - public boolean getMoreResults() throws SQLException { - return pstmt.getMoreResults(); - } - - /** - * Standard Statement method call. - */ - public int getQueryTimeout() throws SQLException { - return pstmt.getQueryTimeout(); - } - - /** - * Standard Statement method call. - */ - public ResultSet getResultSet() throws SQLException { - return pstmt.getResultSet(); - } - - /** - * Standard Statement method call. - */ - public int getResultSetConcurrency() throws SQLException { - return pstmt.getResultSetConcurrency(); - } - - /** - * Standard Statement method call. - */ - public int getResultSetType() throws SQLException { - return pstmt.getResultSetType(); - } - - /** - * Standard Statement method call. - */ - public int getUpdateCount() throws SQLException { - return pstmt.getUpdateCount(); - } - - /** - * Standard Statement method call. - */ - public SQLWarning getWarnings() throws SQLException { - return pstmt.getWarnings(); - } - - /** - * Standard Statement method call. - */ - public void setCursorName(String name) throws SQLException { - pstmt.setCursorName(name); - } - - /** - * Standard Statement method call. - */ - public void setEscapeProcessing(boolean enable) throws SQLException { - pstmt.setEscapeProcessing(enable); - } - - /** - * Standard Statement method call. - */ - public void setFetchDirection(int direction) throws SQLException { - pstmt.setFetchDirection(direction); - } - - /** - * Standard Statement method call. - */ - public void setFetchSize(int rows) throws SQLException { - pstmt.setFetchSize(rows); - } - - /** - * Standard Statement method call. - */ - public void setMaxFieldSize(int max) throws SQLException { - pstmt.setMaxFieldSize(max); - } - - /** - * Standard Statement method call. - */ - public void setMaxRows(int max) throws SQLException { - pstmt.setMaxRows(max); - } - - /** - * Standard Statement method call. - */ - public void setQueryTimeout(int seconds) throws SQLException { - pstmt.setQueryTimeout(seconds); - } - - /** - * Standard Statement method call. - */ - public boolean getMoreResults(int i) throws SQLException { - return pstmt.getMoreResults(i); - } - - /** - * Standard Statement method call. - */ - public ResultSet getGeneratedKeys() throws SQLException { - return pstmt.getGeneratedKeys(); - } - - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, int i) throws SQLException { - return pstmt.executeUpdate(s, i); - } - - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, int[] i) throws SQLException { - return pstmt.executeUpdate(s, i); - } - - /** - * Standard Statement method call. - */ - public int executeUpdate(String s, String[] i) throws SQLException { - return pstmt.executeUpdate(s, i); - } - - /** - * Standard Statement method call. - */ - public boolean execute(String s, int i) throws SQLException { - return pstmt.execute(s, i); - } - - /** - * Standard Statement method call. - */ - public boolean execute(String s, int[] i) throws SQLException { - return pstmt.execute(s, i); - } - - /** - * Standard Statement method call. - */ - public boolean execute(String s, String[] i) throws SQLException { - return pstmt.execute(s, i); - } - - /** - * Standard Statement method call. - */ - public int getResultSetHoldability() throws SQLException { - return pstmt.getResultSetHoldability(); - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java deleted file mode 100644 index 5676f6509..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/FreeConnectionBuffer.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues; - -/** - * A buffer designed especially to hold free pooled connections. - *

- * All thread safety controlled externally (by PooledConnectionQueue). - *

- */ -class FreeConnectionBuffer { - - private static final Logger logger = LoggerFactory.getLogger(FreeConnectionBuffer.class); - - /** - * Buffer oriented for add and remove. - */ - private final LinkedList freeBuffer = new LinkedList(); - - FreeConnectionBuffer() { - } - - protected int size() { - return freeBuffer.size(); - } - - protected boolean isEmpty() { - return freeBuffer.isEmpty(); - } - - /** - * Add connection to the free list. - */ - protected void add(PooledConnection pc) { - freeBuffer.addLast(pc); - } - - /** - * Remove a connection from the free list. - */ - protected PooledConnection remove() { - return freeBuffer.removeFirst(); - } - - /** - * Close all connections in this buffer. - */ - void closeAll(boolean logErrors) { - - // create a temporary list - List tempList = new ArrayList(freeBuffer.size()); - - // add all the connections into it - for (PooledConnection c : freeBuffer) { - tempList.add(c); - } - - // clear the buffer (in case it takes some time to close these connections). - freeBuffer.clear(); - - logger.debug("... closing all {} connections from the free list with logErrors: {}", tempList.size(), logErrors); - for (int i = 0; i < tempList.size(); i++) { - PooledConnection pooledConnection = tempList.get(i); - logger.debug("... closing {} of {} connections from the free list", i, tempList.size()); - pooledConnection.closeConnectionFully(logErrors); - } - } - - /** - * Trim any inactive connections that have not been used since usedSince. - */ - protected int trim(long usedSince, long createdSince) { - - int trimCount = 0; - - Iterator iterator = freeBuffer.iterator(); - while (iterator.hasNext()) { - PooledConnection pooledConnection = iterator.next(); - if (pooledConnection.shouldTrim(usedSince, createdSince)) { - iterator.remove(); - pooledConnection.closeConnectionFully(true); - trimCount++; - } - } - - return trimCount; - } - - /** - * Collect the load statistics from all the free connections. - */ - void collectStatistics(LoadValues values, boolean reset) { - - for (PooledConnection c : freeBuffer) { - values.plus(c.getStatistics().getValues(reset)); - } - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java deleted file mode 100644 index 2edbc9c02..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnection.java +++ /dev/null @@ -1,970 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.sql.Savepoint; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.avaje.ebeaninternal.jdbc.ConnectionDelegator; - -/** - * Is a connection that belongs to a DataSourcePool. - *

- *

- * It is designed to be part of DataSourcePool. Closing the connection puts it - * back into the pool. - *

- *

- *

- * It defaults autoCommit and Transaction Isolation to the defaults of the - * DataSourcePool. - *

- *

- *

- * It has caching of Statements and PreparedStatements. Remembers the last - * statement that was executed. Keeps statistics on how long it is in use. - *

- */ -public class PooledConnection extends ConnectionDelegator { - - private static final Logger logger = LoggerFactory.getLogger(PooledConnection.class); - - private static final String IDLE_CONNECTION_ACCESSED_ERROR = "Pooled Connection has been accessed whilst idle in the pool, via method: "; - - /** - * Marker for when connection is closed due to exceeding the max allowed age. - */ - private static final String REASON_MAXAGE = "maxAge"; - - /** - * Marker for when connection is closed due to exceeding the max inactive time. - */ - private static final String REASON_IDLE = "idleTime"; - - /** - * Marker for when the connection is closed due to a reset. - */ - private static final String REASON_RESET = "reset"; - - /** - * Set when connection is idle in the pool. In general when in the pool the - * connection should not be modified. - */ - private static final int STATUS_IDLE = 88; - - /** - * Set when connection given to client. - */ - private static final int STATUS_ACTIVE = 89; - - /** - * Set when commit() or rollback() called. - */ - private static final int STATUS_ENDED = 87; - - /** - * Name used to identify the PooledConnection for logging. - */ - private final String name; - - /** - * The pool this connection belongs to. - */ - private final DataSourcePool pool; - - /** - * The underlying connection. - */ - private final Connection connection; - - /** - * The time this connection was created. - */ - private final long creationTime; - - /** - * Cache of the PreparedStatements - */ - private final PstmtCache pstmtCache; - - private final Object pstmtMonitor = new Object(); - - /** - * Helper for statistics collection. - */ - private final PooledConnectionStatistics stats = new PooledConnectionStatistics(); - - /** - * The status of the connection. IDLE, ACTIVE or ENDED. - */ - private int status = STATUS_IDLE; - - /** - * The reason for a connection closing. - */ - private String closeReason; - - /** - * Set this to true if the connection will be busy for a long time. - *

- * This means it should skip the suspected connection pool leak checking. - *

- */ - private boolean longRunning; - - /** - * Flag to indicate that this connection had errors and should be checked to - * make sure it is okay. - */ - private boolean hadErrors; - - /** - * The last start time. When the connection was given to a thread. - */ - private long startUseTime; - - /** - * The last end time of this connection. This is to calculate the usage - * time. - */ - private long lastUseTime; - - private long exeStartNanos; - - /** - * The last statement executed by this connection. - */ - private String lastStatement; - - /** - * The non avaje method that created the connection. - */ - private String createdByMethod; - - /** - * Used to find connection pool leaks. - */ - private StackTraceElement[] stackTrace; - - private final int maxStackTrace; - - /** - * Slot position in the BusyConnectionBuffer. - */ - private int slotId; - - private boolean resetIsolationReadOnlyRequired; - - - /** - * Construct the connection that can refer back to the pool it belongs to. - *

- * close() will return the connection back to the pool , while - * closeDestroy() will close() the underlining connection properly. - *

- */ - public PooledConnection(DataSourcePool pool, int uniqueId, Connection connection) { - super(connection); - - this.pool = pool; - this.connection = connection; - this.name = pool.getName() + "." + uniqueId; - this.pstmtCache = new PstmtCache(pool.getPstmtCacheSize()); - this.maxStackTrace = pool.getMaxStackTraceSize(); - this.creationTime = System.currentTimeMillis(); - this.lastUseTime = creationTime; - } - - /** - * For testing the pool without real connections. - */ - protected PooledConnection(String name) { - super(null); - this.name = name; - this.pool = null; - this.connection = null; - this.pstmtCache = null; - this.maxStackTrace = 0; - this.creationTime = System.currentTimeMillis(); - this.lastUseTime = creationTime; - } - - /** - * Return the slot position in the busy buffer. - */ - int getSlotId() { - return slotId; - } - - /** - * Set the slot position in the busy buffer. - */ - void setSlotId(int slotId) { - this.slotId = slotId; - } - - /** - * Return a string to identify the connection. - */ - public String getName() { - return name; - } - - private String getNameSlot() { - return name + ":" + slotId; - } - - public String toString() { - return getDescription(); - } - - private long getBusySeconds() { - return (System.currentTimeMillis() - startUseTime) / 1000; - } - - public String getDescription() { - return "name[" + name + "] slot[" + slotId + "] startTime[" + getStartUseTime() + "] busySeconds[" + getBusySeconds() + "] createdBy[" + getCreatedByMethod() + "] stmt[" + getLastStatement() + "]"; - } - - String getFullDescription() { - return "name[" + name + "] slot[" + slotId + "] startTime[" + getStartUseTime() + "] busySeconds[" + getBusySeconds() + "] stackTrace[" + getStackTraceAsString() + "] stmt[" + getLastStatement() + "]"; - } - - public PooledConnectionStatistics getStatistics() { - return stats; - } - - /** - * Return true if the connection should be treated as long running (skip connection pool leak check). - */ - boolean isLongRunning() { - return longRunning; - } - - /** - * Set this to true if the connection is a long running connection and should skip the - * 'suspected connection pool leak' checking. - */ - public void setLongRunning(boolean longRunning) { - this.longRunning = longRunning; - } - - /** - * Close the connection fully NOT putting in back into the pool. - *

- * The logErrors parameter exists so that expected errors are not logged - * such as when the database is known to be down. - *

- * - * @param logErrors if false then don't log errors when closing - */ - void closeConnectionFully(boolean logErrors) { - - if (pool != null) { - // allow collection of load statistics - pool.reportClosingConnection(this); - } - - if (logger.isDebugEnabled()) { - logger.debug("Closing Connection[{}] slot[{}] reason[{}] stats: {} , pstmtStats: {} ", name, slotId, closeReason, stats.getValues(false), pstmtCache.getDescription()); - } - - try { - if (connection.isClosed()) { - // Typically the JDBC Driver has its own JVM shutdown hook and already - // closed the connections in our DataSource pool so making this DEBUG level - logger.debug("Closing Connection[{}] that is already closed?", name); - return; - } - } catch (SQLException ex) { - if (logErrors) { - logger.error("Error checking if connection [" + getNameSlot() + "] is closed", ex); - } - } - - try { - for (ExtendedPreparedStatement ps : pstmtCache.values()) { - ps.closeDestroy(); - } - - } catch (SQLException ex) { - if (logErrors) { - logger.warn("Error when closing connection Statements", ex); - } - } - - try { - connection.close(); - } catch (SQLException ex) { - if (logErrors || logger.isDebugEnabled()) { - logger.error("Error when fully closing connection [" + getFullDescription() + "]", ex); - } - } - } - - /** - * Creates a wrapper ExtendedStatement so that I can get the executed sql. I - * want to do this so that I can get the slowest query statments etc, and - * log that information. - */ - public Statement createStatement() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); - } - try { - return connection.createStatement(); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public Statement createStatement(int resultSetType, int resultSetConcurreny) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "createStatement()"); - } - try { - return connection.createStatement(resultSetType, resultSetConcurreny); - - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - /** - * Return a PreparedStatement back into the cache. - */ - void returnPreparedStatement(ExtendedPreparedStatement pstmt) { - - synchronized (pstmtMonitor) { - if (!pstmtCache.returnStatement(pstmt)) { - try { - // Already an entry in the cache with the exact same SQL... - pstmt.closeDestroy(); - - } catch (SQLException e) { - logger.error("Error closing Pstmt", e); - } - } - } - } - - /** - * This will try to use a cache of PreparedStatements. - */ - public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException { - String cacheKey = sql + returnKeysFlag; - return prepareStatement(sql, true, returnKeysFlag, cacheKey); - } - - /** - * This will try to use a cache of PreparedStatements. - */ - public PreparedStatement prepareStatement(String sql) throws SQLException { - return prepareStatement(sql, false, 0, sql); - } - - /** - * This will try to use a cache of PreparedStatements. - */ - private PreparedStatement prepareStatement(String sql, boolean useFlag, int flag, String cacheKey) throws SQLException { - - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); - } - try { - synchronized (pstmtMonitor) { - lastStatement = sql; - - // try to get a matching cached PStmt from the cache. - ExtendedPreparedStatement pstmt = pstmtCache.remove(cacheKey); - - if (pstmt != null) { - return pstmt; - } - - // create a new PreparedStatement - PreparedStatement actualPstmt; - if (useFlag) { - actualPstmt = connection.prepareStatement(sql, flag); - } else { - actualPstmt = connection.prepareStatement(sql); - } - return new ExtendedPreparedStatement(this, actualPstmt, sql, cacheKey); - } - - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurreny) throws SQLException { - - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareStatement()"); - } - try { - // no caching when creating PreparedStatements this way - lastStatement = sql; - return connection.prepareStatement(sql, resultSetType, resultSetConcurreny); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - /** - * Reset the connection for returning to the client. Resets the status, - * startUseTime and hadErrors. - */ - void resetForUse() { - this.status = STATUS_ACTIVE; - this.startUseTime = System.currentTimeMillis(); - this.exeStartNanos = System.nanoTime(); - this.createdByMethod = null; - this.lastStatement = null; - this.hadErrors = false; - this.longRunning = false; - } - - /** - * When an error occurs during use add it the connection. - *

- * Any PooledConnection that has an error is checked to make sure it works - * before it is placed back into the connection pool. - *

- */ - void markWithError() { - hadErrors = true; - } - - /** - * close the connection putting it back into the connection pool. - *

- * Note that to ensure that the next transaction starts at the correct time - * a commit() or rollback() should be called. If neither has occured at this - * time then a rollback() is used (to end the transaction). - *

- *

- * To close the connection fully use closeConnectionFully(). - *

- */ - public void close() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "close()"); - } - - long durationNanos = System.nanoTime() - exeStartNanos; - stats.add(durationNanos, hadErrors); - - if (hadErrors) { - if (!pool.validateConnection(this)) { - // the connection is BAD, remove it, close it and test the pool - pool.returnConnectionForceClose(this); - return; - } - } - - try { - // reset the autoCommit back if client code changed it - if (connection.getAutoCommit() != pool.getAutoCommit()) { - connection.setAutoCommit(pool.getAutoCommit()); - } - // Generally resetting Isolation level seems expensive. - // Hence using resetIsolationReadOnlyRequired flag - // performance reasons. - if (resetIsolationReadOnlyRequired) { - resetIsolationReadOnly(); - resetIsolationReadOnlyRequired = false; - } - - // the connection is assumed GOOD so put it back in the pool - lastUseTime = System.currentTimeMillis(); - // connection.clearWarnings(); - status = STATUS_IDLE; - pool.returnConnection(this); - - } catch (Exception ex) { - // the connection is BAD, remove it, close it and test the pool - logger.warn("Error when trying to return connection to pool, closing fully.", ex); - pool.returnConnectionForceClose(this); - } - } - - private void resetIsolationReadOnly() throws SQLException { - // reset the transaction isolation if the client code changed it - //noinspection MagicConstant - if (connection.getTransactionIsolation() != pool.getTransactionIsolation()) { - //noinspection MagicConstant - connection.setTransactionIsolation(pool.getTransactionIsolation()); - } - // reset readonly to false - if (connection.isReadOnly()) { - connection.setReadOnly(false); - } - } - - protected void finalize() throws Throwable { - try { - if (connection != null && !connection.isClosed()) { - // connect leak? - logger.warn("Closing Connection on finalize() - {}", getFullDescription()); - closeConnectionFully(false); - } - } catch (Exception e) { - logger.error("Error when finalize is closing a connection? (unexpected)", e); - } - super.finalize(); - } - - /** - * Return true if the connection is too old. - */ - private boolean exceedsMaxAge(long maxAgeMillis) { - if (maxAgeMillis > 0 && (creationTime < (System.currentTimeMillis() - maxAgeMillis))) { - this.closeReason = REASON_MAXAGE; - return true; - } - return false; - } - - boolean shouldTrimOnReturn(long lastResetTime, long maxAgeMillis) { - if (creationTime <= lastResetTime) { - this.closeReason = REASON_RESET; - return true; - } - return exceedsMaxAge(maxAgeMillis); - } - - /** - * Return true if the connection has been idle for too long or is too old. - */ - boolean shouldTrim(long usedSince, long createdSince) { - if (lastUseTime < usedSince) { - // been idle for too long so trim it - this.closeReason = REASON_IDLE; - return true; - } - if (createdSince > 0 && createdSince > creationTime) { - // exceeds max age so trim it - this.closeReason = REASON_MAXAGE; - return true; - } - return false; - } - - /** - * Return the time the connection was passed to the client code. - *

- * Used to detect busy connections that could be leaks. - *

- */ - private long getStartUseTime() { - return startUseTime; - } - - /** - * Returns the time the connection was last used. - *

- * Used to close connections that have been idle for some time. Typically 5 - * minutes. - *

- */ - long getLastUsedTime() { - return lastUseTime; - } - - /** - * Returns the last sql statement executed. - */ - private String getLastStatement() { - return lastStatement; - } - - /** - * Called by ExtendedStatement to trace the sql being executed. - *

- * Note with addBatch() this will not really work. - *

- */ - void setLastStatement(String lastStatement) { - this.lastStatement = lastStatement; - if (logger.isTraceEnabled()) { - logger.trace(".setLastStatement[" + lastStatement + "]"); - } - } - - - /** - * Also note the read only status needs to be reset when put back into the - * pool. - */ - public void setReadOnly(boolean readOnly) throws SQLException { - // A bit loose not checking for STATUS_IDLE - // if (status == STATUS_IDLE) { - // throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + - // "setReadOnly()"); - // } - resetIsolationReadOnlyRequired = true; - connection.setReadOnly(readOnly); - } - - /** - * Also note the Isolation level needs to be reset when put back into the - * pool. - */ - public void setTransactionIsolation(int level) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setTransactionIsolation()"); - } - try { - resetIsolationReadOnlyRequired = true; - connection.setTransactionIsolation(level); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - // - // - // Simple wrapper methods which pass a method call onto the acutal - // connection object. These methods are safe-guarded to prevent use of - // the methods whilst the connection is in the connection pool. - // - // - public void clearWarnings() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "clearWarnings()"); - } - connection.clearWarnings(); - } - - public void commit() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "commit()"); - } - try { - status = STATUS_ENDED; - connection.commit(); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public boolean getAutoCommit() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getAutoCommit()"); - } - return connection.getAutoCommit(); - } - - public String getCatalog() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getCatalog()"); - } - return connection.getCatalog(); - } - - public DatabaseMetaData getMetaData() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getMetaData()"); - } - return connection.getMetaData(); - } - - public int getTransactionIsolation() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getTransactionIsolation()"); - } - return connection.getTransactionIsolation(); - } - - public Map> getTypeMap() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getTypeMap()"); - } - return connection.getTypeMap(); - } - - public SQLWarning getWarnings() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "getWarnings()"); - } - return connection.getWarnings(); - } - - public boolean isClosed() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "isClosed()"); - } - return connection.isClosed(); - } - - public boolean isReadOnly() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "isReadOnly()"); - } - return connection.isReadOnly(); - } - - public String nativeSQL(String sql) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "nativeSQL()"); - } - lastStatement = sql; - return connection.nativeSQL(sql); - } - - public CallableStatement prepareCall(String sql) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareCall()"); - } - lastStatement = sql; - return connection.prepareCall(sql); - } - - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurreny) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "prepareCall()"); - } - lastStatement = sql; - return connection.prepareCall(sql, resultSetType, resultSetConcurreny); - } - - public void rollback() throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "rollback()"); - } - try { - status = STATUS_ENDED; - connection.rollback(); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public void setAutoCommit(boolean autoCommit) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setAutoCommit()"); - } - try { - connection.setAutoCommit(autoCommit); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public void setCatalog(String catalog) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setCatalog()"); - } - connection.setCatalog(catalog); - } - - public void setTypeMap(Map> map) throws SQLException { - if (status == STATUS_IDLE) { - throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setTypeMap()"); - } - connection.setTypeMap(map); - } - - public Savepoint setSavepoint() throws SQLException { - try { - return connection.setSavepoint(); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public Savepoint setSavepoint(String savepointName) throws SQLException { - try { - return connection.setSavepoint(savepointName); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public void rollback(Savepoint sp) throws SQLException { - try { - connection.rollback(sp); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public void releaseSavepoint(Savepoint sp) throws SQLException { - try { - connection.releaseSavepoint(sp); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public void setHoldability(int i) throws SQLException { - try { - connection.setHoldability(i); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public int getHoldability() throws SQLException { - try { - return connection.getHoldability(); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public Statement createStatement(int i, int x, int y) throws SQLException { - try { - return connection.createStatement(i, x, y); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public PreparedStatement prepareStatement(String s, int i, int x, int y) throws SQLException { - try { - return connection.prepareStatement(s, i, x, y); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public PreparedStatement prepareStatement(String s, int[] i) throws SQLException { - try { - return connection.prepareStatement(s, i); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public PreparedStatement prepareStatement(String s, String[] s2) throws SQLException { - try { - return connection.prepareStatement(s, s2); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - public CallableStatement prepareCall(String s, int i, int x, int y) throws SQLException { - try { - return connection.prepareCall(s, i, x, y); - } catch (SQLException ex) { - markWithError(); - throw ex; - } - } - - /** - * Returns the method that created the connection. - *

- * Used to help finding connection pool leaks. - *

- */ - private String getCreatedByMethod() { - if (createdByMethod != null) { - return createdByMethod; - } - if (stackTrace == null) { - return null; - } - - for (int j = 0; j < stackTrace.length; j++) { - String methodLine = stackTrace[j].toString(); - if (!skipElement(methodLine)) { - createdByMethod = methodLine; - return createdByMethod; - } - } - - return null; - } - - private boolean skipElement(String methodLine) { - if (methodLine.startsWith("java.lang.")) { - return true; - } else if (methodLine.startsWith("java.util.")) { - return true; - } else if (methodLine.startsWith("com.avaje.ebeaninternal.server.query.CallableQuery.")) { - // creating connection on future... - return true; - } else if (methodLine.startsWith("com.avaje.ebeaninternal.server.query.Callable")) { - // it is a future task being executed... - return false; - } else { - return methodLine.startsWith("com.avaje.ebeaninternal"); - } - } - - /** - * Set the stack trace to help find connection pool leaks. - */ - protected void setStackTrace(StackTraceElement[] stackTrace) { - this.stackTrace = stackTrace; - } - - /** - * Return the stackTrace as a String for logging purposes. - */ - private String getStackTraceAsString() { - StackTraceElement[] stackTrace = getStackTrace(); - if (stackTrace == null) { - return ""; - } - return Arrays.toString(stackTrace); - } - - /** - * Return the full stack trace that got the connection from the pool. You - * could use this if getCreatedByMethod() doesn't work for you. - */ - public StackTraceElement[] getStackTrace() { - - if (stackTrace == null) { - return null; - } - - // filter off the top of the stack that we are not interested in - ArrayList filteredList = new ArrayList(); - boolean include = false; - for (int i = 0; i < stackTrace.length; i++) { - if (!include && !skipElement(stackTrace[i].toString())) { - include = true; - } - if (include && filteredList.size() < maxStackTrace) { - filteredList.add(stackTrace[i]); - } - } - return filteredList.toArray(new StackTraceElement[filteredList.size()]); - - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java deleted file mode 100644 index 3f7818d6f..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionQueue.java +++ /dev/null @@ -1,532 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.SQLException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool.Status; -import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues; - -public class PooledConnectionQueue { - - private static final Logger logger = LoggerFactory.getLogger(PooledConnectionQueue.class); - - private static final TimeUnit MILLIS_TIME_UNIT = TimeUnit.MILLISECONDS; - - private final String name; - - private final DataSourcePool pool; - - /** - * A 'circular' buffer designed specifically for free connections. - */ - private final FreeConnectionBuffer freeList; - - /** - * A 'slots' buffer designed specifically for busy connections. - * Fast add remove based on slot id. - */ - private final BusyConnectionBuffer busyList; - - /** - * Load statistics collected off connections that have closed fully (left the pool). - */ - private final PooledConnectionStatistics collectedStats = new PooledConnectionStatistics(); - - /** - * Currently accumulated load statistics. - */ - private LoadValues accumulatedValues = new LoadValues(); - - /** - * Main lock guarding all access - */ - private final ReentrantLock lock; - - /** - * Condition for threads waiting to take a connection - */ - private final Condition notEmpty; - - private int connectionId; - - private final long waitTimeoutMillis; - - private final long leakTimeMinutes; - - private final long maxAgeMillis; - - private int warningSize; - - private int maxSize; - - private int minSize; - - /** - * Number of threads in the wait queue. - */ - private int waitingThreads; - - /** - * Number of times a thread had to wait. - */ - private int waitCount; - - /** - * Number of times a connection was got from this queue. - */ - private int hitCount; - - /** - * The high water mark for the queue size. - */ - private int highWaterMark; - - /** - * Last time the pool was reset. Used to close busy connections as they are - * returned to the pool that where created prior to the lastResetTime. - */ - private long lastResetTime; - - private boolean doingShutdown; - - public PooledConnectionQueue(DataSourcePool pool) { - - this.pool = pool; - this.name = pool.getName(); - this.minSize = pool.getMinSize(); - this.maxSize = pool.getMaxSize(); - - this.warningSize = pool.getWarningSize(); - this.waitTimeoutMillis = pool.getWaitTimeoutMillis(); - this.leakTimeMinutes = pool.getLeakTimeMinutes(); - this.maxAgeMillis = pool.getMaxAgeMillis(); - - this.busyList = new BusyConnectionBuffer(maxSize, 20); - this.freeList = new FreeConnectionBuffer(); - - this.lock = new ReentrantLock(false); - this.notEmpty = lock.newCondition(); - } - - private Status createStatus() { - return new Status(name, minSize, maxSize, freeList.size(), busyList.size(), waitingThreads, highWaterMark, waitCount, hitCount); - } - - public String toString() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return createStatus().toString(); - } finally { - lock.unlock(); - } - } - - /** - * Collect statistics of a connection that is fully closing - */ - void reportClosingConnection(PooledConnection pooledConnection) { - - collectedStats.add(pooledConnection.getStatistics()); - } - - public DataSourcePoolStatistics getStatistics(boolean reset) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { - - LoadValues aggregate = collectedStats.getValues(reset); - - freeList.collectStatistics(aggregate, reset); - busyList.collectStatistics(aggregate, reset); - - aggregate.plus(accumulatedValues); - - this.accumulatedValues = (reset) ? new LoadValues() : aggregate; - - return new DataSourcePoolStatistics(aggregate.getCollectionStart(), aggregate.getCount(), aggregate.getErrorCount(), aggregate.getHwmMicros(), aggregate.getTotalMicros()); - - } finally { - lock.unlock(); - } - } - - public Status getStatus(boolean reset) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - Status s = createStatus(); - if (reset) { - highWaterMark = busyList.size(); - hitCount = 0; - waitCount = 0; - } - return s; - } finally { - lock.unlock(); - } - } - - void setMinSize(int minSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (minSize > this.maxSize) { - throw new IllegalArgumentException("minSize " + minSize + " > maxSize " + this.maxSize); - } - this.minSize = minSize; - } finally { - lock.unlock(); - } - } - - void setMaxSize(int maxSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (maxSize < this.minSize) { - throw new IllegalArgumentException("maxSize " + maxSize + " < minSize " + this.minSize); - } - this.busyList.setCapacity(maxSize); - this.maxSize = maxSize; - } finally { - lock.unlock(); - } - } - - void setWarningSize(int warningSize) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (warningSize > this.maxSize) { - throw new IllegalArgumentException("warningSize " + warningSize + " > maxSize " + this.maxSize); - } - this.warningSize = warningSize; - } finally { - lock.unlock(); - } - } - - private int totalConnections() { - return freeList.size() + busyList.size(); - } - - void ensureMinimumConnections() throws SQLException { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - int add = minSize - totalConnections(); - if (add > 0) { - for (int i = 0; i < add; i++) { - PooledConnection c = pool.createConnectionForQueue(connectionId++); - freeList.add(c); - } - notEmpty.signal(); - } - - } finally { - lock.unlock(); - } - } - - /** - * Return a PooledConnection. - */ - void returnPooledConnection(PooledConnection c, boolean forceClose) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (!busyList.remove(c)) { - logger.error("Connection [{}] not found in BusyList? ", c); - } - if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) { - c.closeConnectionFully(false); - - } else { - freeList.add(c); - notEmpty.signal(); - } - } finally { - lock.unlock(); - } - } - - private PooledConnection extractFromFreeList() { - PooledConnection c = freeList.remove(); - registerBusyConnection(c); - return c; - } - - PooledConnection getPooledConnection() throws SQLException { - - try { - PooledConnection pc = _getPooledConnection(); - pc.resetForUse(); - return pc; - - } catch (InterruptedException e) { - String msg = "Interrupted getting connection from pool " + e; - throw new SQLException(msg); - } - } - - /** - * Register the PooledConnection with the busyList. - */ - private int registerBusyConnection(PooledConnection c) { - int busySize = busyList.add(c); - if (busySize > highWaterMark) { - highWaterMark = busySize; - } - return busySize; - } - - private PooledConnection _getPooledConnection() throws InterruptedException, SQLException { - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - if (doingShutdown) { - throw new SQLException("Trying to access the Connection Pool when it is shutting down"); - } - - // this includes attempts that fail with InterruptedException - // or SQLException but that is ok as its only an indicator - hitCount++; - - // are other threads already waiting? (they get priority) - if (waitingThreads == 0) { - - if (!freeList.isEmpty()) { - // we have a free connection to return - return extractFromFreeList(); - } - - if (busyList.size() < maxSize) { - // grow the connection pool - PooledConnection c = pool.createConnectionForQueue(connectionId++); - int busySize = registerBusyConnection(c); - - if (logger.isDebugEnabled()) { - logger.debug("DataSourcePool [{}] grow; id[{}] busy[{}] max[{}]", name, c.getName(), busySize, maxSize); - } - checkForWarningSize(); - return c; - } - } - - try { - // The pool is at maximum size. We are going to go into - // a wait loop until connections are returned into the pool. - waitCount++; - waitingThreads++; - return _getPooledConnectionWaitLoop(); - } finally { - waitingThreads--; - } - - } finally { - lock.unlock(); - } - } - - /** - * Got into a loop waiting for connections to be returned to the pool. - */ - private PooledConnection _getPooledConnectionWaitLoop() throws SQLException, InterruptedException { - - long nanos = MILLIS_TIME_UNIT.toNanos(waitTimeoutMillis); - for (; ; ) { - - if (nanos <= 0) { - String msg = "Unsuccessfully waited [" + waitTimeoutMillis + "] millis for a connection to be returned." - + " No connections are free. You need to Increase the max connections of [" + maxSize + "]" - + " or look for a connection pool leak using datasource.xxx.capturestacktrace=true"; - if (pool.isCaptureStackTrace()) { - dumpBusyConnectionInformation(); - } - - throw new SQLException(msg); - } - - try { - nanos = notEmpty.awaitNanos(nanos); - if (!freeList.isEmpty()) { - // successfully waited - return extractFromFreeList(); - } - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to non-interrupted thread - throw ie; - } - } - } - - public void shutdown() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - doingShutdown = true; - Status status = createStatus(); - DataSourcePoolStatistics statistics = pool.getStatistics(false); - logger.debug("DataSourcePool [{}] shutdown {} - Statistics {}", name, status, statistics); - - closeFreeConnections(true); - - if (!busyList.isEmpty()) { - logger.warn("Closing busy connections on shutdown size: " + busyList.size()); - dumpBusyConnectionInformation(); - closeBusyConnections(0); - } - } finally { - lock.unlock(); - } - } - - /** - * Close all the connections in the pool and any current busy connections - * when they are returned. New connections will be then created on demand. - *

- * This is typically done when a database down event occurs. - *

- */ - public void reset(long leakTimeMinutes) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - Status status = createStatus(); - logger.info("Reseting DataSourcePool [{}] {}", name, status); - lastResetTime = System.currentTimeMillis(); - - closeFreeConnections(false); - closeBusyConnections(leakTimeMinutes); - - logger.info("Busy Connections:\n" + getBusyConnectionInformation()); - - } finally { - lock.unlock(); - } - } - - public void trim(long maxInactiveMillis, long maxAgeMillis) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (trimInactiveConnections(maxInactiveMillis, maxAgeMillis) > 0) { - try { - ensureMinimumConnections(); - } catch (SQLException e) { - logger.error("Error trying to ensure minimum connections", e); - } - } - } finally { - lock.unlock(); - } - } - - /** - * Trim connections that have been not used for some time. - */ - private int trimInactiveConnections(long maxInactiveMillis, long maxAgeMillis) { - - long usedSince = System.currentTimeMillis() - maxInactiveMillis; - long createdSince = (maxAgeMillis == 0) ? 0 : System.currentTimeMillis() - maxAgeMillis; - - int trimedCount = freeList.trim(usedSince, createdSince); - if (trimedCount > 0) { - logger.debug("DataSourcePool [{}] trimmed [{}] inactive connections. New size[{}]", name, trimedCount, totalConnections()); - } - return trimedCount; - } - - /** - * Close all the connections that are in the free list. - */ - private void closeFreeConnections(boolean logErrors) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - freeList.closeAll(logErrors); - } finally { - lock.unlock(); - } - } - - /** - * Close any busy connections that have not been used for some time. - *

- * These connections are considered to have leaked from the connection pool. - *

- *

- * Connection leaks occur when code doesn't ensure that connections are - * closed() after they have been finished with. There should be an - * appropriate try catch finally block to ensure connections are always - * closed and put back into the pool. - *

- */ - void closeBusyConnections(long leakTimeMinutes) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { - busyList.closeBusyConnections(leakTimeMinutes); - } finally { - lock.unlock(); - } - } - - /** - * As the pool grows it gets closer to the maxConnections limit. We can send - * an Alert (or warning) as we get close to this limit and hence an - * Administrator could increase the pool size if desired. - *

- * This is called whenever the pool grows in size (towards the max limit). - *

- */ - private void checkForWarningSize() { - - // the the total number of connections that we can add - // to the pool before it hits the maximum - int availableGrowth = (maxSize - totalConnections()); - - if (availableGrowth < warningSize) { - - closeBusyConnections(leakTimeMinutes); - - String msg = "DataSourcePool [" + name + "] is [" + availableGrowth + "] connections from its maximum size."; - pool.notifyWarning(msg); - } - } - - String getBusyConnectionInformation() { - return getBusyConnectionInformation(false); - } - - void dumpBusyConnectionInformation() { - getBusyConnectionInformation(true); - } - - /** - * Returns information describing connections that are currently being used. - */ - private String getBusyConnectionInformation(boolean toLogger) { - - final ReentrantLock lock = this.lock; - lock.lock(); - try { - - return busyList.getBusyConnectionInformation(toLogger); - - } finally { - lock.unlock(); - } - } - -} - diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java deleted file mode 100644 index dd4e96daf..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PooledConnectionStatistics.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Collects load statistics for a PooledConnection. - */ -class PooledConnectionStatistics { - - private final AtomicLong count = new AtomicLong(); - - private final AtomicLong errorCount = new AtomicLong(); - - private final AtomicLong hwmNanos = new AtomicLong(); - - private final AtomicLong totalNanos = new AtomicLong(); - - private final AtomicLong collectionStart; - - PooledConnectionStatistics() { - this.collectionStart = new AtomicLong(System.currentTimeMillis()); - } - - /** - * Add statistics from another collector. - */ - public void add(PooledConnectionStatistics other) { - - errorCount.addAndGet(other.getErrorCount()); - totalNanos.addAndGet(other.totalNanos.get()); - count.addAndGet(other.getCount()); - - final long otherHwm = other.hwmNanos.get(); - if (otherHwm > hwmNanos.get()) { - hwmNanos.set(otherHwm); - } - } - - /** - * Add some time duration to the statistics. - */ - public void add(long durationNanos, boolean hasError) { - - // This will be done in pretty much single threaded fashion - // as the Connections generally are not shared across threads - - if (hasError) { - errorCount.incrementAndGet(); - } - count.incrementAndGet(); - totalNanos.addAndGet(durationNanos); - if (durationNanos > hwmNanos.get()) { - hwmNanos.set(durationNanos); - } - } - - public String toString() { - return "count[" + count + "] errors[" + errorCount + "] totalMicros[" + getTotalMicros() + "] hwmMicros[" + getHwmMicros() + "]"; - } - - public long getCollectionStart() { - return collectionStart.get(); - } - - public long getCount() { - return count.get(); - } - - private long getErrorCount() { - return errorCount.get(); - } - - private long getTotalMicros() { - return TimeUnit.MICROSECONDS.convert(totalNanos.get(), TimeUnit.NANOSECONDS); - } - - private long getHwmMicros() { - return TimeUnit.MICROSECONDS.convert(hwmNanos.get(), TimeUnit.NANOSECONDS); - } - - /** - * Get the current values and reset the statistics if necessary. - */ - LoadValues getValues(boolean reset) { - LoadValues value = new LoadValues(collectionStart.get(), count.get(), errorCount.get(), getHwmMicros(), getTotalMicros()); - if (reset) { - count.set(0); - errorCount.set(0); - hwmNanos.set(0); - totalNanos.set(0); - collectionStart.set(System.currentTimeMillis()); - } - return value; - } - - /** - * Values representing the load or activity of a PooledConnection. - *

- * These are aggregated up to get a total for the DataSourcePool. - *

- */ - static class LoadValues { - - private long collectionStart; - private long count; - private long errorCount; - private long hwmMicros; - private long totalMicros; - - LoadValues() { - } - - LoadValues(long collectionStart, long count, long errorCount, long hwmMicros, long totalMicros) { - this.collectionStart = collectionStart; - this.count = count; - this.errorCount = errorCount; - this.hwmMicros = hwmMicros; - this.totalMicros = totalMicros; - } - - public void plus(LoadValues additional) { - collectionStart = (collectionStart == 0) ? additional.collectionStart : Math.min(collectionStart, additional.collectionStart); - count += additional.count; - errorCount += additional.errorCount; - hwmMicros = Math.max(hwmMicros, additional.hwmMicros); - totalMicros += additional.totalMicros; - } - - public String toString() { - return "count[" + count + "] errors[" + errorCount + "] totalMicros[" + totalMicros + "] hwmMicros[" + hwmMicros + "] avgMicros[" + getAvgMicros() + "]"; - } - - long getCollectionStart() { - return collectionStart; - } - - public long getCount() { - return count; - } - - long getErrorCount() { - return errorCount; - } - - long getHwmMicros() { - return hwmMicros; - } - - long getTotalMicros() { - return totalMicros; - } - - long getAvgMicros() { - return (count == 0) ? 0 : totalMicros / count; - } - } - - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java deleted file mode 100644 index 64b3cd894..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/PstmtCache.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.SQLException; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * A LRU based cache for PreparedStatements. - */ -class PstmtCache extends LinkedHashMap { - - private static final Logger logger = LoggerFactory.getLogger(PstmtCache.class); - - static final long serialVersionUID = -3096406924865550697L; - - /** - * The maximum size of the cache. When this is exceeded the oldest entry is removed. - */ - private final int maxSize; - - /** - * The total number of entries removed from this cache. - */ - private int removeCounter; - - /** - * The number of get hits. - */ - private int hitCounter; - - /** - * The number of get() misses. - */ - private int missCounter; - - /** - * The number of puts into this cache. - */ - private int putCounter; - - PstmtCache(int maxCacheSize) { - // note = access ordered list. This is what gives it the LRU order - super(maxCacheSize * 3, 0.75f, true); - this.maxSize = maxCacheSize; - } - - /** - * Return a summary description of this cache. - */ - public String getDescription() { - return "size[" + size() + "] max[" + maxSize + "] hits[" + hitCounter + "] miss[" + missCounter + "] hitRatio[" + getHitRatio() + "] removes[" + removeCounter + "]"; - } - - /** - * returns the current maximum size of the cache. - */ - public int getMaxSize() { - return maxSize; - } - - /** - * Gets the hit ratio. A number between 0 and 100 indicating the number of - * hits to misses. A number approaching 100 is desirable. - */ - private int getHitRatio() { - if (hitCounter == 0) { - return 0; - } else { - return hitCounter * 100 / (hitCounter + missCounter); - } - } - - /** - * The total number of hits against this cache. - */ - public int getHitCounter() { - return hitCounter; - } - - /** - * The total number of misses against this cache. - */ - public int getMissCounter() { - return missCounter; - } - - /** - * The total number of puts against this cache. - */ - public int getPutCounter() { - return putCounter; - } - - /** - * Try to add the returning statement to the cache. If there is already a - * matching ExtendedPreparedStatement in the cache return false else add - * the statement to the cache and return true. - */ - boolean returnStatement(ExtendedPreparedStatement pstmt) { - - ExtendedPreparedStatement alreadyInCache = super.get(pstmt.getCacheKey()); - if (alreadyInCache != null) { - return false; - } - // add the returning prepared statement to the cache. - // Note that the LRUCache will automatically close fully old unused - // PStmts when the cache has hit its maximum size. - put(pstmt.getCacheKey(), pstmt); - return true; - } - - /** - * additionally maintains hit and miss statistics. - */ - public ExtendedPreparedStatement get(Object key) { - - ExtendedPreparedStatement o = super.get(key); - if (o == null) { - missCounter++; - } else { - hitCounter++; - } - return o; - } - - /** - * additionally maintains hit and miss statistics. - */ - public ExtendedPreparedStatement remove(Object key) { - - ExtendedPreparedStatement o = super.remove(key); - if (o == null) { - missCounter++; - } else { - hitCounter++; - } - return o; - } - - /** - * additionally maintains put counter statistics. - */ - public ExtendedPreparedStatement put(String key, ExtendedPreparedStatement value) { - - putCounter++; - return super.put(key, value); - } - - /** - * will check to see if we need to remove entries and - * if so call the cacheCleanup.cleanupEldestLRUCacheEntry() if - * one has been set. - */ - protected boolean removeEldestEntry(Map.Entry eldest) { - - if (size() < maxSize) { - return false; - } - - removeCounter++; - - try { - ExtendedPreparedStatement pstmt = eldest.getValue(); - pstmt.closeDestroy(); - } catch (SQLException e) { - logger.error("Error closing ExtendedPreparedStatement", e); - } - return true; - } - - -} - diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/SimpleDataSourceAlert.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/SimpleDataSourceAlert.java deleted file mode 100644 index 03af1d41e..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/SimpleDataSourceAlert.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import com.avaje.ebeaninternal.server.lib.util.MailEvent; -import com.avaje.ebeaninternal.server.lib.util.MailListener; -import com.avaje.ebeaninternal.server.lib.util.MailMessage; -import com.avaje.ebeaninternal.server.lib.util.MailSender; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A simple smtp email alert that sends a email message on dataSourceDown and - * dataSourceUp etc. - *
    - *
  • alert.fromuser = the from user name - *
  • alert.fromemail = the from email account - *
  • alert.toemail = comma delimited list of email accounts to email - *
  • alert.mailserver = the smpt server name - *
- */ -public class SimpleDataSourceAlert implements DataSourceAlert, MailListener { - - private static final Logger logger = LoggerFactory.getLogger(SimpleDataSourceAlert.class); - - private static final String alertMailServerName = System.getProperty("ebean.datasource.alert.mailserver"); - - private static final String fromUser = System.getProperty("ebean.datasource.alert.fromUser"); - private static final String fromEmail = System.getProperty("ebean.datasource.alert.fromEmail"); - private static final String toEmail = System.getProperty("ebean.datasource.alert.toEmail"); - - /** - * Create a SimpleAlerter. - */ - public SimpleDataSourceAlert() { - } - - /** - * If the email failed then log the error. - */ - public void handleEvent(MailEvent event) { - Throwable e = event.getError(); - if (e != null) { - logger.error(null, e); - } - } - - /** - * Send the dataSource down alert. - */ - @Override - public void dataSourceDown(String dataSourceName) { - String msg = getSubject(true, dataSourceName); - sendMessage(msg, msg); - } - - /** - * Send the dataSource up alert. - */ - @Override - public void dataSourceUp(String dataSourceName) { - String msg = getSubject(false, dataSourceName); - sendMessage(msg, msg); - } - - /** - * Send the warning message. - */ - @Override - public void dataSourceWarning(String subject, String msg) { - sendMessage(subject, msg); - } - - private String getSubject(boolean isDown, String dsName) { - String msg = "The DataSource " + dsName; - if (isDown) { - msg += " is DOWN!!"; - } else { - msg += " is UP."; - } - return msg; - } - - private void sendMessage(String subject, String msg) { - - if (alertMailServerName == null) { - return; - } - - MailMessage data = new MailMessage(); - data.setSender(fromUser, fromEmail); - data.addBodyLine(msg); - data.setSubject(subject); - - String[] toList = toEmail.split(","); - if (toList.length == 0) { - logger.error("alert.toemail has not been set?"); - } else { - for (int i = 0; i < toList.length; i++) { - data.addRecipient(null, toList[i].trim()); - } - MailSender sender = new MailSender(alertMailServerName); - sender.setMailListener(this); - sender.sendInBackground(data); - } - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java deleted file mode 100644 index bbc7becb9..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/TransactionIsolation.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.Connection; - -/** - * Helper object that can convert between transaction isolation descriptions and values. - */ -class TransactionIsolation { - - /** - * Return the string description of the transaction isolation level specified. - *

Returned value is one of NONE, READ_COMMITTED,READ_UNCOMMITTED, - * REPEATABLE_READ or SERIALIZABLE.

- * - * @param level the transaction isolation level as per java.sql.Connection - * @return the level description as a string. - */ - static String getLevelDescription(int level) { - switch (level) { - case Connection.TRANSACTION_NONE: - return "NONE"; - case Connection.TRANSACTION_READ_COMMITTED: - return "READ_COMMITTED"; - case Connection.TRANSACTION_READ_UNCOMMITTED: - return "READ_UNCOMMITTED"; - case Connection.TRANSACTION_REPEATABLE_READ: - return "REPEATABLE_READ"; - case Connection.TRANSACTION_SERIALIZABLE: - return "SERIALIZABLE"; - case -1: - return "NotSet"; - default: - throw new RuntimeException("Transaction Isolaction level [" + level + "] is not defined."); - } - } - - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/message.properties b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/message.properties deleted file mode 100644 index 8fe526f32..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/message.properties +++ /dev/null @@ -1,20 +0,0 @@ -FATAL_ERROR=ERROR: A fatal error has occured. Check the error log. {0} -DATASOURCE_OK=DataSource {0} working ok. -SHUTTING_DOWN=DataSource shutdown all datasources in [{0}] -SHUT_DOWN_FINISHED=DataSource shutdown has finished. -CANT_FIND_PROPS=ERROR: Can't find the datasource props file. -ERROR_CREATING_FACTORY=ERROR: An error occured when creating the DataSourceFactory {0}. -CANT_SHUTDOWN_TYPE=WARN: Can't shutdown DataSource objects of this type {0}. - -DB_DRIVER_NOTFOUND=ERROR: The JDBC Driver {0} can't be found. -POOL_IN_SHUTDOWN=ERROR: Trying to use the pool while it is shutting down. -WAIT_TIME_EXCEEDED=ERROR: Wait time {0} for connection exceeded. {1}. -SHUTDOWN_START=DataSource [{0}] Shutting down. -SHUTDOWN_LEAK=A Connection leak has been detected on shutdown {0}. -SHUTDOWN_END=DataSource [{0}] Shutdown ended. -METHOD_NOT_SUPPORTED=ERROR: this method is not supported. -SET_ALERT=WARN: Alert {0} has been set. -MISSING_PARAMETER=ERROR: A parameter {0} is missing from the props file. -IDLE_CONNECTION_ACCESSED=Pooled Connection has been accessed whilst idle in the pool, via method: - -DEFAULT_DS_NOT_SPECIFIED=ERROR: No default dataSource has been specified. diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html b/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html deleted file mode 100644 index 6c537f2a6..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/sql/package.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - AvajeLib - - -Enhanced JDBC objects and connection pool. - -

Provides Database meta data objects, Robust connection pooling, PreparedStatement Caching. -

- - \ No newline at end of file diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailAddress.java b/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailAddress.java deleted file mode 100644 index 571014f31..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailAddress.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.util; - -/** - * An Email address with an associated alias. - */ -public class MailAddress { - - - final String alias; - - final String emailAddress; - - /** - * Create an address with an optional alias. - */ - public MailAddress(String alias, String emailAddress) { - this.alias = alias; - this.emailAddress = emailAddress; - } - - /** - * Return the alias. - * If the alias is null this returns an empty string. - */ - public String getAlias() { - if (alias == null) { - return ""; - } - return alias; - } - - /** - * Return the email address. - */ - public String getEmailAddress() { - return emailAddress; - } - - public String toString() { - return getAlias() + " " + "<" + getEmailAddress() + ">"; - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailEvent.java b/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailEvent.java deleted file mode 100644 index 413c63966..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.util; - -/** - * Represents the success or failure of a mail send. - */ -public class MailEvent { - - - /** - * The error indicating a send failure. - */ - final Throwable error; - - /** - * The message that was sent. - */ - final MailMessage message; - - - /** - * The message send failed with an error. - */ - public MailEvent(MailMessage message, Throwable error) { - this.message = message; - this.error = error; - } - - /** - * The message that we attempted to send. - */ - public MailMessage getMailMessage() { - return message; - } - - /** - * Returns true if the message was sent successfully. - */ - public boolean wasSuccessful() { - return (error == null); - } - - /** - * The error indicating the send failed. - */ - public Throwable getError() { - return error; - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailListener.java b/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailListener.java deleted file mode 100644 index 7bde4b328..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.util; - -/** - * Listens to see if the message was successfully sent. - */ -public interface MailListener { - - /** - * Handle the message event. - */ - void handleEvent(MailEvent event); - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailMessage.java b/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailMessage.java deleted file mode 100644 index a88d67c9a..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailMessage.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.util; - - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * A simple test message that can be sent via smtp. - */ -public class MailMessage { - - /** - * The body content. - */ - final ArrayList bodylines; - - /** - * The sender email address. - */ - MailAddress senderAddress; - - /** - * The headers. - */ - final HashMap header = new HashMap(); - - /** - * the recipient of the email. - */ - MailAddress currentRecipient; - - /** - * The list of recipients. - */ - final ArrayList recipientList = new ArrayList(); - - /** - * Create the message. - */ - public MailMessage() { - bodylines = new ArrayList(); - } - - /** - * Set the current recipient. - */ - public void setCurrentRecipient(MailAddress currentRecipient) { - this.currentRecipient = currentRecipient; - } - - /** - * Return the current recipient. - */ - public MailAddress getCurrentRecipient() { - return currentRecipient; - } - - /** - * Add a recipient. - */ - public void addRecipient(String alias, String emailAddress) { - recipientList.add(new MailAddress(alias, emailAddress)); - } - - /** - * Set the sender details. - */ - public void setSender(String alias, String senderEmail) { - this.senderAddress = new MailAddress(alias, senderEmail); - } - - /** - * Return the sender address. - */ - public MailAddress getSender() { - return senderAddress; - } - - /** - * Return the recipient list. - */ - public List getRecipientList() { - return recipientList; - } - - /** - * add a header to the message. - */ - public void addHeader(String key, String val) { - header.put(key, val); - } - - /** - * Set the subject text. - */ - public void setSubject(String subject) { - addHeader("Subject", subject); - } - - /** - * Return the subject text. - */ - public String getSubject() { - return getHeader("Subject"); - } - - /** - * Add text to the body. - */ - public void addBodyLine(String line) { - bodylines.add(line); - } - - /** - * Return the body text. - */ - public List getBodyLines() { - return bodylines; - } - - /** - * Return the headers. - */ - public Collection getHeaderFields() { - return header.keySet(); - } - - /** - * Return a given header. - */ - public String getHeader(String key) { - return header.get(key); - } - - public String toString() { - StringBuilder sb = new StringBuilder(100); - sb.append("Sender: ").append(senderAddress).append("\tRecipient: ").append(recipientList).append("\n"); - for (String key : header.keySet()) { - String hline = key + ": " + header.get(key) + "\n"; - sb.append(hline); - } - sb.append("\n"); - for (String line : bodylines) { - sb.append(line).append("\n"); - } - return sb.toString(); - } -} - - - diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailSender.java b/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailSender.java deleted file mode 100644 index dfdd7a3fa..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/MailSender.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -/** - * Sends simple MailMessages via smtp. - */ -public class MailSender implements Runnable { - - private static final Logger logger = LoggerFactory.getLogger(MailSender.class); - - int traceLevel = 0; - - Socket sserver; - final String server; - - BufferedReader in; - - OutputStreamWriter out; - - MailMessage message; - - MailListener listener = null; - - private static final int SMTP_PORT = 25; - - /** - * Create for a given mail server. - */ - public MailSender(String server) { - this.server = server; - } - - /** - * Set the listener to handle MessageEvents. - */ - public void setMailListener(MailListener listener) { - this.listener = listener; - } - - /** - * Send the message. - */ - public void run() { - send(message); - } - - /** - * Send the message in a background thread. - */ - public void sendInBackground(MailMessage message) { - this.message = message; - Thread thread = new Thread(this); - thread.start(); - } - - /** - * Send the message in the current thread. - */ - public void send(MailMessage message) { - try { - for (MailAddress recipientAddress : message.getRecipientList()) { - sserver = new Socket(server, SMTP_PORT); - send(message, sserver, recipientAddress); - sserver.close(); - - if (listener != null) { - MailEvent event = new MailEvent(message, null); - listener.handleEvent(event); - } - } - } catch (Exception ex) { - if (listener != null) { - MailEvent event = new MailEvent(message, ex); - listener.handleEvent(event); - } else { - logger.error(null, ex); - } - } - } - - private void send(MailMessage message, Socket sserver, MailAddress recipientAddress) throws IOException { - - // A bit convoluted, but doesn't depend on DNS in any way... - InetAddress localhost = sserver.getLocalAddress(); - String localaddress = localhost.getHostAddress(); - MailAddress sender = message.getSender(); - message.setCurrentRecipient(recipientAddress); - - // Mandatory header fields, Date and From - if (message.getHeader("Date") == null) { - message.addHeader("Date", new java.util.Date().toString()); - } - if (message.getHeader("From") == null) { - message.addHeader("From", sender.getAlias() + " <" + sender.getEmailAddress() + ">"); - } - - // if (message.getHeader("From") == null){ - message.addHeader("To", recipientAddress.getAlias() + " <" + recipientAddress.getEmailAddress() + ">"); - // } - - out = new OutputStreamWriter(sserver.getOutputStream()); - in = new BufferedReader(new InputStreamReader(sserver.getInputStream())); - String sintro = readln(); - if (!sintro.startsWith("220")) { // 220 - logger.debug("SmtpSender: intro==" + sintro); - return; - } - - writeln("EHLO " + localaddress); - if (!expect250()) { - return; - } - - writeln("MAIL FROM:<" + sender.getEmailAddress() + ">"); - if (!expect250()) { - return; - } - writeln("RCPT TO:<" + recipientAddress.getEmailAddress() + ">"); - if (!expect250()) { - return; - } - writeln("DATA"); - while (true) { // may be multiple 250 replies pending from server - String line = readln(); - if (line.startsWith("3")) - break; // ready to send - if (!line.startsWith("2")) { - logger.debug("SmtpSender.send reponse to DATA: " + line); - return; - } - } - for (String key : message.getHeaderFields()) { - writeln(key + ": " + message.getHeader(key)); - } - writeln(""); // end of header; - for (String bline : message.getBodyLines()) { - if (bline.startsWith(".")) { - bline = "." + bline; - } - writeln(bline); - } - writeln("."); - expect250(); - writeln("QUIT"); - - } - - private boolean expect250() throws IOException { - String line = readln(); - if (!line.startsWith("2")) { - logger.info("SmtpSender.expect250: " + line); - return false; - } - return true; - } - - private void writeln(String s) throws IOException { - if (traceLevel > 2) { - logger.debug("From client: " + s); - } - out.write(s + "\r\n"); - out.flush(); - } - - private String readln() throws IOException { - String line = in.readLine(); - if (traceLevel > 1) { - logger.debug("From server: " + line); - } - return line; - } - - /** - * Set the trace level. - */ - public void setTraceLevel(int traceLevel) { - this.traceLevel = traceLevel; - } - - /** - * Return the hostname of the local machine. - */ - public String getLocalHostName() { - try { - InetAddress ipaddress = InetAddress.getLocalHost(); - String localHost = ipaddress.getHostName(); - if (localHost == null) { - return "localhost"; - } else { - return localHost; - } - } catch (UnknownHostException e) { - return "localhost"; - } - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java index 239aa0ffa..0f466c649 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java @@ -16,7 +16,7 @@ import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD; import com.avaje.ebeaninternal.server.cluster.ClusterManager; import com.avaje.ebeaninternal.server.core.BootupClasses; import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool; +import org.avaje.datasource.DataSourcePool; import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import com.avaje.ebeanservice.docstore.api.DocStoreUpdates; import org.slf4j.Logger; @@ -27,7 +27,6 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.List; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** @@ -129,15 +128,6 @@ public class TransactionManager { this.externalTransPrefix = "e"; this.onQueryOnly = initOnQueryOnly(config.getDatabasePlatform().getOnQueryOnly(), dataSource); - - initialiseHeartbeat(); - } - - private void initialiseHeartbeat() { - if (dataSource instanceof DataSourcePool) { - DataSourcePool ds = (DataSourcePool) dataSource; - backgroundExecutor.executePeriodically(ds.getHeartbeatRunnable(), ds.getHeartbeatFreqSecs(), TimeUnit.SECONDS); - } } public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) { diff --git a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestBusyBuffer.java b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestBusyBuffer.java deleted file mode 100644 index 24fc550d4..000000000 --- a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestBusyBuffer.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import org.junit.Assert; -import org.junit.Test; - -import com.avaje.ebean.BaseTestCase; - -public class TestBusyBuffer extends BaseTestCase { - - @Test - public void test() { - - BusyConnectionBuffer b = new BusyConnectionBuffer(2, 4); - - PooledConnection p0 = new PooledConnection("0"); - PooledConnection p1 = new PooledConnection("1"); - PooledConnection p2 = new PooledConnection("2"); - PooledConnection p3 = new PooledConnection("3"); - - Assert.assertEquals(2, b.getCapacity()); - b.add(p0); - b.add(p1); - Assert.assertEquals(2, b.getCapacity()); - b.add(p2); - Assert.assertEquals(6, b.getCapacity()); - b.add(p3); - - Assert.assertEquals(0, p0.getSlotId()); - Assert.assertEquals(1, p1.getSlotId()); - Assert.assertEquals(2, p2.getSlotId()); - Assert.assertEquals(3, p3.getSlotId()); - - b.remove(p2); - b.add(p2); - Assert.assertEquals(4, p2.getSlotId()); - - b.remove(p0); - b.add(p0); - Assert.assertEquals(5, p0.getSlotId()); - - b.remove(p2); - b.add(p2); - Assert.assertEquals(0, p2.getSlotId()); - - } - - @Test - public void test_rotate() { - - BusyConnectionBuffer b = new BusyConnectionBuffer(2, 2); - - PooledConnection p0 = new PooledConnection("0"); - PooledConnection p1 = new PooledConnection("1"); - PooledConnection p2 = new PooledConnection("2"); - PooledConnection p3 = new PooledConnection("3"); - - Assert.assertEquals(2, b.getCapacity()); - Assert.assertEquals(0, b.size()); - - b.add(p0); - b.add(p1); - Assert.assertEquals(2, b.size()); - Assert.assertEquals(2, b.getCapacity()); - b.add(p2); - Assert.assertEquals(3, b.size()); - Assert.assertEquals(4, b.getCapacity()); - b.add(p3); - Assert.assertEquals(4, b.size()); - Assert.assertEquals(4, b.getCapacity()); - - Assert.assertEquals(0, p0.getSlotId()); - Assert.assertEquals(1, p1.getSlotId()); - Assert.assertEquals(2, p2.getSlotId()); - Assert.assertEquals(3, p3.getSlotId()); - - b.remove(p2); - Assert.assertEquals(3, b.size()); - b.remove(p0); - Assert.assertEquals(2, b.size()); - b.remove(p3); - Assert.assertEquals(1, b.size()); - b.add(p2); - Assert.assertEquals(2, b.size()); - Assert.assertEquals(0, p2.getSlotId()); - - b.remove(p0); - Assert.assertEquals(2, b.size()); - b.add(p0); - Assert.assertEquals(3, b.size()); - - // p1 is still in it's slot - Assert.assertEquals(2, p0.getSlotId()); - - b.remove(p2); - b.add(p2); - Assert.assertEquals(3, p2.getSlotId()); - - } - -} diff --git a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMax.java b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMax.java deleted file mode 100644 index 4283609ba..000000000 --- a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMax.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; - -import org.junit.Test; - -import com.avaje.ebean.BaseTestCase; -import com.avaje.ebean.config.DataSourceConfig; -import com.avaje.ebeaninternal.server.core.DefaultBackgroundExecutor; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool.Status; - -public class TestDataSourceMax extends BaseTestCase { - - @Test - public void test() { - - boolean skipThisTest = true; - - if (skipThisTest) { - return; - } - - String name = "mysql"; - - DataSourceConfig dsConfig = new DataSourceConfig(); - dsConfig.loadSettings(name); - dsConfig.setMinConnections(2); - dsConfig.setMaxConnections(25); - dsConfig.setWaitTimeoutMillis(30000); - dsConfig.setCaptureStackTrace(true); - - DataSourcePool pool = new DataSourcePool(null, name, dsConfig); - - - //pool.checkDataSource(); - -// if (true) { -// pool.shutdown(false); -// return; -// } - - DefaultBackgroundExecutor bg = new DefaultBackgroundExecutor(1, 1, 2, 180, 30, "testDs"); - - try { - for (int i = 0; i < 12; i++) { - // Thread.sleep(10*i); - bg.execute(new ConnRunner(pool, 4000, i)); - } - - Thread.sleep(10000); - pool.getStatistics(true); - - Thread.sleep(30000); - - Status status = pool.getStatus(false); - System.out.println(status); - - pool.shutdown(false); - - } catch (Exception e) { - e.printStackTrace(); - } - - } - - private static class ConnRunner implements Runnable { - - final DataSourcePool pool; - final long sleepMillis; - final int position; - - ConnRunner(DataSourcePool pool, long sleepMillis, int position) { - this.pool = pool; - this.sleepMillis = sleepMillis; - this.position = position; - } - - private void waitSomeTime(long count) { - try { - Thread.sleep(sleepMillis); - } catch (InterruptedException e){ - throw new RuntimeException(e); - } - } - - public void run() { - Connection connection = null; - PreparedStatement pstmt = null; - ResultSet rset = null; - long count = -1; - try { - connection = pool.getConnection(); - pstmt = connection.prepareStatement("select count(*) from o_customer"); - rset = pstmt.executeQuery(); - - while (rset.next()) { - // do nothing actually - count = rset.getLong(1); - } - - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - if (rset != null) { - try { - rset.close(); - } catch (Exception e) { - e.printStackTrace(); - } - if (pstmt != null) { - try { - pstmt.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - if (connection != null) { - try { - connection.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - waitSomeTime(count); - } - } - } -} diff --git a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBuffer.java b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBuffer.java deleted file mode 100644 index 85e0f1a4e..000000000 --- a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBuffer.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import org.junit.Assert; -import org.junit.Test; - -import com.avaje.ebean.BaseTestCase; - -public class TestFreeBuffer extends BaseTestCase { - - @Test - public void test() { - - FreeConnectionBuffer b = new FreeConnectionBuffer(); - - PooledConnection p0 = new PooledConnection("0"); - PooledConnection p1 = new PooledConnection("1"); - PooledConnection p2 = new PooledConnection("2"); - // PooledConnection p3 = new PooledConnection("3"); - - Assert.assertEquals(0, b.size()); - Assert.assertEquals(true, b.isEmpty()); - - b.add(p0); - - Assert.assertEquals(1, b.size()); - Assert.assertEquals(false, b.isEmpty()); - - PooledConnection r0 = b.remove(); - Assert.assertTrue(p0 == r0); - - Assert.assertEquals(0, b.size()); - Assert.assertEquals(true, b.isEmpty()); - - b.add(p0); - b.add(p1); - b.add(p2); - - Assert.assertEquals(3, b.size()); - - PooledConnection r1 = b.remove(); - Assert.assertTrue(p0 == r1); - PooledConnection r2 = b.remove(); - Assert.assertTrue(p1 == r2); - - Assert.assertEquals(1, b.size()); - b.add(p0); - Assert.assertEquals(2, b.size()); - PooledConnection r3 = b.remove(); - Assert.assertTrue(p2 == r3); - Assert.assertEquals(1, b.size()); - PooledConnection r4 = b.remove(); - Assert.assertTrue(p0 == r4); - Assert.assertEquals(0, b.size()); - - b.add(p2); - b.add(p1); - b.add(p0); - - Assert.assertEquals(3, b.size()); - - PooledConnection r5 = b.remove(); - Assert.assertTrue(p2 == r5); - Assert.assertEquals(2, b.size()); - - PooledConnection r6 = b.remove(); - Assert.assertTrue(p1 == r6); - Assert.assertEquals(1, b.size()); - - PooledConnection r7 = b.remove(); - Assert.assertTrue(p0 == r7); - Assert.assertEquals(0, b.size()); - - } -} diff --git a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBufferTrim.java b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBufferTrim.java deleted file mode 100644 index a7a4052c2..000000000 --- a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestFreeBufferTrim.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.avaje.ebeaninternal.server.lib.sql; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.avaje.ebean.BaseTestCase; - -public class TestFreeBufferTrim extends BaseTestCase { - - @Test - public void testWithTime() { - - FreeConnectionBuffer b = new FreeConnectionBuffer(); - Assert.assertEquals(0, b.size()); - - PooledConnection p0 = Mockito.mock(PooledConnection.class); - Mockito.when(p0.shouldTrim(1500, 0)).thenReturn(true); - - PooledConnection p1 = Mockito.mock(PooledConnection.class); - Mockito.when(p1.shouldTrim(1500, 0)).thenReturn(true); - - PooledConnection p2 = Mockito.mock(PooledConnection.class); - Mockito.when(p2.shouldTrim(1500, 0)).thenReturn(false); - - b.add(p0); - b.add(p1); - b.add(p2); - - Assert.assertEquals(3, b.size()); - - int trimCount = b.trim(1500, 0); - - Assert.assertEquals(1, b.size()); - Assert.assertEquals(2, trimCount); - } - - - -} diff --git a/src/test/java/com/avaje/tests/basic/MainDbBoolean.java b/src/test/java/com/avaje/tests/basic/MainDbBoolean.java index 712616eff..37669b177 100644 --- a/src/test/java/com/avaje/tests/basic/MainDbBoolean.java +++ b/src/test/java/com/avaje/tests/basic/MainDbBoolean.java @@ -8,7 +8,7 @@ import com.avaje.ebean.EbeanServer; import com.avaje.ebean.EbeanServerFactory; import com.avaje.ebean.Query; import com.avaje.ebean.SqlRow; -import com.avaje.ebean.config.DataSourceConfig; +import org.avaje.datasource.DataSourceConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.PostgresPlatform; import com.avaje.tests.model.basic.TOne; diff --git a/src/test/java/com/avaje/tests/basic/MyTestDataSourcePoolListener.java b/src/test/java/com/avaje/tests/basic/MyTestDataSourcePoolListener.java index ceb4c68a8..acb2c85b9 100644 --- a/src/test/java/com/avaje/tests/basic/MyTestDataSourcePoolListener.java +++ b/src/test/java/com/avaje/tests/basic/MyTestDataSourcePoolListener.java @@ -2,7 +2,7 @@ package com.avaje.tests.basic; import java.sql.Connection; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePoolListener; +import org.avaje.datasource.DataSourcePoolListener; public class MyTestDataSourcePoolListener implements DataSourcePoolListener { diff --git a/src/test/java/com/avaje/tests/transaction/TestAutoCommitDataSource.java b/src/test/java/com/avaje/tests/transaction/TestAutoCommitDataSource.java index 75ec8d753..61395f226 100644 --- a/src/test/java/com/avaje/tests/transaction/TestAutoCommitDataSource.java +++ b/src/test/java/com/avaje/tests/transaction/TestAutoCommitDataSource.java @@ -5,16 +5,19 @@ import com.avaje.ebean.EbeanServer; import com.avaje.ebean.EbeanServerFactory; import com.avaje.ebean.Query; import com.avaje.ebean.Transaction; -import com.avaje.ebean.config.DataSourceConfig; +import com.avaje.ebean.config.PropertyMap; import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool; import com.avaje.tests.model.basic.UTDetail; import com.avaje.tests.model.basic.UTMaster; +import org.avaje.datasource.DataSourceConfig; +import org.avaje.datasource.DataSourcePool; +import org.avaje.datasource.pool.ConnectionPool; import org.junit.Test; import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import java.util.Properties; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -24,11 +27,13 @@ public class TestAutoCommitDataSource extends BaseTestCase { @Test public void test() throws SQLException { + Properties properties = PropertyMap.defaultProperties(); + DataSourceConfig dsConfig = new DataSourceConfig(); - dsConfig.loadSettings("h2autocommit");//"pg" + dsConfig.loadSettings(properties, "h2autocommit");//"pg" dsConfig.setAutoCommit(true); - DataSourcePool pool = new DataSourcePool(null, "h2autocommit", dsConfig); + DataSourcePool pool = new ConnectionPool("h2autocommit", dsConfig); Connection connection = pool.getConnection(); assertTrue(connection.getAutoCommit()); diff --git a/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java b/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java index 04d63a0e5..d5957589a 100644 --- a/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java +++ b/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java @@ -5,16 +5,19 @@ import com.avaje.ebean.EbeanServer; import com.avaje.ebean.EbeanServerFactory; import com.avaje.ebean.Query; import com.avaje.ebean.Transaction; -import com.avaje.ebean.config.DataSourceConfig; +import com.avaje.ebean.config.PropertyMap; import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool; import com.avaje.tests.model.basic.UTDetail; import com.avaje.tests.model.basic.UTMaster; +import org.avaje.datasource.DataSourceConfig; +import org.avaje.datasource.DataSourcePool; +import org.avaje.datasource.pool.ConnectionPool; import org.junit.Test; import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import java.util.Properties; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -24,11 +27,13 @@ public class TestExplicitTransactionMode extends BaseTestCase { @Test public void test() throws SQLException { + Properties properties = PropertyMap.defaultProperties(); + DataSourceConfig dsConfig = new DataSourceConfig(); - dsConfig.loadSettings("h2autocommit");//"h2autocommit","pg" + dsConfig.loadSettings(properties, "h2autocommit");//"h2autocommit","pg" dsConfig.setAutoCommit(true); - DataSourcePool pool = new DataSourcePool(null, "h2autocommit", dsConfig); + DataSourcePool pool = new ConnectionPool("h2autocommit", dsConfig); Connection connection = pool.getConnection(); assertTrue(connection.getAutoCommit()); diff --git a/src/test/java/com/avaje/tests/unitinternal/HelloMain.java b/src/test/java/com/avaje/tests/unitinternal/HelloMain.java index 50a5f52c9..659ade8a4 100644 --- a/src/test/java/com/avaje/tests/unitinternal/HelloMain.java +++ b/src/test/java/com/avaje/tests/unitinternal/HelloMain.java @@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; import com.avaje.ebean.EbeanServer; import com.avaje.ebean.EbeanServerFactory; -import com.avaje.ebean.config.DataSourceConfig; +import org.avaje.datasource.DataSourceConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.tests.model.basic.TOne;