Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package l2.commons.db;
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.ArrayDeque;
- 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.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public abstract class BaseDataConnectionFactory {
- private static final Logger LOG = LoggerFactory.getLogger(BaseDataConnectionFactory.class);
- private final ConnectionPoolDataSource _connectionPoolDataSource;
- private final Semaphore _semaphore;
- private final ArrayDeque<PooledConnection> _recycledConnections;
- private final int _maxConnections;
- private final long _timeout;
- private boolean _isDisposed;
- private int _activeConnections;
- private PooledConnection _connectionInTransition;
- private final PoolConnectionEventListener _poolConnectionEventListener;
- protected BaseDataConnectionFactory(ConnectionPoolDataSource connectionPoolDataSource, int maxConnections, int timeout) {
- _connectionPoolDataSource = connectionPoolDataSource;
- _maxConnections = maxConnections;
- _timeout = timeout;
- if (maxConnections < 1) {
- throw new IllegalArgumentException("Invalid maxConnections value.");
- }
- _semaphore = new Semaphore(maxConnections, true);
- _recycledConnections = new ArrayDeque(_maxConnections);
- _poolConnectionEventListener = new PoolConnectionEventListener();
- _isDisposed = false;
- _activeConnections = 0;
- try {
- testDB();
- LOG.info("DatabaseFactory: Database connection tested and working.");
- }
- catch (SQLException se) {
- throw new RuntimeException("Can't init database connections pool", se);
- }
- }
- public Connection getConnection() throws SQLException {
- return getConnectionImpl();
- }
- protected abstract void testDB() throws SQLException;
- protected Connection getConnectionImpl() throws SQLException {
- BaseDataConnectionFactory baseDataConnectionFactory = this;
- synchronized (baseDataConnectionFactory) {
- if (_isDisposed) {
- throw new IllegalStateException("Connection pool has been disposed.");
- }
- }
- Thread.currentThread();
- boolean interrupted = Thread.interrupted();
- try {
- try {
- if (!_semaphore.tryAcquire(_timeout, TimeUnit.MILLISECONDS)) {
- throw new TimeoutException();
- }
- }
- catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while waiting for a database connection.", e);
- }
- boolean ok = false;
- try {
- Connection conn = getConnectionImpl0();
- ok = true;
- Connection connection = conn;
- if (!ok) {
- _semaphore.release();
- }
- return connection;
- }
- catch (Throwable throwable) {
- if (!ok) {
- _semaphore.release();
- }
- throw throwable;
- }
- }
- finally {
- if (interrupted) {
- Thread.currentThread().interrupt();
- }
- }
- }
- private synchronized Connection getConnectionImpl0() throws SQLException {
- Connection conn;
- PooledConnection pconn;
- if (_isDisposed) {
- throw new IllegalStateException("Connection pool has been disposed.");
- }
- if (!_recycledConnections.isEmpty()) {
- pconn = _recycledConnections.remove();
- } else {
- pconn = _connectionPoolDataSource.getPooledConnection();
- pconn.addConnectionEventListener(_poolConnectionEventListener);
- }
- try {
- _connectionInTransition = pconn;
- conn = pconn.getConnection();
- }
- finally {
- _connectionInTransition = null;
- }
- _activeConnections++;
- checkInnerState();
- return conn;
- }
- private void checkInnerState() {
- if (_activeConnections < 0) {
- throw new RuntimeException();
- }
- if (_activeConnections + _recycledConnections.size() > _maxConnections) {
- throw new RuntimeException();
- }
- if (_activeConnections + _semaphore.availablePermits() > _maxConnections) {
- throw new RuntimeException();
- }
- }
- private synchronized void recycleConnection(PooledConnection pconn) {
- if (_isDisposed) {
- disposeConnection(pconn);
- return;
- }
- if (_activeConnections <= 0) {
- throw new AssertionError();
- }
- --_activeConnections;
- _semaphore.release();
- _recycledConnections.add(pconn);
- checkInnerState();
- }
- private synchronized void disposeConnection(PooledConnection pconn) {
- pconn.removeConnectionEventListener(_poolConnectionEventListener);
- if (!_recycledConnections.remove(pconn) && pconn != _connectionInTransition) {
- if (_activeConnections <= 0) {
- throw new AssertionError();
- }
- _activeConnections--;
- _semaphore.release();
- }
- closeConnectionAndIgnoreException(pconn);
- checkInnerState();
- }
- private void closeConnectionAndIgnoreException(PooledConnection pconn) {
- try {
- pconn.close();
- }
- catch (SQLException se) {
- LOG.error("Error while closing database connection", se);
- }
- }
- public synchronized void shutdown() 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) continue;
- e = e2;
- }
- }
- if (e != null) {
- throw e;
- }
- }
- private class PoolConnectionEventListener
- implements ConnectionEventListener {
- private PoolConnectionEventListener() {
- }
- @Override
- public void connectionClosed(ConnectionEvent event) {
- PooledConnection pconn = (PooledConnection)event.getSource();
- recycleConnection(pconn);
- }
- @Override
- public void connectionErrorOccurred(ConnectionEvent event) {
- PooledConnection pconn = (PooledConnection)event.getSource();
- disposeConnection(pconn);
- }
- }
- public static class TimeoutException
- extends RuntimeException {
- private static final long serialVersionUID = 1L;
- public TimeoutException() {
- super("Timeout while waiting for a free database connection.");
- }
- public TimeoutException(String msg) {
- super(msg);
- }
- }
- }
Add Comment
Please, Sign In to add comment