001/* 002MIT License 003 004Copyright (c) 2020 FBSQL Team 005 006Permission is hereby granted, free of charge, to any person obtaining a copy 007of this software and associated documentation files (the "Software"), to deal 008in the Software without restriction, including without limitation the rights 009to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010copies of the Software, and to permit persons to whom the Software is 011furnished to do so, subject to the following conditions: 012 013The above copyright notice and this permission notice shall be included in all 014copies or substantial portions of the Software. 015 016THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 022SOFTWARE. 023 024Home: https://fbsql.github.io 025E-Mail: fbsql.team@gmail.com 026*/ 027 028package org.fbsql.connection_pool; 029 030import java.io.FileNotFoundException; 031import java.io.IOException; 032import java.security.NoSuchAlgorithmException; 033import java.security.NoSuchProviderException; 034import java.sql.Connection; 035import java.sql.DriverManager; 036import java.sql.SQLException; 037import java.util.ArrayList; 038import java.util.Collection; 039import java.util.Collections; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Properties; 043 044/** 045 * Connection pool used to connect to database using a pre-created set of reusable connections. 046 * When a new connection is required, an arbitrary available connection is retrieved from the pool. 047 * When connection closed, it is returned to connection pool for future use. 048 */ 049public class ConnectionPoolManager implements AutoCloseable { 050 private int initialPoolSize; 051 private int maxPoolSize; 052 // 053 private String jdbcUrl; 054 private String jdbcUser; 055 private String jdbcPassword; 056 private Properties jdbcProperties; 057 // 058 private List<DbConnection> availableList; 059 private Collection<DbConnection> inUseList; 060 061 /** 062 * Constructs ConnectionPoolManager 063 * 064 * @param jdbcUrl 065 * @param jdbcUser 066 * @param jdbcPassword 067 * @param initialPoolSize 068 * @param maxPoolSize 069 */ 070 public ConnectionPoolManager(String jdbcUrl, String jdbcUser, String jdbcPassword, Properties jdbcProperties, int initialPoolSize, int maxPoolSize) { 071 this.jdbcUrl = jdbcUrl; 072 this.jdbcUser = jdbcUser; 073 this.jdbcPassword = jdbcPassword; 074 this.jdbcProperties = jdbcProperties; 075 this.initialPoolSize = initialPoolSize; 076 this.maxPoolSize = maxPoolSize; 077 } 078 079 /** 080 * Initialize ConnectionPoolManager 081 * 082 * @throws NoSuchAlgorithmException 083 * @throws NoSuchProviderException 084 * @throws SQLException 085 * @throws FileNotFoundException 086 * @throws IOException 087 */ 088 public void init() throws NoSuchAlgorithmException, NoSuchProviderException, SQLException, FileNotFoundException, IOException { 089 inUseList = Collections.synchronizedList(new ArrayList<>(initialPoolSize)); 090 availableList = Collections.synchronizedList(new ArrayList<>(initialPoolSize)); 091 for (int i = 0; i < initialPoolSize; i++) 092 addNewConnection(); 093 } 094 095 /** 096 * Close ConnectionPoolManager 097 */ 098 @Override 099 public void close() throws SQLException { 100 for (Iterator<DbConnection> iterator = inUseList.iterator(); iterator.hasNext();) { 101 DbConnection dbConnection = iterator.next(); 102 dbConnection.getConnection().commit(); 103 availableList.add(dbConnection); 104 iterator.remove(); 105 } 106 for (Iterator<DbConnection> iterator = availableList.iterator(); iterator.hasNext();) { 107 iterator.next().getConnection().close(); 108 iterator.remove(); 109 } 110 } 111 112 /** 113 * Get available connection from pool 114 * 115 * @return 116 * @throws SQLException 117 */ 118 public synchronized DbConnection getConnection() throws SQLException { 119 if (availableList.isEmpty()) 120 if (inUseList.size() < maxPoolSize) 121 addNewConnection(); 122 else // no available connections 123 throw new SQLException("Connection pool size exceeds maximum value"); 124 DbConnection dbConnection = availableList.remove(availableList.size() - 1); 125 inUseList.add(dbConnection); 126 return dbConnection; 127 } 128 129 /** 130 * Release connection 131 * 132 * @param dbConnection 133 * @return true if connection successfully released 134 * @throws SQLException 135 */ 136 public boolean releaseConnection(DbConnection dbConnection) throws SQLException { 137 dbConnection.getConnection().commit(); 138 availableList.add(dbConnection); 139 return inUseList.remove(dbConnection); 140 } 141 142 /** 143 * Add new connection to pool 144 * 145 * @throws SQLException 146 */ 147 private void addNewConnection() throws SQLException { 148 Connection connection; 149 if (jdbcProperties != null && !jdbcProperties.isEmpty()) 150 connection = DriverManager.getConnection(jdbcUrl, jdbcProperties); 151 else if (jdbcUser != null) 152 connection = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword); 153 else 154 connection = DriverManager.getConnection(jdbcUrl); 155 156 connection.setAutoCommit(false); 157 158 DbConnection dbConnection = new DbConnection(connection); 159 availableList.add(dbConnection); 160 } 161 162} 163 164/* 165Please contact FBSQL Team by E-Mail fbsql.team@gmail.com 166or visit https://fbsql.github.io if you need additional 167information or have any questions. 168*/ 169 170/* EOF */