1 19 20 21 package org.apache.cayenne.conn; 22 23 import java.io.PrintWriter ; 24 import java.sql.Connection ; 25 import java.sql.SQLException ; 26 import java.util.LinkedList ; 27 import java.util.List ; 28 import java.util.ListIterator ; 29 30 import javax.sql.ConnectionEvent ; 31 import javax.sql.ConnectionEventListener ; 32 import javax.sql.ConnectionPoolDataSource ; 33 import javax.sql.DataSource ; 34 import javax.sql.PooledConnection ; 35 36 43 public class PoolManager implements DataSource , ConnectionEventListener { 44 45 51 public static final int MAX_QUEUE_WAIT = 20000; 52 53 protected ConnectionPoolDataSource poolDataSource; 54 protected int minConnections; 55 protected int maxConnections; 56 protected String dataSourceUrl; 57 protected String jdbcDriver; 58 protected String password; 59 protected String userName; 60 61 protected List unusedPool; 62 protected List usedPool; 63 64 private PoolMaintenanceThread poolMaintenanceThread; 65 66 67 71 public PoolManager( 72 String jdbcDriver, 73 String dataSourceUrl, 74 int minCons, 75 int maxCons, 76 String userName, 77 String password) 78 throws SQLException { 79 80 this(jdbcDriver, dataSourceUrl, minCons, maxCons, userName, password, null); 81 } 82 83 public PoolManager( 84 String jdbcDriver, 85 String dataSourceUrl, 86 int minCons, 87 int maxCons, 88 String userName, 89 String password, 90 ConnectionEventLoggingDelegate logger) 91 throws SQLException { 92 93 if (logger != null) { 94 DataSourceInfo info = new DataSourceInfo(); 95 info.setJdbcDriver(jdbcDriver); 96 info.setDataSourceUrl(dataSourceUrl); 97 info.setMinConnections(minCons); 98 info.setMaxConnections(maxCons); 99 info.setUserName(userName); 100 info.setPassword(password); 101 logger.logPoolCreated(info); 102 } 103 104 this.jdbcDriver = jdbcDriver; 105 this.dataSourceUrl = dataSourceUrl; 106 DriverDataSource driverDS = new DriverDataSource(jdbcDriver, dataSourceUrl); 107 driverDS.setLogger(logger); 108 PoolDataSource poolDS = new PoolDataSource(driverDS); 109 init(poolDS, minCons, maxCons, userName, password); 110 } 111 112 122 public PoolManager( 123 ConnectionPoolDataSource poolDataSource, 124 int minCons, 125 int maxCons, 126 String userName, 127 String password) 128 throws SQLException { 129 init(poolDataSource, minCons, maxCons, userName, password); 130 } 131 132 133 protected void init( 134 ConnectionPoolDataSource poolDataSource, 135 int minCons, 136 int maxCons, 137 String userName, 138 String password) 139 throws SQLException { 140 141 if (maxConnections < 0) { 143 throw new SQLException ( 144 "Maximum number of connections can not be negative (" + maxCons + ")."); 145 } 146 147 if (minConnections < 0) { 148 throw new SQLException ( 149 "Minimum number of connections can not be negative (" + minCons + ")."); 150 } 151 152 if (minConnections > maxConnections) { 153 throw new SQLException ("Minimum number of connections can not be bigger then maximum."); 154 } 155 156 this.userName = userName; 158 this.password = password; 159 this.minConnections = minCons; 160 this.maxConnections = maxCons; 161 this.poolDataSource = poolDataSource; 162 163 usedPool = new LinkedList (); 165 unusedPool = new LinkedList (); 166 growPool(minConnections, userName, password); 167 168 startMaintenanceThread(); 169 } 170 171 protected synchronized void startMaintenanceThread() { 172 disposeOfMaintenanceThread(); 173 this.poolMaintenanceThread = new PoolMaintenanceThread(this); 174 this.poolMaintenanceThread.start(); 175 } 176 177 181 protected PooledConnection newPooledConnection(String userName, String password) 182 throws SQLException { 183 PooledConnection connection = 184 (userName != null) 185 ? poolDataSource.getPooledConnection(userName, password) 186 : poolDataSource.getPooledConnection(); 187 connection.addConnectionEventListener(this); 188 return connection; 189 } 190 191 192 public void dispose() throws SQLException { 193 synchronized (this) { 194 ListIterator unusedIterator = unusedPool.listIterator(); 196 while (unusedIterator.hasNext()) { 197 PooledConnection con = (PooledConnection ) unusedIterator.next(); 198 con.close(); 200 unusedIterator.remove(); 202 } 203 204 ListIterator usedIterator = usedPool.listIterator(); 206 while (usedIterator.hasNext()) { 207 PooledConnection con = (PooledConnection ) usedIterator.next(); 208 con.removeConnectionEventListener(this); 210 con.close(); 212 usedIterator.remove(); 214 } 215 } 216 217 disposeOfMaintenanceThread(); 218 } 219 220 protected void disposeOfMaintenanceThread() { 221 if (poolMaintenanceThread != null) { 222 this.poolMaintenanceThread.dispose(); 223 } 224 } 225 226 229 protected synchronized boolean canGrowPool() { 230 return getPoolSize() < maxConnections; 231 } 232 233 239 protected synchronized int growPool( 240 int addConnections, 241 String userName, 242 String password) 243 throws SQLException { 244 245 int i = 0; 246 int startPoolSize = getPoolSize(); 247 for (; i < addConnections && startPoolSize + i < maxConnections; i++) { 248 PooledConnection newConnection = newPooledConnection(userName, password); 249 unusedPool.add(newConnection); 250 } 251 252 return i; 253 } 254 255 protected synchronized void shrinkPool(int closeConnections) { 256 int idleSize = unusedPool.size(); 257 for (int i = 0; i < closeConnections && i < idleSize; i++) { 258 PooledConnection con = (PooledConnection ) unusedPool.remove(i); 259 260 try { 261 con.close(); 262 } catch (SQLException ex) { 263 } 265 } 266 } 267 268 273 public int getMaxConnections() { 274 return maxConnections; 275 } 276 277 public void setMaxConnections(int maxConnections) { 278 this.maxConnections = maxConnections; 279 } 280 281 283 public int getMinConnections() { 284 return minConnections; 285 } 286 287 public void setMinConnections(int minConnections) { 288 this.minConnections = minConnections; 289 } 290 291 293 public String getDataSourceUrl() { 294 return dataSourceUrl; 295 } 296 297 299 public String getJdbcDriver() { 300 return jdbcDriver; 301 } 302 303 304 public String getPassword() { 305 return password; 306 } 307 308 309 public String getUserName() { 310 return userName; 311 } 312 313 316 public synchronized int getPoolSize() { 317 return usedPool.size() + unusedPool.size(); 318 } 319 320 324 public synchronized int getCurrentlyInUse() { 325 return usedPool.size(); 326 } 327 328 333 public synchronized int getCurrentlyUnused() { 334 return unusedPool.size(); 335 } 336 337 343 public Connection getConnection() throws SQLException { 344 return getConnection(userName, password); 345 } 346 347 348 public synchronized Connection getConnection(String userName, String password) 349 throws SQLException { 350 351 PooledConnection pooledConnection = uncheckPooledConnection(userName, password); 352 353 try { 354 return uncheckConnection(pooledConnection); 355 } 356 catch (SQLException ex) { 357 358 try { 359 pooledConnection.close(); 360 } 361 catch (SQLException ignored) { 362 } 363 364 pooledConnection = uncheckPooledConnection(userName, password); 366 try { 367 return uncheckConnection(pooledConnection); 368 } 369 catch (SQLException reconnectEx) { 370 try { 371 pooledConnection.close(); 372 } 373 catch (SQLException ignored) { 374 } 375 376 throw reconnectEx; 377 } 378 } 379 } 380 381 private Connection uncheckConnection(PooledConnection pooledConnection) 382 throws SQLException { 383 Connection c = pooledConnection.getConnection(); 384 385 usedPool.add(pooledConnection); 387 return c; 388 } 389 390 private PooledConnection uncheckPooledConnection(String userName, String password) 391 throws SQLException { 392 395 if (unusedPool.size() == 0) { 396 397 if (canGrowPool()) { 399 return newPooledConnection(userName, password); 400 } 401 402 404 long waitTill = 409 System.currentTimeMillis() 410 + MAX_QUEUE_WAIT; 411 412 do { 413 try { 414 wait(MAX_QUEUE_WAIT); 415 } catch (InterruptedException iex) { 416 } 418 419 } while (unusedPool.size() == 0 && waitTill > System.currentTimeMillis()); 420 421 if (unusedPool.size() == 0) { 422 throw new SQLException ( 423 "Can't obtain connection. Request timed out. Total used connections: " 424 + usedPool.size()); 425 } 426 } 427 428 return (PooledConnection ) unusedPool.remove(0); 430 } 431 432 public int getLoginTimeout() throws java.sql.SQLException { 433 return poolDataSource.getLoginTimeout(); 434 } 435 436 public void setLoginTimeout(int seconds) throws java.sql.SQLException { 437 poolDataSource.setLoginTimeout(seconds); 438 } 439 440 public PrintWriter getLogWriter() throws java.sql.SQLException { 441 return poolDataSource.getLogWriter(); 442 } 443 444 public void setLogWriter(PrintWriter out) throws java.sql.SQLException { 445 poolDataSource.setLogWriter(out); 446 } 447 448 451 public synchronized void connectionClosed(ConnectionEvent event) { 452 PooledConnection closedConn = (PooledConnection ) event.getSource(); 454 455 int usedInd = usedPool.indexOf(closedConn); 458 if (usedInd >= 0) { 459 usedPool.remove(usedInd); 460 unusedPool.add(closedConn); 461 462 notifyAll(); 464 } 465 } 469 470 475 public synchronized void connectionErrorOccurred(ConnectionEvent event) { 476 479 PooledConnection errorSrc = (PooledConnection ) event.getSource(); 480 481 484 int usedInd = usedPool.indexOf(errorSrc); 485 if (usedInd >= 0) { 486 usedPool.remove(usedInd); 487 } else { 488 int unusedInd = unusedPool.indexOf(errorSrc); 489 if (unusedInd >= 0) 490 unusedPool.remove(unusedInd); 491 } 492 493 } 497 498 static class PoolMaintenanceThread extends Thread { 499 protected boolean shouldDie; 500 protected PoolManager pool; 501 502 PoolMaintenanceThread(PoolManager pool) { 503 super.setName("PoolManagerCleanup-" + pool.hashCode()); 504 super.setDaemon(true); 505 this.pool = pool; 506 } 507 508 public void run() { 509 while (true) { 511 512 try { 513 sleep(600000); 515 } catch (InterruptedException iex) { 516 } 518 519 if (shouldDie) { 520 break; 521 } 522 523 synchronized (pool) { 524 528 int unused = pool.getCurrentlyUnused(); 529 int used = pool.getCurrentlyInUse(); 530 int total = unused + used; 531 int median = 532 pool.minConnections 533 + 1 534 + (pool.maxConnections - pool.minConnections) / 2; 535 536 if (unused > 0 && total > median) { 537 pool.shrinkPool(1); 538 } 539 } 540 } 541 } 542 543 546 public void dispose() { 547 shouldDie = true; 548 } 549 } 550 } 551 | Popular Tags |