Guest User

Untitled

a guest
Feb 7th, 2019
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.04 KB | None | 0 0
  1. package l2.commons.db;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5. import java.util.ArrayDeque;
  6. import java.util.concurrent.Semaphore;
  7. import java.util.concurrent.TimeUnit;
  8. import javax.sql.ConnectionEvent;
  9. import javax.sql.ConnectionEventListener;
  10. import javax.sql.ConnectionPoolDataSource;
  11. import javax.sql.PooledConnection;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14.  
  15. public abstract class BaseDataConnectionFactory {
  16.     private static final Logger LOG = LoggerFactory.getLogger(BaseDataConnectionFactory.class);
  17.     private final ConnectionPoolDataSource _connectionPoolDataSource;
  18.     private final Semaphore _semaphore;
  19.     private final ArrayDeque<PooledConnection> _recycledConnections;
  20.     private final int _maxConnections;
  21.     private final long _timeout;
  22.     private boolean _isDisposed;
  23.     private int _activeConnections;
  24.     private PooledConnection _connectionInTransition;
  25.     private final PoolConnectionEventListener _poolConnectionEventListener;
  26.  
  27.     protected BaseDataConnectionFactory(ConnectionPoolDataSource connectionPoolDataSource, int maxConnections, int timeout) {
  28.         _connectionPoolDataSource = connectionPoolDataSource;
  29.         _maxConnections = maxConnections;
  30.         _timeout = timeout;
  31.         if (maxConnections < 1) {
  32.             throw new IllegalArgumentException("Invalid maxConnections value.");
  33.         }
  34.         _semaphore = new Semaphore(maxConnections, true);
  35.         _recycledConnections = new ArrayDeque(_maxConnections);
  36.         _poolConnectionEventListener = new PoolConnectionEventListener();
  37.         _isDisposed = false;
  38.         _activeConnections = 0;
  39.         try {
  40.             testDB();
  41.             LOG.info("DatabaseFactory: Database connection tested and working.");
  42.         }
  43.         catch (SQLException se) {
  44.             throw new RuntimeException("Can't init database connections pool", se);
  45.         }
  46.     }
  47.  
  48.     public Connection getConnection() throws SQLException {
  49.         return getConnectionImpl();
  50.     }
  51.  
  52.     protected abstract void testDB() throws SQLException;
  53.    
  54.     protected Connection getConnectionImpl() throws SQLException {
  55.         BaseDataConnectionFactory baseDataConnectionFactory = this;
  56.         synchronized (baseDataConnectionFactory) {
  57.             if (_isDisposed) {
  58.                 throw new IllegalStateException("Connection pool has been disposed.");
  59.             }
  60.         }
  61.         Thread.currentThread();
  62.         boolean interrupted = Thread.interrupted();
  63.         try {
  64.             try {
  65.                 if (!_semaphore.tryAcquire(_timeout, TimeUnit.MILLISECONDS)) {
  66.                     throw new TimeoutException();
  67.                 }
  68.             }
  69.             catch (InterruptedException e) {
  70.                 throw new RuntimeException("Interrupted while waiting for a database connection.", e);
  71.             }
  72.             boolean ok = false;
  73.             try {
  74.                 Connection conn = getConnectionImpl0();
  75.                 ok = true;
  76.                 Connection connection = conn;
  77.                 if (!ok) {
  78.                     _semaphore.release();
  79.                 }
  80.                 return connection;
  81.             }
  82.             catch (Throwable throwable) {
  83.                 if (!ok) {
  84.                     _semaphore.release();
  85.                 }
  86.                 throw throwable;
  87.             }
  88.         }
  89.         finally {
  90.             if (interrupted) {
  91.                 Thread.currentThread().interrupt();
  92.             }
  93.         }
  94.     }
  95.    
  96.     private synchronized Connection getConnectionImpl0() throws SQLException {
  97.         Connection conn;
  98.         PooledConnection pconn;
  99.         if (_isDisposed) {
  100.             throw new IllegalStateException("Connection pool has been disposed.");
  101.         }
  102.         if (!_recycledConnections.isEmpty()) {
  103.             pconn = _recycledConnections.remove();
  104.         } else {
  105.             pconn = _connectionPoolDataSource.getPooledConnection();
  106.             pconn.addConnectionEventListener(_poolConnectionEventListener);
  107.         }
  108.         try {
  109.             _connectionInTransition = pconn;
  110.             conn = pconn.getConnection();
  111.         }
  112.         finally {
  113.             _connectionInTransition = null;
  114.         }
  115.         _activeConnections++;
  116.         checkInnerState();
  117.         return conn;
  118.     }
  119.  
  120.     private void checkInnerState() {
  121.         if (_activeConnections < 0) {
  122.             throw new RuntimeException();
  123.         }
  124.         if (_activeConnections + _recycledConnections.size() > _maxConnections) {
  125.             throw new RuntimeException();
  126.         }
  127.         if (_activeConnections + _semaphore.availablePermits() > _maxConnections) {
  128.             throw new RuntimeException();
  129.         }
  130.     }
  131.  
  132.     private synchronized void recycleConnection(PooledConnection pconn) {
  133.         if (_isDisposed) {
  134.             disposeConnection(pconn);
  135.             return;
  136.         }
  137.         if (_activeConnections <= 0) {
  138.             throw new AssertionError();
  139.         }
  140.         --_activeConnections;
  141.         _semaphore.release();
  142.         _recycledConnections.add(pconn);
  143.         checkInnerState();
  144.     }
  145.  
  146.     private synchronized void disposeConnection(PooledConnection pconn) {
  147.         pconn.removeConnectionEventListener(_poolConnectionEventListener);
  148.         if (!_recycledConnections.remove(pconn) && pconn != _connectionInTransition) {
  149.             if (_activeConnections <= 0) {
  150.                 throw new AssertionError();
  151.             }
  152.             _activeConnections--;
  153.             _semaphore.release();
  154.         }
  155.         closeConnectionAndIgnoreException(pconn);
  156.         checkInnerState();
  157.     }
  158.  
  159.     private void closeConnectionAndIgnoreException(PooledConnection pconn) {
  160.         try {
  161.             pconn.close();
  162.         }
  163.         catch (SQLException se) {
  164.             LOG.error("Error while closing database connection", se);
  165.         }
  166.     }
  167.  
  168.     public synchronized void shutdown() throws SQLException {
  169.         if (_isDisposed) {
  170.             return;
  171.         }
  172.         _isDisposed = true;
  173.         SQLException e = null;
  174.         while (!_recycledConnections.isEmpty()) {
  175.             PooledConnection pconn = _recycledConnections.remove();
  176.             try {
  177.                 pconn.close();
  178.             }
  179.             catch (SQLException e2) {
  180.                 if (e != null) continue;
  181.                 e = e2;
  182.             }
  183.         }
  184.         if (e != null) {
  185.             throw e;
  186.         }
  187.     }
  188.  
  189.     private class PoolConnectionEventListener
  190.             implements ConnectionEventListener {
  191.         private PoolConnectionEventListener() {
  192.         }
  193.  
  194.         @Override
  195.         public void connectionClosed(ConnectionEvent event) {
  196.             PooledConnection pconn = (PooledConnection)event.getSource();
  197.             recycleConnection(pconn);
  198.         }
  199.  
  200.         @Override
  201.         public void connectionErrorOccurred(ConnectionEvent event) {
  202.             PooledConnection pconn = (PooledConnection)event.getSource();
  203.             disposeConnection(pconn);
  204.         }
  205.     }
  206.  
  207.     public static class TimeoutException
  208.             extends RuntimeException {
  209.         private static final long serialVersionUID = 1L;
  210.  
  211.         public TimeoutException() {
  212.             super("Timeout while waiting for a free database connection.");
  213.         }
  214.  
  215.         public TimeoutException(String msg) {
  216.             super(msg);
  217.         }
  218.     }
  219.  
  220. }
Add Comment
Please, Sign In to add comment