1 21 22 package uk.org.primrose.pool.core; 23 import java.util.Vector ; 24 import java.util.StringTokenizer ; 25 import java.io.PrintWriter ; 26 import java.io.Serializable ; 27 import java.sql.SQLException ; 28 import java.sql.Connection ; 29 30 public class Pool implements Serializable { 31 32 public Pool() {} 33 36 37 private boolean available; 39 private int base; 41 private int overflow; 43 private int allowedOverflow; 45 private String name; 47 private String driverClass; 49 private String driverURL; 50 private String user; 51 private String password; 52 private Vector availableConnections = new Vector (); 54 private Vector activeConnectionsData = new Vector (); 56 private Vector activeConnections = new Vector (); 57 private Vector killedConnections = new Vector (); 58 PrintWriter log; 60 boolean waitingThreads = false; 62 private boolean messageLogging = false; 64 private boolean sizeLogging = false; 65 private int cycleConnections = -1; 67 boolean runPooledMode = true; 68 boolean connectionAutoCommit = true; 69 private int idleTime = 0; 70 private int connectionTransactionIsolation = -1; 72 private String checkSQL = null; 74 public SyncHack synchack = new SyncHack(); 75 76 79 class SyncHack { 83 84 } 85 86 89 public Connection get() { 90 synchronized(synchack) { 91 if (!runPooledMode) { 92 log("Getting new non-pooled connection " +this, false); 95 Connection pc = new NewConnection().get(driverClass, driverURL, user, password); 96 if (!checkConnection(pc)) { 97 return null; 98 } 99 100 return pc; 101 } 102 if (availableConnections.size() > 0 && isAvailable()) { 109 PoolConnection pc = (PoolConnection)availableConnections.elementAt(0); 110 availableConnections.removeElement(pc); 111 log("Extracting connection from pool " +pc, true); 112 113 114 if (!checkConnection(pc)) { 121 log("Connection " +pc + " was closed. Creating a new one.", true); 122 dump(pc); 124 fill(1); 126 return get(); 128 } 129 130 activeConnectionsData.addElement(pc +"|" +System.currentTimeMillis()); 131 activeConnections.addElement(pc); 132 pc.setConnectionCalled(true); 133 134 return pc; 135 136 } else if ((availableConnections.size() < base) && (activeConnections.size() < base) && isAvailable()) { 137 log("Extracting connection due to base being low due to idle connections", false); 138 if (fill(1)) { return get(); 140 } else { 141 return null; 142 } 143 144 } else if (allowedOverflow > 0 && isAvailable()) { 145 log("Extracting connection by adding overflow ...", false); 146 fill(1); 147 allowedOverflow--; 150 return get(); 151 } else { 152 return null; 153 } 154 } 155 } 156 157 public boolean checkConnection(Connection pc) { 158 try { 159 if (pc.isClosed()) return false; 160 } catch (SQLException e) { 161 log("Error calling isClosed() on connection " +pc +" : " +e, false); 162 return false; 163 } 164 if (checkSQL != null) { 166 167 java.sql.Statement s = null; 168 java.sql.ResultSet rs = null; 169 try { 170 s = pc.createStatement(); 171 rs = s.executeQuery(checkSQL); 172 } catch (Exception e) { 173 log("SQL Check returned an error - dumping this connection(" +pc +"). Error was : " +e, false); 174 return false; 175 } finally { 176 try { 177 if (rs != null) rs.close(); 178 if (s != null) s.close(); 179 } catch (java.sql.SQLException sqle) {} 180 } 181 } 182 183 return true; 184 } 185 186 189 public boolean fill(int num) { 190 for (int i = 0; i < num; i++) { 191 PoolConnection pc = new PoolConnection(this).getConnection(driverClass, driverURL, user, password); 192 if (pc != null) { 193 if (checkConnection(pc)) { 194 setConnectionDefaults(pc); 196 availableConnections.addElement(pc); 197 log("Filled pool with connection " +pc, true); 198 } else { 199 log("New Connection was closed or broken ! Perhaps the database is down ?", true); 200 return false; 201 } 202 } else { 203 log("New Connection was NULL ! Perhaps the database is down ?", true); 204 return false; 205 } 206 } 207 return true; 208 } 209 210 211 214 public void put(PoolConnection pc) { 215 synchronized(synchack) { 216 217 if (!runPooledMode) { 218 log("Closing non-pooled connection " +this, false); 219 dump(pc, true); 220 return; 221 } 222 boolean dumped = false; 223 224 if (killedConnections.contains(pc)) { 229 return; 234 } 235 236 if (pc != null && (!pc.isClosed())) { 238 removeFromActiveConnections(pc); 240 if (getCycleConnections() != -1 && pc.getNumberOfCalls() >= getCycleConnections()) { 244 log("Cycled connection " +pc +" after numberOfCalls(" +pc.getNumberOfCalls() +")", false); 245 dump(pc); 246 removeFromActiveConnections(pc); 247 248 pc = new PoolConnection(this).getConnection(driverClass, driverURL, user, password); 249 } 250 251 255 265 if (availableConnections.size() + activeConnections.size() > base +overflow) { 266 dump(pc, true); 268 return; 269 270 } 271 272 if (allowedOverflow > overflow) allowedOverflow--; 274 275 if (availableConnections.size() >= base && !waitingThreads) { 276 dumped = true; 278 dump(pc, true); 279 allowedOverflow++; 280 } else { 282 dumped = false; 283 availableConnections.insertElementAt(pc, 0); 285 286 } 287 } else { 289 if (availableConnections.size() < base) { 290 log("Replacing duff connecion (" +pc +") with new one ..", true); 291 fill(1); 292 } 293 } 294 295 296 if (!dumped) { 297 setConnectionDefaults(pc); 299 log("Put connection into pool " +pc, true); 300 } else { 301 log("Dumped connection " +pc +" " +waitingThreads, true); 302 } 303 } 304 } 305 306 307 312 public void setConnectionDefaults(PoolConnection pc) { 313 try { 315 if (pc.getAutoCommit() != connectionAutoCommit) { 316 if (pc.getNumberOfCalls() > 1) { 319 log("WARNING : Checking autocommit value : Looks like someone has changed it from the default, and has not set it back. Default should be '" +connectionAutoCommit +"', but the connection value is '" +pc.getAutoCommit() +"'", false); 320 } 321 pc.setAutoCommit(connectionAutoCommit); 322 323 } 324 } catch (SQLException sqle) { 325 sqle.printStackTrace(System.err); 326 } 327 328 329 try { 330 if (connectionTransactionIsolation == -1) { 333 setConnectionTransactionIsolation(null); 334 } 335 if (pc.getTransactionIsolation() != connectionTransactionIsolation) { 338 if (pc.getNumberOfCalls() > 1) { 341 log("WARNING : Checking transaction isolation level : Looks like someone has changed it from the default, and has not set it back. Default should be '" +getConnectionTransactionIsolation() +"', but the connection value is '" +getConnectionTransactionIsolation(pc.getTransactionIsolation()) +"'", false); 342 } 343 pc.setTransactionIsolation(connectionTransactionIsolation); 344 } 345 } catch (SQLException sqle) { 346 sqle.printStackTrace(System.err); 347 } 348 } 349 350 public void killActiveConnection(PoolConnection pc) { 351 353 synchronized(this) { 356 removeFromActiveConnections(pc); 357 killedConnections.addElement(pc); 358 359 } 360 361 dump(pc, false); 363 364 killedConnections.removeElement(pc); 366 367 pc = new PoolConnection(this).getConnection(driverClass, driverURL, user, password); 369 put(pc); 370 372 } 373 374 public void dumpIdleConnection(PoolConnection pc) { 375 availableConnections.removeElement(pc); 376 log(pc +" Dumping IDLE connection, idle for " +(pc.getIdleTime() /1000) +" seconds", false); 377 try { 378 synchronized (pc) { 379 pc.getRealConnection().close(); 380 } 381 } catch (SQLException sqle) { 382 sqle.printStackTrace(System.err); 383 } 384 pc = null; 385 if (availableConnections.size() >= base) allowedOverflow++; 386 } 387 388 public void removeFromActiveConnections(PoolConnection pc) { 389 boolean found = false; 390 for (int i = 0; i < activeConnectionsData.size(); i++) { 391 if (new StringTokenizer ((String )activeConnectionsData.get(i), "|").nextToken().equals("" +pc)) { 392 activeConnectionsData.removeElement(activeConnectionsData.get(i)); 393 activeConnections.removeElement(pc); 394 found = true; 395 } 396 } 397 if (!found) log("[Pool::removeFromActiveConnections] Could not find " +pc +" to remove from active list !", false); 398 } 399 400 403 public void dump(PoolConnection pc) { 404 dump(pc, true); 405 } 406 407 408 public void dump(PoolConnection pc, boolean nullify) { 409 if (pc == null) return; 410 411 if (!pc.isClosed()) { 412 try { 413 synchronized(pc) { 414 if (runPooledMode) { 415 pc.close(false); 416 } 417 418 java.sql.Connection c = pc.getRealConnection(); 419 if (c != null) { 420 c.close(); 421 } 422 } 423 } catch (SQLException sqle) { 424 sqle.printStackTrace(System.err); 425 } 426 if (nullify) pc = null; 427 } 428 } 429 430 public void log(String message, boolean printSize) { 431 if (log == null) return; 433 434 if (messageLogging) { 435 log.println("[Pool-" +name +"@" +driverURL+"] " +message +" " +new java.util.Date ()); 439 log.flush(); 440 } 441 442 if (sizeLogging) { 443 if (printSize) { 444 log.println("[Pool-" +name +"] [available(" +availableConnections.size() +"), active(" +activeConnections.size() +"), overflow("+ allowedOverflow+")]"); 447 450 } 451 log.flush(); 452 } 453 454 455 } 456 457 458 461 462 public boolean getRunPooledMode() { 463 return runPooledMode; 464 } 465 466 470 public boolean getSizeLogging() { 471 return this.sizeLogging; 472 } 473 474 478 public boolean getMessageLogging() { 479 return this.messageLogging; 480 } 481 482 486 public boolean getWaitingThreads() { 487 return waitingThreads; 488 } 489 490 494 public PrintWriter getLog() { 495 return log; 496 } 497 498 502 public boolean isAvailable() { 503 return available; 504 } 505 506 510 public Vector getActiveConnections() { 511 return activeConnections; 512 } 513 514 518 public String [] getActiveConnectionsData() { 519 synchronized(synchack) { 520 523 String [] s = new String [activeConnections.size()]; 524 for (int i = 0; i < activeConnections.size(); i++) { 525 PoolConnection pc = (PoolConnection)activeConnections.get(i); 526 StringTokenizer st1 = new StringTokenizer ("" +pc, "@"); 529 st1.nextToken(); 530 s[i] = ("ID(" +st1.nextToken() +"), SQL(" +pc.getSql() +"), TIME(" +(pc.getTimeInUse() / 1000.0)+" secs), CALLER(" +pc.getCaller() +"), NUMBER_OF_CALLS(" + pc.getNumberOfCalls()+")"); 532 533 534 } 535 536 return s; 537 } 538 } 539 540 544 public String [] getAvailableConnections() { 545 synchronized(synchack) { 546 String [] s = new String [availableConnections.size()]; 548 for (int i = 0; i < availableConnections.size(); i++) { 549 PoolConnection pc = (PoolConnection)availableConnections.get(i); 550 StringTokenizer st1 = new StringTokenizer ("" +pc, "@"); 551 st1.nextToken(); 552 s[i] = ("ID(" +st1.nextToken() +"), IDLE_FOR(" +(pc.getIdleTime() /1000) +" seconds), NUMBER_OF_CALLS(" + pc.getNumberOfCalls()+")"); 553 } 554 return s; 555 } 556 } 557 558 562 public int getBase() { 563 return base; 564 } 565 566 570 public String getName() { 571 return name; 572 } 573 574 578 public int getOverflow() { 579 return overflow; 580 } 581 582 586 public String getPassword() { 587 return password; 588 } 589 590 594 public String getDriverClass() { 595 return driverClass; 596 } 597 598 602 public String getDriverURL() { 603 return driverURL; 604 } 605 606 610 public String getUser() { 611 return this.user; 612 } 613 614 619 public int getCycleConnections() { 620 return this.cycleConnections; 621 } 622 623 626 public boolean getConnectionAutoCommit() { 627 return this.connectionAutoCommit; 628 } 629 630 public String getCheckSQL() { 631 return this.checkSQL; 632 } 633 634 public void setCheckSQL(String checkSQL) { 635 this.checkSQL = checkSQL; 636 } 637 638 public void setRunPooledMode(boolean runPooledMode) { 639 646 this.runPooledMode = runPooledMode; 647 } 648 649 654 public void setCycleConnections(int cycleConnections) { 655 this.cycleConnections = cycleConnections; 656 } 657 658 659 662 public void setMessageLogging(boolean messageLogging) { 663 this.messageLogging = messageLogging; 664 } 665 666 669 public void setSizeLogging(boolean sizeLogging) { 670 this.sizeLogging = sizeLogging; 671 } 672 673 677 public void setLog(PrintWriter log) { 678 this.log = log; 679 } 680 681 685 public void setWaitingThreads(boolean waitingThreads) { 686 this.waitingThreads = waitingThreads; 687 } 688 689 693 public void setAvailable(boolean available) { 694 this.available = available; 695 } 696 697 701 public void setActiveConnections(Vector activeConnectionsData) { 702 this.activeConnectionsData = activeConnectionsData; 703 } 704 705 709 public void setAvailableConnections(Vector availableConnections) { 710 this.availableConnections = availableConnections; 711 } 712 713 717 public void setBase(int base) { 718 this.base = base; 719 } 720 721 722 726 public void setName(String name) { 727 this.name = name; 728 } 729 730 734 public void setOverflow(int overflow) { 735 this.overflow = overflow; 736 this.allowedOverflow = overflow; 737 } 738 739 743 public void setPassword(String password) { 744 this.password = password; 745 } 746 747 751 public void setDriverURL(String driverURL) { 752 this.driverURL = driverURL; 753 } 754 755 759 public void setDriverClass(String driverClass) { 760 this.driverClass = driverClass; 761 } 762 763 767 public void setUser(String user) { 768 this.user = user; 769 } 770 771 776 public void setConnectionAutoCommit(boolean connectionAutoCommit) { 777 this.connectionAutoCommit = connectionAutoCommit; 778 } 779 780 781 785 public void setConnectionTransactionIsolation(String sConnectionTransactionIsolation) { 786 if (sConnectionTransactionIsolation == null) { 788 try { 789 Connection c = new NewConnection().get(driverClass, driverURL, user, password); 790 if (c == null) { 796 log("WARNING : DB is down/not reachable, and because the pool config variable 'connectionTransactionLevel' is not set, it will be set when the db comes back up and the next call for a connection is made.", false); 797 connectionTransactionIsolation = -1; 798 return; 799 } 800 connectionTransactionIsolation = c.getTransactionIsolation(); 801 c.close(); 802 } catch (SQLException sqle) { 803 804 sqle.printStackTrace(System.err); 805 } 806 } else if (sConnectionTransactionIsolation.equalsIgnoreCase("TRANSACTION_NONE")) { 807 connectionTransactionIsolation = Connection.TRANSACTION_NONE; 808 } else if (sConnectionTransactionIsolation.equalsIgnoreCase("TRANSACTION_READ_COMMITTED")) { 809 connectionTransactionIsolation = Connection.TRANSACTION_READ_COMMITTED; 810 } else if (sConnectionTransactionIsolation.equalsIgnoreCase("TRANSACTION_READ_UNCOMMITTED")) { 811 connectionTransactionIsolation = Connection.TRANSACTION_READ_UNCOMMITTED; 812 } else if (sConnectionTransactionIsolation.equalsIgnoreCase("TRANSACTION_REPEATABLE_READ")) { 813 connectionTransactionIsolation = Connection.TRANSACTION_REPEATABLE_READ; 814 } else if (sConnectionTransactionIsolation.equalsIgnoreCase("TRANSACTION_SERIALIZABLE")) { 815 connectionTransactionIsolation = Connection.TRANSACTION_SERIALIZABLE; 816 } else { 818 log("WARNING : setConnectionTransactionIsolation : Do not recognize transaction level of '" +sConnectionTransactionIsolation +"', using driver default", false); 819 try { 820 Connection c = new NewConnection().get(driverClass, driverURL, user, password); 821 connectionTransactionIsolation = c.getTransactionIsolation(); 822 c.close(); 823 } catch (SQLException sqle) { 824 825 sqle.printStackTrace(System.err); 826 } 827 } 828 829 log("INFO : setConnectionTransactionIsolation : Set connection transaction level to '" +getConnectionTransactionIsolation() +"'", false); 830 831 } 832 833 836 public String getConnectionTransactionIsolation() { 837 return getConnectionTransactionIsolation(connectionTransactionIsolation); 838 } 839 840 private String getConnectionTransactionIsolation(int level) { 841 String sLevel = "DRIVER_DEFAULT"; 842 843 switch (level) { 844 case Connection.TRANSACTION_NONE : 845 sLevel = "TRANSACTION_NONE"; 846 break; 847 case Connection.TRANSACTION_READ_COMMITTED : 848 sLevel = "TRANSACTION_READ_COMMITTED"; 849 break; 850 case Connection.TRANSACTION_READ_UNCOMMITTED : 851 sLevel = "TRANSACTION_READ_UNCOMMITTED"; 852 break; 853 case Connection.TRANSACTION_REPEATABLE_READ : 854 sLevel = "TRANSACTION_REPEATABLE_READ"; 855 break; 856 case Connection.TRANSACTION_SERIALIZABLE : 857 sLevel = "TRANSACTION_SERIALIZABLE"; 858 break; 859 } 860 861 return sLevel; 862 } 863 864 865 866 871 public int checkIdleConnections() { 872 synchronized(synchack) { 873 PoolConnection[] pca = new PoolConnection[availableConnections.size()]; 875 for (int i = 0; i < availableConnections.size(); i++) { 876 pca[i] = (PoolConnection)availableConnections.elementAt(i); 877 } 878 879 for (int i = 0; i < pca.length; i++) { 880 PoolConnection pc = pca[i]; 881 if (pc.getIdleTime() > this.getIdleTime()) { 882 dumpIdleConnection(pc); 883 } 884 } 885 pca = null; 886 return 0; 887 } 888 } 889 890 893 public int getIdleTime() { 894 return this.idleTime; 895 } 896 897 900 public void setIdleTime(int idleTime) { 901 this.idleTime = idleTime; 902 } 903 904 } | Popular Tags |