1 22 23 package org.cofax.connectionpool; 24 25 import java.sql.*; 26 import java.util.*; 27 import java.io.*; 28 import org.cofax.CofaxUtil; 29 30 public class ConnectionPool { 31 32 final static boolean DEBUG = false; 33 34 private String name; 35 36 private String URL; 37 38 private String user; 39 40 private String password; 41 42 private int maxConns; 43 44 private int timeOut; 45 46 private int initConns; 47 48 private int connUsageLimit; 49 50 private int peakInUse; 51 52 private int avgInUse; 53 54 private LogWriter logWriter; 55 56 private String testQuery; 57 58 private long connUsageTimeToDie = CofaxUtil.MILLISECONDS_PER_SECOND * 30; 60 66 private long numConnCleanUps; 67 68 private long numConnsCleaned; 69 70 private long peakRunTime; 71 72 private long numConnsReq; 73 74 private long numConnsDel; 75 76 private long numConnsRet; 77 78 private long totalRunTime; 79 80 private long totalInUse; 81 82 private long numWait; 83 84 private double avgRunTime; 85 86 private Vector freeConnections = new Vector(); 87 88 private Vector usedConnections = new Vector(); 89 90 public ConnectionPool(String name, String URL, String user, String password, int maxConns, int inInitConns, int inTimeOut, PrintWriter pw, int logLevel, 91 String testQuery, int connUsageLimit) { 92 93 this.name = name; 94 this.URL = URL; 95 this.user = user; 96 this.password = password; 97 this.maxConns = maxConns; 98 this.initConns = inInitConns; 99 this.testQuery = testQuery; 100 this.connUsageLimit = connUsageLimit; 101 this.timeOut = inTimeOut > 0 ? inTimeOut : 5; 102 this.numConnCleanUps = 0; 103 this.numConnsCleaned = 0; 104 this.peakInUse = 1; 105 this.peakRunTime = 0; 106 this.avgRunTime = 0.0; 107 this.avgInUse = 0; 108 this.numConnsReq = 0; 109 this.numConnsDel = 0; 110 this.numConnsRet = 0; 111 this.totalRunTime = 0; 112 this.totalInUse = 0; 113 this.numWait = 0; 114 115 logWriter = new LogWriter(name, logLevel, pw); 116 creatInitConnections(); 117 118 logWriter.log("SYS: New pool created", LogWriter.INFO); 119 String lf = System.getProperty("line.separator"); 120 logWriter.log(lf + " url=" + URL + lf + " user=" + user + lf + " password=" + password + lf + " initconns=" + initConns + lf + " maxconns=" + maxConns 121 + lf + " testQuery=" + testQuery + lf + " connUsageLimit=" + connUsageLimit + lf + " logintimeout=" + this.timeOut, LogWriter.DEBUG); 122 logWriter.log(getStats(), LogWriter.DEBUG); 123 } 124 125 public String getURL() { 126 return URL; 127 } 128 129 public String getUser() { 130 return user; 131 } 132 133 public String getPassword() { 134 return password; 135 } 136 137 public int getMaxConns() { 138 return maxConns; 139 } 140 141 public int getInitConns() { 142 return initConns; 143 } 144 145 public int getTimeOut() { 146 return timeOut; 147 } 148 149 public int getConUsageLimit() { 150 return connUsageLimit; 151 } 152 153 public long getKillTime() { 154 return connUsageTimeToDie; 155 } 156 157 public void setURL(String inURL) { 158 URL = inURL; 159 } 160 161 public void setUser(String inUser) { 162 user = inUser; 163 } 164 165 public void setPassword(String inPassowrd) { 166 password = inPassowrd; 167 } 168 169 public void setMaxConns(int inMaxConns) { 170 maxConns = inMaxConns; 171 } 172 173 public void setInitConns(int inInitConns) { 174 initConns = inInitConns; 175 } 176 177 public void setTimeOut(int inTimeOut) { 178 timeOut = inTimeOut; 179 } 180 181 public void setConUsageLimit(int inConnUsageLimit) { 182 connUsageLimit = inConnUsageLimit; 183 } 184 185 public void setKillTime(long inKillTime) { 186 connUsageTimeToDie = inKillTime; 187 } 188 189 private void creatInitConnections() { 190 191 int curCons = freeConnections.size() + usedConnections.size(); 192 193 for (int i = curCons; i < this.initConns; i++) { 194 try { 195 ConnectionWrapper newCon = newConnection(); 196 freeConnections.addElement(newCon); 197 } catch (SQLException e) { 198 logWriter.log("Error Creating Init Connection:" + e.toString(), LogWriter.ERROR); 199 } 200 } 201 } 202 203 public ConnectionWrapper getConnection() throws SQLException { 204 try { 206 ConnectionWrapper conn = getConnection(timeOut * 1000); 207 return conn; 208 } catch (SQLException e) { 209 logWriter.log(e, "Exception getting connection", LogWriter.ERROR); 210 throw e; 213 } 214 } 215 216 public synchronized void freeConnection(ConnectionWrapper conn) { 217 218 java.util.Date currDate = new java.util.Date (); 220 long curTime = currDate.getTime(); 221 long timeInUse; 222 223 this.numConnsRet++; 224 timeInUse = curTime - conn.getLastTimeUsed(); 225 this.totalRunTime += timeInUse; 226 this.avgRunTime = ((double) this.totalRunTime / this.numConnsRet); 227 conn.setLastTimeUsed(); 228 freeConnections.addElement(conn); 229 usedConnections.remove(conn); 230 logWriter.log("CON: Released ConnectionID: " + conn.getConnectionId() + " |was in use for: " + timeInUse + " mSecs |was running: " 233 + conn.getCurrentActivity(), LogWriter.INFO); 234 logWriter.log(getStats(), LogWriter.DEBUG); 235 236 } 237 238 private synchronized ConnectionWrapper getConnection(long timeout) throws SQLException { 239 240 244 long startTime = System.currentTimeMillis(); 245 long remaining = timeout; 246 ConnectionWrapper conn = null; 247 long sleepTime = (long) (remaining / 4); 250 while ((conn = getPooledConnection()) == null) { 251 try { 252 logWriter.log("CON: All Connections in use, waiting for: " + remaining + " mSecs", LogWriter.DEBUG); 253 wait(sleepTime); 254 numWait++; 255 } catch (InterruptedException e) { 256 } 257 remaining = timeout - (System.currentTimeMillis() - startTime); 258 if (remaining <= 0) { 259 logWriter.log("ERR: Timed out waiting for con, throwing error...", LogWriter.DEBUG); 261 logWriter.log(getStats(), LogWriter.DEBUG); 262 throw new SQLException("getConnection() timed-out"); 263 } 264 } 265 266 if (!isConnectionOK(conn)) { 268 return getConnection(remaining); 270 } 271 272 if (freeConnections.size() + usedConnections.size() < this.initConns) { 276 logWriter.log("SYS: Connection Pool below initial size, rebuilding now...", LogWriter.INFO); 277 this.creatInitConnections(); 278 } 279 280 java.util.Date currDate = new java.util.Date (); 281 long curTime = currDate.getTime(); 282 long timeSinceCreated = curTime - conn.getTimeCreated(); 283 logWriter.log("CON: Pool Use ConnectionID: " + conn.getConnectionId() + " |Use Count: " + conn.getTimesUsed() + " |Time Alive: " + timeSinceCreated 284 + " mSecs", LogWriter.INFO); 285 logWriter.log(getStats(), LogWriter.DEBUG); 286 return conn; 287 288 } 289 290 private boolean isConnectionOK(ConnectionWrapper conn) { 291 292 if (conn == null) 293 return false; 294 295 long connId = conn.getConnectionId(); 296 if (DEBUG) 297 logWriter.log("CON: Checking ConnectionID: " + connId, LogWriter.DEBUG); 298 299 if (conn.getTimesUsed() > connUsageLimit) { 300 try { 301 usedConnections.remove(conn); 302 conn.closeConnection(); 303 conn = null; 304 if ((this.freeConnections.size() + this.usedConnections.size()) < this.initConns) { 305 ConnectionWrapper newCon = newConnection(); 306 freeConnections.addElement(newCon); 307 } 308 } catch (SQLException se) { 309 logWriter.log("ERR: Error closing connection: " + se, LogWriter.DEBUG); 310 } finally { 311 conn = null; 312 } 313 logWriter.log("CON: Use limit reached ConnectionID: " + connId, LogWriter.DEBUG); 314 return false; 315 } 316 Statement testStmt = null; 317 try { 318 if (!conn.isClosed()) { 319 testStmt = conn.createStatement(); 321 testStmt.execute(testQuery); 322 testStmt.close(); 323 324 } else { 325 logWriter.log("ERR: Connection was already closed!", LogWriter.ERROR); 326 throw new SQLException("Connection was already closed"); 327 } 328 } catch (SQLException e) { 329 logWriter.log("ERR: Testing of the connection failed: " + e.getMessage(), LogWriter.ERROR); 330 if (testStmt != null) { 332 try { 333 testStmt.close(); 334 } catch (SQLException se) { 335 logWriter.log("ERR: Error closing connection: " + se, LogWriter.ERROR); 336 } 337 } 338 if (conn != null) { 340 try { 341 logWriter.log("DEBUG: Removing connection from pool", LogWriter.DEBUG); 342 usedConnections.remove(conn); 343 conn.closeConnection(); 344 conn = null; 345 } catch (SQLException se) { 346 logWriter.log("ERR : Error removing bad connection: " + se.getMessage(), LogWriter.ERROR); 347 } 348 } 349 return false; 350 } 351 return true; 352 353 } 354 355 368 private ConnectionWrapper getPooledConnection() { 369 370 ConnectionWrapper conn = null; 371 372 this.numConnsReq++; 373 this.runBadConnCleanUp(); 374 if (freeConnections.size() > 0) { 375 conn = (ConnectionWrapper) freeConnections.firstElement(); 376 conn.incrementTimesUsed(); 377 freeConnections.remove(conn); 378 } else if (maxConns == 0 || (freeConnections.size() + usedConnections.size() < maxConns)) { 379 try { 380 conn = newConnection(); 381 conn.incrementTimesUsed(); 382 } catch (Exception e) { 383 } 384 } 385 if (conn != null) { 386 usedConnections.addElement(conn); 387 this.numConnsDel++; 388 } 389 390 this.totalInUse += usedConnections.size(); 391 this.avgInUse = (int) (this.totalInUse / this.numConnsReq); 392 if (usedConnections.size() > this.peakInUse) 393 this.peakInUse = usedConnections.size(); 394 395 return conn; 396 397 } 398 399 410 private synchronized boolean runBadConnCleanUp() { 411 412 boolean cleaned = false; 413 414 if (usedConnections.size() > 0) { 415 this.numConnCleanUps++; 416 417 Enumeration uCons = usedConnections.elements(); 418 ConnectionWrapper con; 419 java.util.Date currDate = new java.util.Date (); 420 long curTime = currDate.getTime(); 421 long timeInUse; 422 423 logWriter.log("SYS: Checking for errant connections", LogWriter.INFO); 424 while (uCons.hasMoreElements()) { 425 con = (ConnectionWrapper) uCons.nextElement(); 426 timeInUse = curTime - con.getLastTimeUsed(); 427 if (timeInUse > this.peakRunTime) 428 this.peakRunTime = timeInUse; 429 430 if (timeInUse >= this.connUsageTimeToDie) { 431 try { 432 logWriter.log("CON: Killing errant ConnectionID: " + con.getConnectionId() + " |Use Time: " + timeInUse + " mSecs |Query: " 433 + con.getCurrentActivity(), LogWriter.INFO); 434 usedConnections.remove(con); 435 con.closeConnection(); 436 con = null; 437 this.numConnsCleaned++; 438 cleaned = true; 439 } catch (Exception e) { 440 logWriter.log("ERR: Could not kill errant ConnectionID : " + con.getConnectionId() + " |Reason: " + e.toString(), LogWriter.ERROR); 441 } 442 } 443 } 444 } 445 return cleaned; 446 447 } 448 449 private ConnectionWrapper newConnection() throws SQLException { 450 451 Connection conn = null; 452 if (user == null) 453 conn = DriverManager.getConnection(URL); 454 else 455 conn = DriverManager.getConnection(URL, user, password); 456 ConnectionWrapper newCon = new ConnectionWrapper(conn, this); 457 logWriter.log("CON: Created a new ConnectionID: " + newCon.getConnectionId(), LogWriter.INFO); 458 return newCon; 459 460 } 461 462 public synchronized void release() { 463 464 Enumeration allConnections = freeConnections.elements(); 465 while (allConnections.hasMoreElements()) { 466 ConnectionWrapper con = (ConnectionWrapper) allConnections.nextElement(); 467 long connId = con.getConnectionId(); 468 try { 469 logWriter.log("CON: Closed ConnectionID: " + connId, LogWriter.INFO); 470 freeConnections.remove(con); 471 con.closeConnection(); 472 con = null; 473 } catch (SQLException e) { 474 logWriter.log(e, "ERR: Couldn't close connection", LogWriter.ERROR); 475 } 476 } 477 freeConnections.removeAllElements(); 478 479 allConnections = usedConnections.elements(); 480 while (allConnections.hasMoreElements()) { 481 ConnectionWrapper con = (ConnectionWrapper) allConnections.nextElement(); 482 long connId = con.getConnectionId(); 483 try { 484 logWriter.log("CON: Closed ConnectionID: " + connId, LogWriter.INFO); 485 usedConnections.remove(con); 486 con.closeConnection(); 487 con = null; 488 } catch (SQLException e) { 489 logWriter.log(e, "ERR: Couldn't close connection", LogWriter.ERROR); 490 } 491 } 492 usedConnections.removeAllElements(); 493 494 } 495 496 private String getStats() { 497 498 String retVal = "STAT: Total connections: " + (freeConnections.size() + usedConnections.size()) + " |Available: " + freeConnections.size() 499 + " |In Use: " + usedConnections.size(); 500 return (retVal); 501 502 } 503 504 512 public String getConnectionStats() { 513 514 String outPut; 515 Enumeration uCons = usedConnections.elements(); 516 Enumeration fCons = freeConnections.elements(); 517 ConnectionWrapper con; 518 java.util.Date currDate = new java.util.Date (); 519 long curTime = currDate.getTime(); 520 long timeSinceCreated; 521 long timeSinceUsed; 522 523 long uConns = usedConnections.size(); 524 long fConns = freeConnections.size(); 525 long tConns = uConns + fConns; 526 long tDie = this.connUsageTimeToDie / CofaxUtil.MILLISECONDS_PER_SECOND; 527 long tPRt = this.peakRunTime / CofaxUtil.MILLISECONDS_PER_SECOND; 528 double tAvgRt = this.avgRunTime / CofaxUtil.MILLISECONDS_PER_SECOND; 529 530 outPut = "<br><br><table border=1>\n"; 532 outPut += "<tr><td colspan=2 bgColor=FFEEFF align=center><font size=4>Connection Pool Settings</font></td></tr>\n"; 533 outPut += "<tr><td bgColor=FFEEFF>Connection Pool Name:</td><td>" + this.name + "</td></tr>\n"; 534 outPut += "<tr><td bgColor=FFEEFF>Initial Number of Connections:</td><td>" + this.initConns + "</td></tr>\n"; 535 outPut += "<tr><td bgColor=FFEEFF>Max Number of Connections:</td><td>" + this.maxConns + "</td></tr>\n"; 536 outPut += "<tr><td bgColor=FFEEFF>Usage Limit for Conns</td><td>" + this.connUsageLimit + "</td></tr>\n"; 537 outPut += "<tr><td bgColor=FFEEFF>Wait for Conn Time:</td><td>" + this.timeOut + "</td></tr>\n"; 538 outPut += "<tr><td bgColor=FFEEFF>Time before In-use con is killed:</td><td>" + tDie + "</td></tr>\n"; 539 540 outPut += "<tr><td colspan=2 bgColor=FFEEFF align=center><font size=4>Connection Pool Stats</font></td></tr>\n"; 541 outPut += "<tr><td bgColor=FFEEFF>Current Connections Total/In Use/Avail:</td>\n"; 542 outPut += "<td>" + tConns + "/" + uConns + "/" + fConns + "</td></tr>\n"; 543 outPut += "<tr><td bgColor=FFEEFF>Total Number of Cons Requeted</td><td>" + this.numConnsReq + "</td></tr>\n"; 544 outPut += "<tr><td bgColor=FFEEFF>Total Number of Cons Delivered</td><td>" + this.numConnsDel + "</td></tr>\n"; 545 outPut += "<tr><td bgColor=FFEEFF>Total Number of Cons Returned</td><td>" + this.numConnsRet + "</td></tr>\n"; 546 outPut += "<tr><td bgColor=FFEEFF>Numer of Requests which had to wait</td><td>" + this.numWait + "</td></tr>\n"; 547 outPut += "<tr><td bgColor=FFEEFF>Average Number of Cons in Use(at any time)</td><td>" + this.avgInUse + "</td></tr>\n"; 548 outPut += "<tr><td bgColor=FFEEFF>Peak Number of Cons is Use:</td><td>" + this.peakInUse + "</td></tr>\n"; 549 outPut += "<tr><td bgColor=FFEEFF>Average Con Use Time</td><td>" + tAvgRt + "</td></tr>\n"; 550 outPut += "<tr><td bgColor=FFEEFF>Peak Con Use Time:</td><td>" + tPRt + "</td></tr>\n"; 551 outPut += "<tr><td bgColor=FFEEFF>Number of times Con cleanup has run:</td><td>" + this.numConnCleanUps + "</td></tr>\n"; 552 outPut += "<tr><td bgColor=FFEEFF>Number of cleaned Cons :</td><td>" + this.numConnsCleaned + "</td></tr>\n"; 553 554 outPut += "</table>\n"; 555 556 outPut += "<br><br><table border=1>\n"; 558 outPut += "<tr><td colspan=5 bgColor=FFEEFF align=center><font size=4>In Use Connections(" + uConns + ")</font></td></tr>\n"; 559 outPut += "<tr><td bgColor=FFEEFF>ConnectionID</td>\n"; 560 outPut += "<td bgColor=FFEEFF>Number of times used</td>\n"; 561 outPut += "<td bgColor=FFEEFF>Time Since Created(Sec)</td>\n"; 562 outPut += "<td bgColor=FFEEFF>Time since this use started(Sec)</td>\n"; 563 outPut += "<td bgColor=FFEEFF>Current Activity</td></tr>\n"; 564 while (uCons.hasMoreElements()) { 565 con = (ConnectionWrapper) uCons.nextElement(); 566 timeSinceCreated = ((curTime - con.getTimeCreated()) / CofaxUtil.MILLISECONDS_PER_SECOND); 567 timeSinceUsed = ((curTime - con.getLastTimeUsed()) / CofaxUtil.MILLISECONDS_PER_SECOND); 568 outPut += "<tr><td>" + con.getConnectionId() + "</td>\n"; 569 outPut += "<td>" + con.getTimesUsed() + "</td>\n"; 570 outPut += "<td>" + timeSinceCreated + "</td>\n"; 571 outPut += "<td>" + timeSinceUsed + "</td><td>\n"; 572 if (con.getCurrentActivity() != null) 573 outPut += con.getCurrentActivity(); 574 else 575 outPut += "Has not been used Yet"; 576 outPut += "</td></tr>\n"; 577 } 578 outPut += "</table>\n"; 579 580 outPut += "<br><br><table border=1>\n"; 582 outPut += "<tr><td colspan=5 bgColor=FFEEFF align=center><font size=4>Available Connections(" + fConns + ")</font></td></tr>\n"; 583 outPut += "<tr><td bgColor=FFEEFF>ConnectionID</td>\n"; 584 outPut += "<td bgColor=FFEEFF>Number of times used</td>\n"; 585 outPut += "<td bgColor=FFEEFF>Time Since Created(Sec)</td>\n"; 586 outPut += "<td bgColor=FFEEFF>Time since last used(Sec)</td>\n"; 587 outPut += "<td bgColor=FFEEFF>Last Activity</td></tr>\n"; 588 while (fCons.hasMoreElements()) { 589 con = (ConnectionWrapper) fCons.nextElement(); 590 timeSinceCreated = ((curTime - con.getTimeCreated()) / CofaxUtil.MILLISECONDS_PER_SECOND); 591 timeSinceUsed = ((curTime - con.getLastTimeUsed()) / CofaxUtil.MILLISECONDS_PER_SECOND); 592 outPut += "<tr><td>" + con.getConnectionId() + "</td>\n"; 593 outPut += "<td>" + con.getTimesUsed() + "</td>\n"; 594 outPut += "<td>" + timeSinceCreated + "</td>\n"; 595 outPut += "<td>" + timeSinceUsed + "</td><td>\n"; 596 if (con.getCurrentActivity() != null) 597 outPut += con.getCurrentActivity(); 598 else 599 outPut += "Has not been used Yet"; 600 outPut += "</td></tr>\n"; 601 } 602 outPut += "</table>\n"; 603 return (outPut); 604 605 } 606 607 } 608 | Popular Tags |