import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Object pool manager: Responsible for DatabaseConnection creation, reuse, and recycling * @author chuyang * @version 1.0 */ public class ConnectionPoolManager { /** * Connection pool storage */ private final List connectionPool; /** * Database URL */ private final String databaseUrl; /** * Initial pool size */ private final int initialSize; /** * Maximum pool size */ private final int maxSize; /** * For thread safety */ private final Lock poolLock = new ReentrantLock(); public DatabaseConnection m_DatabaseConnection; public ConnectionPoolManager(){ this.connectionPool = new ArrayList<>(); this.databaseUrl = ""; this.initialSize = 0; this.maxSize = 0; } @Override public void finalize() throws Throwable { // Close all connections poolLock.lock(); try { for (DatabaseConnection conn : connectionPool) { System.out.println("Closing connection " + conn.getConnectionId()); } connectionPool.clear(); } finally { poolLock.unlock(); } } /** * Constructor: Initialize object pool * * @param initialSize Initial number of connections * @param maxSize Maximum number of connections * @param databaseUrl Database URL */ public ConnectionPoolManager(int initialSize, int maxSize, String databaseUrl){ if (initialSize < 0 || maxSize < initialSize) { throw new IllegalArgumentException("Invalid pool size parameters"); } this.connectionPool = new ArrayList<>(maxSize); this.databaseUrl = databaseUrl; this.initialSize = initialSize; this.maxSize = maxSize; // Initialize connection pool initializePool(); } /** * Initialize the connection pool, create initial connections */ private void initializePool() { System.out.println("Initializing connection pool with " + initialSize + " connections"); for (int i = 0; i < initialSize; i++) { String connId = "conn-" + i; DatabaseConnection conn = new DatabaseConnection(connId, databaseUrl); connectionPool.add(conn); } System.out.println("Connection pool initialized with " + connectionPool.size() + " connections"); } /** * Borrow a connection from the pool * @return Available connection, or null (pool is full) */ public DatabaseConnection borrowConnection(){ poolLock.lock(); try { // 1. Look for idle connection for (DatabaseConnection conn : connectionPool) { if (!conn.isInUse()) { conn.setInUse(true); System.out.println("Borrowed existing connection: " + conn.getConnectionId()); return conn; } } // 2. If no idle connections and max size not reached, create new connection if (connectionPool.size() < maxSize) { String connId = "conn-" + connectionPool.size(); DatabaseConnection newConn = new DatabaseConnection(connId, databaseUrl); newConn.setInUse(true); connectionPool.add(newConn); System.out.println("Created and borrowed new connection: " + newConn.getConnectionId()); return newConn; } // 3. Pool is full, return null System.out.println("Connection pool is full, no available connections"); return null; } finally { poolLock.unlock(); } } /** * Return connection to the pool * * @param conn Connection to return */ public void returnConnection(DatabaseConnection conn){ if (conn == null) { return; } poolLock.lock(); try { // Check if connection belongs to this pool if (connectionPool.contains(conn)) { // Reset connection state conn.reset(); conn.setInUse(false); System.out.println("Connection returned to pool: " + conn.getConnectionId()); } else { System.out.println("Warning: Attempting to return a connection not managed by this pool"); } } finally { poolLock.unlock(); } } /** * Shrink pool: Destroy idle connections */ public void shrinkPool(){ poolLock.lock(); try { // Only keep initial size of connections List connectionsToRemove = new ArrayList<>(); int activeConnections = 0; for (DatabaseConnection conn : connectionPool) { if (conn.isInUse()) { activeConnections++; } else if (connectionPool.size() - connectionsToRemove.size() > initialSize) { connectionsToRemove.add(conn); System.out.println("Removing idle connection: " + conn.getConnectionId()); } } connectionPool.removeAll(connectionsToRemove); System.out.println("Pool shrunk. Active connections: " + activeConnections + ", Idle connections: " + connectionPool.size() + ", Removed: " + connectionsToRemove.size()); } finally { poolLock.unlock(); } } /** * Get pool status information */ public String getPoolStatus() { poolLock.lock(); try { int activeConnections = 0; for (DatabaseConnection conn : connectionPool) { if (conn.isInUse()) { activeConnections++; } } return "Pool status: " + connectionPool.size() + " total connections, " + activeConnections + " active, " + (connectionPool.size() - activeConnections) + " idle, " + "Max capacity: " + maxSize; } finally { poolLock.unlock(); } } }