Bug 77 : introduce a DataSourcePoolListener
Priority 
High
Reported Version 
 
Logged By 
imario
Status 
Fixed
Fixed Version 
1.1.0
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
24/02/2009
Updated 
24/02/2009
Type 
Bug
 
Attachments 
No attachments

I would like to ask if you could add a feature which allows one into the process where one can get notified about connections which have been borrowed or returned to the pool.

The following patch will introduce a new interface (the DataSourcePoolListener) with two methods

public void onAfterBorrowConnection(Connection con);
public void onBeforeReturnConnection(Connection con);

I need this feature to issue a specific command to the database before staring to access it and don't wanted to implement all the datasource pooling myself, extending Avajes default implementation is not possible due to the DatasourceManager.
I think this API is usefull for others anyway.

Would be great if you could apply the patch.

Thanks!

 
imario 24 Feb 10:15
The patch

Index: ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePool.java
===================================================================
--- ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePool.java (revision 141)
+++ ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePool.java Tue Feb 24 09:11:04 CET 2009
@@ -17,12 +17,12 @@
*/
package com.avaje.ebean.server.lib.sql;

+import com.avaje.ebean.server.lib.cron.CronManager;
+import com.avaje.lib.log.LogFactory;
+
+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.Statement;
+import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -30,11 +30,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;

-import javax.sql.DataSource;
-
-import com.avaje.ebean.server.lib.cron.CronManager;
-import com.avaje.lib.log.LogFactory;
-
/**
* A robust DataSource.
*


@@ -180,7 +175,17 @@
*/
private long leakTime = 60 * 1000 * 5;

- /**
+ /**
+ * a listener which gets called for borrow/return connection
+ */
+ private DataSourcePoolListener dataSourcePoolListener;
+
+ /**
+ * The listener class name
+ */
+ private String poolListenerClassName;
+
+ /**
* Create the pool.
*/
public DataSourcePool(DataSourceManager manager, DataSourceParams params) {
@@ -211,6 +216,7 @@
this.waitTimeout = params.getWaitTimeout();
this.transactionIsolation = params.getIsolationLevel();
this.heartbeatsql = params.getHeartBeatSql();
+ this.poolListenerClassName = params.getPoolListener();
}

/**
@@ -243,6 +249,22 @@
throw new SQLException("Database Driver class not found: " + e.getMessage());
}

+ if (poolListenerClassName != null) {
+ try {
+ Class clazz = Class.forName(poolListenerClassName);
+ dataSourcePoolListener = (DataSourcePoolListener) clazz.newInstance();
+ }
+ catch (ClassNotFoundException e) {
+ throw new SQLException(e);
+ }
+ catch (IllegalAccessException e) {
+ throw new SQLException(e);
+ }
+ catch (InstantiationException e) {
+ throw new SQLException(e);
+ }
+ }
+
String transIsolation = TransactionIsolation.getLevelDescription(transactionIsolation);
StringBuffer sb = new StringBuffer();
sb.append("DataSourcePool [").append(name);
@@ -485,6 +507,10 @@
*
*/
protected void returnConnection(PooledConnection pooledConnection) {
+ if (dataSourcePoolListener != null)
+ {
+ dataSourcePoolListener.onBeforeReturnConnection(pooledConnection);
+ }

if (pooledConnection.getCreationTime() <= lastResetTime) {
pooledConnection.closeConnectionFully(false);
@@ -699,8 +725,17 @@
* will go into a wait if the pool has hit its maximum size.
*


*/
- public PooledConnection getPooledConnection() throws SQLException {
+ public PooledConnection getPooledConnection() throws SQLException {
+ PooledConnection ret = _getPooledConnection();
+ if (dataSourcePoolListener != null)
+ {
+ dataSourcePoolListener.onAfterBorrowConnection(ret);
+ }
+ return ret;
+ }

+ private PooledConnection _getPooledConnection() throws SQLException {
+
if (doingShutdown) {
throw new SQLException("Trying to access the Connection Pool when it is shutting down");
}
@@ -732,8 +767,10 @@
reset();

try {
freeList.wait(waitTimeout);
} catch (InterruptedException e) {
}

if (!freeList.isEmpty()) {
Index: ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourceParams.java
===================================================================
--- ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourceParams.java (revision 141)
+++ ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourceParams.java Tue Feb 24 09:11:04 CET 2009
@@ -143,6 +143,13 @@
return getParam(key, false);
}

+ /**
+ * Return the maximum size of the callable statement cache.
+ */
+ public String getPoolListener() {
+ return getParam("poolListener", false);
+ }
+
private void parse() {
String un = getParam("username", false);
if (un == null) {
Index: ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePoolListener.java
===================================================================
--- ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePoolListener.java Tue Feb 24 11:03:18 CET 2009
+++ ../ebean/src/com/avaje/ebean/server/lib/sql/DataSourcePoolListener.java Tue Feb 24 11:03:18 CET 2009
@@ -0,0 +1,24 @@
+package com.avaje.ebean.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
+ */
+ public void onAfterBorrowConnection(Connection con);
+
+ /**
+ * called before a connection will be put back to the connection pool
+ */
+ public void onBeforeReturnConnection(Connection con);
+}

Rob 26 Feb 10:21
Yes. Good enhancement.

Yes, I am fine with this enhancement.

Just also incorporating a little bit of general tidy up work including re-instating the stackTrace capturing (to help identify connection pool leaks).

Rob 01 Mar 08:25
Fixed in HEAD

The code to support this enhancement is in HEAD.

woResponse

Upload a file