All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.unicore.persist.util.Pool Maven / Gradle / Ivy

There is a newer version: 1.2.3
Show newest version
package eu.unicore.persist.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * A simple standalone JDBC connection pool manager.
 * 

* The public methods of this class are thread-safe. *

* Home page: www.source-code.biz
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
* Multi-licensed: EPL/LGPL/MPL. */ public class Pool { private static final Logger logger = LogManager.getLogger("unicore.persistence.Pool"); private ConnectionPoolDataSource dataSource; private int maxConnections; private int timeout; private Semaphore semaphore; private Queue recycledConnections; private int activeConnections; private PoolConnectionEventListener poolConnectionEventListener; private boolean isDisposed; /** * Constructs a MiniConnectionPoolManager object with a timeout of 60 * seconds. * * @param dataSource * the data source for the connections. * @param maxConnections * the maximum number of connections. */ public Pool(ConnectionPoolDataSource dataSource, int maxConnections) { this(dataSource, maxConnections, 60); } /** * Constructs a MiniConnectionPoolManager object. * * @param dataSource * the data source for the connections. * @param maxConnections * the maximum number of connections. * @param timeout * the maximum time in seconds to wait for a free connection. */ public Pool(ConnectionPoolDataSource dataSource, int maxConnections, int timeout) { this.dataSource = dataSource; this.maxConnections = maxConnections; this.timeout = timeout; if (maxConnections < 1) throw new IllegalArgumentException("Invalid maxConnections value."); semaphore = new Semaphore(maxConnections, true); recycledConnections = new LinkedList(); poolConnectionEventListener = new PoolConnectionEventListener(); } /** * Closes all unused pooled connections and disposes the pool, after * which it will become unusable */ public synchronized void dispose() throws SQLException { if (isDisposed) return; isDisposed = true; SQLException e = null; while (!recycledConnections.isEmpty()) { PooledConnection pconn = recycledConnections.remove(); try { pconn.close(); } catch (SQLException e2) { if (e == null) e = e2; } } if (e != null) throw e; } /** * remove all pooled connections, thus ensuring that a call to getConnection() will * create a new connection * @throws SQLException */ public synchronized void cleanupPooledConnections() throws SQLException { if (isDisposed) throw new IllegalStateException("Pool is disposed."); SQLException e = null; while (!recycledConnections.isEmpty()) { PooledConnection pconn = recycledConnections.remove(); try { pconn.close(); } catch (SQLException e2) { if (e == null) e = e2; } } if (e != null) throw e; } /** * Retrieves a connection from the connection pool. If * maxConnections connections are already in use, the method * waits until a connection becomes available or timeout * seconds elapsed. When the application is finished using the connection, * it must close it in order to return it to the pool. * * @return a new Connection object. */ public Connection getConnection() throws SQLException { // This routine is unsynchronized, because semaphore.tryAcquire() may // block. synchronized (this) { if (isDisposed) throw new IllegalStateException( "Connection pool has been disposed."); } try { if (!semaphore.tryAcquire(timeout, TimeUnit.SECONDS)) throw new SQLException("Timeout while waiting for a free database connection."); } catch (InterruptedException e) { throw new SQLException( "Interrupted while waiting for a database connection.", e); } boolean ok = false; try { Connection conn = getConnection2(); ok = true; return conn; } finally { if (!ok) semaphore.release(); } } private synchronized Connection getConnection2() throws SQLException { if (isDisposed) throw new IllegalStateException( "Connection pool has been disposed."); // test again with // lock PooledConnection pconn; if (!recycledConnections.isEmpty()) { pconn = recycledConnections.remove(); } else { pconn = dataSource.getPooledConnection(); } Connection conn = pconn.getConnection(); activeConnections++; pconn.addConnectionEventListener(poolConnectionEventListener); assertInnerState(); return conn; } private synchronized void recycleConnection(PooledConnection pconn) { if (isDisposed) { disposeConnection(pconn); return; } if (activeConnections <= 0) throw new AssertionError(); activeConnections--; semaphore.release(); recycledConnections.add(pconn); assertInnerState(); } private synchronized void disposeConnection(PooledConnection pconn) { if (activeConnections <= 0) throw new AssertionError(); activeConnections--; semaphore.release(); closeConnectionNoEx(pconn); assertInnerState(); } private void closeConnectionNoEx(PooledConnection pconn) { try { pconn.close(); } catch (SQLException e) { logger.error("Error while closing database connection: " + e.toString(), e); } } private void assertInnerState() { if (activeConnections < 0) throw new AssertionError(); if (activeConnections + recycledConnections.size() > maxConnections) throw new AssertionError(); if (activeConnections + semaphore.availablePermits() > maxConnections) throw new AssertionError(); } private class PoolConnectionEventListener implements ConnectionEventListener { public void connectionClosed(ConnectionEvent event) { PooledConnection pconn = (PooledConnection) event.getSource(); pconn.removeConnectionEventListener(this); recycleConnection(pconn); } public void connectionErrorOccurred(ConnectionEvent event) { PooledConnection pconn = (PooledConnection) event.getSource(); pconn.removeConnectionEventListener(this); disposeConnection(pconn); } } /** * Returns the number of active (open) connections of this pool. This is the * number of Connection objects that have been issued by * {@link #getConnection()} for which Connection.close() has * not yet been called. * * @return the number of active connections. **/ public synchronized int getActiveConnections() { return activeConnections; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy