001/******************************************************************************* 002The MIT License (MIT) 003 004Copyright (c) 2024 KILLCODING.COM 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 014all copies 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 022THE SOFTWARE. 023*****************************************************************************/ 024package com.killcoding.datasource; 025 026import java.util.List; 027import java.util.ArrayList; 028import java.util.Map; 029import java.util.concurrent.ConcurrentHashMap; 030import java.util.stream.Collectors; 031import com.killcoding.log.LoggerFactory; 032import com.killcoding.log.Logger; 033import java.util.Date; 034import java.sql.Connection; 035import java.util.HashMap; 036 037/** 038 * This class functions as a connection pool counter 039 * */ 040public class ConnectionPool { 041 042 /** 043 * Record all connection hash code 044 * */ 045 private final Map<Long, Integer> CONNECTION_POOL = new ConcurrentHashMap<Long, Integer>(); 046 047 private final Map<Integer, String> CONNECTION_THREAD_MARK = new ConcurrentHashMap<Integer, String>(); 048 private final Map<Integer, Connection> CONNECTION_MARK = new ConcurrentHashMap<Integer, Connection>(); 049 private final Map<Integer, Date> CONNECTION_OPENED_AT_MARK = new ConcurrentHashMap<Integer, Date>(); 050 private final Map<Integer, Date> CONNECTION_USING_AT_MARK = new ConcurrentHashMap<Integer, Date>(); 051 private final Map<Integer, Date> CONNECTION_IDLE_BEGIN_MARK = new ConcurrentHashMap<Integer, Date>(); 052 053 /** 054 * New a ConnectionPool object 055 * */ 056 public ConnectionPool() { 057 super(); 058 } 059 060 /** 061 * List all connection hash code 062 * @return Map - All connection hash code map 063 * */ 064 public synchronized Map<Long,Integer> map() { 065 return new HashMap<Long,Integer>(CONNECTION_POOL); 066 } 067 068 /** 069 * List all connection hash code 070 * @return List - All connection hash code 071 * */ 072 public synchronized List<Integer> list() { 073 List<Integer> list = new ArrayList<Integer>(); 074 List<Long> klist = CONNECTION_POOL.keySet() 075 .stream() 076 .sorted() 077 .collect(Collectors.toList()); 078 for(Object k : klist){ 079 list.add((Integer)CONNECTION_POOL.get(k)); 080 } 081 return list; 082 } 083 084 /** 085 * Get connection pool size 086 * @return int - All connection size 087 * */ 088 public synchronized int size() { 089 return CONNECTION_POOL.keySet().size(); 090 } 091 092 093 protected synchronized boolean add(Connection conn) { 094 Integer connHashCode = conn.hashCode(); 095 if(!contains(connHashCode)){ 096 Long newKey = System.nanoTime(); 097 while(CONNECTION_POOL.containsKey(newKey)){ 098 newKey = System.nanoTime(); 099 } 100 101 final Date openedAt = new Date(); 102 CONNECTION_IDLE_BEGIN_MARK.put(connHashCode, openedAt); 103 CONNECTION_OPENED_AT_MARK.put(connHashCode, openedAt); 104 CONNECTION_MARK.put(connHashCode, conn); 105 CONNECTION_POOL.put(newKey,connHashCode); 106 return true; 107 } 108 return false; 109 } 110 111 protected synchronized void freed(Integer connHashCode) { 112 if(!contains(connHashCode)){ 113 Long newKey = System.nanoTime(); 114 while(CONNECTION_POOL.containsKey(newKey)){ 115 newKey = System.nanoTime(); 116 } 117 CONNECTION_POOL.put(newKey,connHashCode); 118 } 119 CONNECTION_IDLE_BEGIN_MARK.put(connHashCode, new Date()); 120 } 121 122 protected synchronized void removeAll(Integer connHashCode) { 123 CONNECTION_MARK.remove(connHashCode); 124 CONNECTION_OPENED_AT_MARK.remove(connHashCode); 125 CONNECTION_USING_AT_MARK.remove(connHashCode); 126 CONNECTION_IDLE_BEGIN_MARK.remove(connHashCode); 127 CONNECTION_THREAD_MARK.remove(connHashCode); 128 remove(connHashCode); 129 } 130 131 protected synchronized Boolean remove(Integer connHashCode) { 132 List klist = new ArrayList(CONNECTION_POOL.keySet()); 133 Object rmKey = -1; 134 int size = klist.size(); 135 for(int i = 0;i < size;i++){ 136 Object key = klist.get(i); 137 Object hashCode = (Integer)CONNECTION_POOL.get(key); 138 if(hashCode.equals(connHashCode)){ 139 rmKey = key; 140 break; 141 } 142 } 143 if(rmKey.equals(-1)){ 144 return false; 145 }else{ 146 Object rmHashCode = CONNECTION_POOL.remove(rmKey); 147 return rmHashCode != null; 148 } 149 } 150 151 public synchronized boolean contains(Integer connHashCode) { 152 return list().contains(connHashCode); 153 } 154 155 private synchronized Integer get() { 156 try{ 157 Integer hashCode = list().get(0); 158 remove(hashCode); 159 return hashCode; 160 }catch(Exception e){ 161 LoggerFactory.getLogger(ConnectionPool.class).error(e.getMessage(),e); 162 return null; 163 } 164 } 165 166 public synchronized Integer getOpenConnectionSize() { 167 return CONNECTION_OPENED_AT_MARK.keySet().size(); 168 } 169 170 public synchronized Map<Integer, Date> getConnectionOpenedAtMark(){ 171 return new HashMap<Integer, Date>(CONNECTION_OPENED_AT_MARK); 172 } 173 174 protected synchronized Object removeConnectionOpenedAtMark(Integer hashCode){ 175 return CONNECTION_OPENED_AT_MARK.remove(hashCode); 176 } 177 178 protected synchronized Object setConnectionOpenedAtMark(Integer hashCode,Date date){ 179 return CONNECTION_OPENED_AT_MARK.put(hashCode,date); 180 } 181 182 public synchronized Map<Integer, Date> getConnectionUsingAtMark(){ 183 return new HashMap<Integer, Date>(CONNECTION_USING_AT_MARK); 184 } 185 186 protected synchronized Object removeConnectionUsingAtMark(Integer hashCode){ 187 return CONNECTION_USING_AT_MARK.remove(hashCode); 188 } 189 190 protected synchronized Object setConnectionUsingAtMark(Integer hashCode,Date date){ 191 return CONNECTION_USING_AT_MARK.put(hashCode,date); 192 } 193 194 protected synchronized Map<Integer, Connection> getConnectionMark(){ 195 return CONNECTION_MARK; 196 } 197 198 protected synchronized Connection getConnection(){ 199 Thread ct = Thread.currentThread(); 200 String tn = ct.getName(); 201 long tid = ct.getId(); 202 Integer hashCode = get(); 203 204 if(hashCode == null) return null; 205 206 CONNECTION_USING_AT_MARK.put(hashCode, new Date()); 207 CONNECTION_IDLE_BEGIN_MARK.remove(hashCode); 208 CONNECTION_THREAD_MARK.put(hashCode, String.format("%s-%s", tn, tid)); 209 return CONNECTION_MARK.get(hashCode); 210 } 211 212 protected synchronized Object removeConnectionMark(Integer hashCode){ 213 return CONNECTION_MARK.remove(hashCode); 214 } 215 216 protected synchronized Object setConnectionMark(Integer hashCode,Connection conn){ 217 return CONNECTION_MARK.put(hashCode,conn); 218 } 219 220 public synchronized Map<Integer, Date> getConnectionIdleBeginMark(){ 221 return new HashMap<Integer,Date>(CONNECTION_IDLE_BEGIN_MARK); 222 } 223 224 protected synchronized Object removeConnectionIdleBeginMark(Integer hashCode){ 225 return CONNECTION_IDLE_BEGIN_MARK.remove(hashCode); 226 } 227 228 protected synchronized Object setConnectionIdleBeginMark(Integer hashCode,Date date){ 229 return CONNECTION_IDLE_BEGIN_MARK.put(hashCode,date); 230 } 231 232 public synchronized Map<Integer, String> getConnectionThreadMark(){ 233 return new HashMap<Integer, String>(CONNECTION_THREAD_MARK); 234 } 235 236}