I am trying to implement jdbc-pool in a standalone web app (self contained – not relying on server.xml) so that it can be moved to tomcat installations that may be earlier than 7.0.
I am connecting to MSSQL Server with the sourceforge driver (net.sourceforge.jtds.jdbc.Driver)
Everything runs fine except for this error:
SEVERE: The web application [/jdbc-pool] appears to have started a
thread named [[Pool-Cleaner]:Tomcat Connection Pool[1-12524859]] but
has failed to stop it. This is very likely to create a memory leak.
Based on this I determined that I need to close the jdbc-pool datasource. I am having trouble with this last line from that post though:
>> If it is configured in the application context, then this simply
means you forgot to call DataSource.close on the connection pool when
your web application is stopped.> This is confusing advice because javax.sql.DataSource doesn’t have
a close() method.In order to call close, one has to cast it to what ever the data
source you are using.
How do I find out what type of datasource I am using and where is the class for it? Can I extract it from the driver jar somehow?
In addition to a servlet which uses the pool, I am using a ServletContextListener so that I can start out with pooled connections immediately from the contextInitialized method. I started adding the code to kill the connection in the contextDestroyed method of this ServletContextListener but got hung up where the question marks are:
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;
public class JdbcPoolListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent myServletContextEvent) {
// initialize jdbc-pool datasource to start out with pooled connections
try {
Context myContext = (Context) new InitialContext().lookup("java:comp/env");
DataSource myDataSource = (DataSource) myContext.lookup("jdbc/db");
myServletContextEvent.getServletContext().setAttribute("JdbcPool", myDataSource);
} catch (NamingException e) {
System.out.println("Error initializing jdbc-pool datasource");
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent myServletContextEvent) {
// failed attempt to close the data source
ServletContext myServletContext = myServletContextEvent.getServletContext();
//DataSource myDataSource = (DataSource) myServletContext.getAttribute("JdbcPool");
DataSource dataSource = (DataSource)((???) myServletContext.getAttribute(contextAttribute)).getConfiguration().getEnvironment().getDataSource();
dataSource.close();
myServletContext.removeAttribute("JdbcPool");
// deregister JDBC driver to prevent Tomcat 7 from complaining about memory leaks
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
System.out.println(String.format("Deregistering jdbc driver: %s", driver));
} catch (SQLException e) {
System.out.println(String.format("Error deregistering driver %s", driver));
e.printStackTrace();
}
}
}
}
Resolved this, I noticed that the
tomcat.jdbc.pool.DataSourceProxyhad a close method, so I cast the datasource as aDataSourceProxy, then called closed on it. I no longer get the tomcat memory leak error in the log now.SOLUTION: