1 53 54 106 107 package com.Yasna.forum.database; 108 109 import java.sql.*; 110 import java.util.*; 111 import java.io.*; 112 import java.text.*; 113 import java.util.Date ; 114 import com.Yasna.forum.*; 115 116 121 public class DbConnectionDefaultPool extends DbConnectionProvider { 122 123 private static final String NAME = "Default Connection Pool"; 124 private static final String DESCRIPTION = "The default connection provider " 125 + "that uses the connection pool from javaexchange.com. It works with " 126 + "almost any database setup, is customizable, and offers good performance. " 127 + "Use this connection provider unless you have your own or can use a " 128 + "container managed connection pool."; 129 private static final String AUTHOR = "Yazd.Yasna.com"; 130 private static final int MAJOR_VERSION = 1; 131 private static final int MINOR_VERSION = 0; 132 private static final boolean POOLED = true; 133 134 private ConnectionPool connectionPool = null; 135 private Properties props; 136 private Properties propDescriptions; 137 138 private Object initLock = new Object (); 139 140 public DbConnectionDefaultPool() { 141 props = new Properties(); 143 propDescriptions = new Properties(); 144 initializeProperties(); 146 loadProperties(); 148 } 149 150 153 public Connection getConnection() { 154 if (connectionPool == null) { 155 synchronized(initLock) { 157 if (connectionPool == null) { 159 System.err.println("Warning: DbConnectionDefaultPool.getConnection() was " + 160 "called when the internal pool has not been initialized."); 161 return null; 162 } 163 } 164 } 165 return new ConnectionWrapper(connectionPool.getConnection(), connectionPool); 166 } 167 168 171 protected void start() { 172 synchronized (initLock) { 174 String driver = props.getProperty("driver"); 176 String server = props.getProperty("server"); 177 String username = props.getProperty("username"); 178 String password = props.getProperty("password"); 179 int minConnections = 0, maxConnections = 0; 180 double connectionTimeout = 0.0; 181 try { 182 minConnections = Integer.parseInt(props.getProperty("minConnections")); 183 maxConnections = Integer.parseInt(props.getProperty("maxConnections")); 184 connectionTimeout = Double.parseDouble(props.getProperty("connectionTimeout")); 185 } 186 catch (Exception e) { 187 System.err.println("Error: could not parse default pool properties. " + 188 "Make sure the values exist and are correct."); 189 e.printStackTrace(); 190 return; 191 } 192 String logPath = props.getProperty("logPath"); 193 194 try { 195 connectionPool = new ConnectionPool(driver, server, username, password, 196 minConnections, maxConnections, logPath, connectionTimeout); 197 } 198 catch (IOException ioe) { 199 System.err.println("Error starting DbConnectionDefaultPool: " + ioe); 200 ioe.printStackTrace(); 201 } 202 } 203 } 204 205 208 protected void restart() { 209 destroy(); 211 loadProperties(); 213 start(); 215 } 216 217 220 protected void destroy() { 221 if (connectionPool != null) { 222 try { 223 connectionPool.destroy(1); 224 } 225 catch (Exception e) { 226 e.printStackTrace(); 227 } 228 } 229 connectionPool = null; 231 } 232 233 239 public String getProperty(String name) { 240 return (String )props.get(name); 241 } 242 243 249 public String getPropertyDescription(String name) { 250 return (String )propDescriptions.get(name); 251 } 252 253 256 public Enumeration propertyNames() { 257 return props.propertyNames(); 258 } 259 260 269 public void setProperty(String name, String value) { 270 props.put(name, value); 271 saveProperties(); 272 } 273 274 277 private void initializeProperties() { 278 props.put("driver",""); 279 props.put("server",""); 280 props.put("username",""); 281 props.put("password",""); 282 props.put("minConnections",""); 283 props.put("maxConnections",""); 284 props.put("logPath",""); 285 props.put("connectionTimeout",""); 286 287 propDescriptions.put("driver","JDBC driver. e.g. 'oracle.jdbc.driver.OracleDriver'"); 288 propDescriptions.put("server","JDBC connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'"); 289 propDescriptions.put("username","Database username. e.g. 'Scott'"); 290 propDescriptions.put("password","Database password. e.g. 'Tiger'"); 291 propDescriptions.put("minConnections","Minimum # of connections to start with in pool. Three is the recommended minimum"); 292 propDescriptions.put("maxConnections","Maximum # of connections in dynamic pool. Fifteen should give good performance for an average load."); 293 propDescriptions.put("logPath","Absolute path name for log file. e.g. 'c:\\logs\\yazdDbLog.log'"); 294 propDescriptions.put("connectionTimeout","Time in days between connection resets. e.g. '.5'"); 295 } 296 297 300 private void loadProperties() { 301 String driver = PropertyManager.getProperty("DbConnectionDefaultPool.driver"); 302 String server = PropertyManager.getProperty("DbConnectionDefaultPool.server"); 303 String username = PropertyManager.getProperty("DbConnectionDefaultPool.username"); 304 String password = PropertyManager.getProperty("DbConnectionDefaultPool.password"); 305 String minConnections = PropertyManager.getProperty("DbConnectionDefaultPool.minConnections"); 306 String maxConnections = PropertyManager.getProperty("DbConnectionDefaultPool.maxConnections"); 307 String logPath = PropertyManager.getProperty("DbConnectionDefaultPool.logPath"); 308 String connectionTimeout = PropertyManager.getProperty("DbConnectionDefaultPool.connectionTimeout"); 309 310 if (driver != null) { props.setProperty("driver", driver); } 311 if (server != null) { props.setProperty("server", server); } 312 if (username != null) { props.setProperty("username", username); } 313 if (password != null) { props.setProperty("password", password); } 314 if (minConnections != null) { props.setProperty("minConnections", minConnections); } 315 if (maxConnections != null) { props.setProperty("maxConnections", maxConnections); } 316 if (logPath != null) { props.setProperty("logPath", logPath); } 317 if (connectionTimeout != null) { props.setProperty("connectionTimeout", connectionTimeout); } 318 } 319 320 private void saveProperties() { 321 PropertyManager.setProperty("DbConnectionDefaultPool.driver", props.getProperty("driver")); 322 PropertyManager.setProperty("DbConnectionDefaultPool.server", props.getProperty("server")); 323 PropertyManager.setProperty("DbConnectionDefaultPool.username", props.getProperty("username")); 324 PropertyManager.setProperty("DbConnectionDefaultPool.password", props.getProperty("password")); 325 PropertyManager.setProperty("DbConnectionDefaultPool.minConnections", props.getProperty("minConnections")); 326 PropertyManager.setProperty("DbConnectionDefaultPool.maxConnections", props.getProperty("maxConnections")); 327 PropertyManager.setProperty("DbConnectionDefaultPool.logPath", props.getProperty("logPath")); 328 PropertyManager.setProperty("DbConnectionDefaultPool.connectionTimeout", props.getProperty("connectionTimeout")); 329 } 330 331 353 private class ConnectionPool implements Runnable { 354 private Thread runner; 355 356 private Connection[] connPool; 357 private int[] connStatus; 358 359 private long[] connLockTime, connCreateDate; 360 private String [] connID; 361 private String dbDriver, dbServer, dbLogin, dbPassword, logFileString; 362 private int currConnections, connLast, minConns, maxConns, maxConnMSec; 363 364 private boolean available=true; 366 367 private PrintWriter log; 368 private SQLWarning currSQLWarning; 369 private String pid; 370 371 382 public ConnectionPool (String dbDriver, String dbServer, String dbLogin, 383 String dbPassword, int minConns, int maxConns, 384 String logFileString, double maxConnTime) throws IOException 385 { 386 connPool = new Connection[maxConns]; 387 connStatus = new int[maxConns]; 388 connLockTime = new long[maxConns]; 389 connCreateDate = new long[maxConns]; 390 connID = new String [maxConns]; 391 currConnections = minConns; 392 this.maxConns = maxConns; 393 this.dbDriver = dbDriver; 394 this.dbServer = dbServer; 395 this.dbLogin = dbLogin; 396 this.dbPassword = dbPassword; 397 this.logFileString = logFileString; 398 maxConnMSec = (int)(maxConnTime * 86400000.0); if(maxConnMSec < 30000) { maxConnMSec = 30000; 401 } 402 403 try { 404 log = new PrintWriter(new FileOutputStream(logFileString),true); 405 } 407 catch (IOException e1) { 408 System.err.println("Warning: DbConnectionDefaultPool could not open \"" 409 + logFileString + "\" to write log to. Make sure that your Java " + 410 "process has permission to write to the file and that the directory exists." 411 ); 412 try { 413 log = new PrintWriter(new FileOutputStream("DCB_" + 414 System.currentTimeMillis() + ".log"), true 415 ); 416 } 417 catch (IOException e2) { 418 throw new IOException("Can't open any log file"); 419 } 420 } 421 422 SimpleDateFormat formatter 424 = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz"); 425 java.util.Date nowc = new java.util.Date (); 426 pid = formatter.format(nowc); 427 428 BufferedWriter pidout = new BufferedWriter(new 429 FileWriter(logFileString + "pid")); 430 pidout.write(pid); 431 pidout.close(); 432 433 log.println("Starting ConnectionPool:"); 434 log.println("dbDriver = " + dbDriver); 435 log.println("dbServer = " + dbServer); 436 log.println("dbLogin = " + dbLogin); 437 log.println("log file = " + logFileString); 438 log.println("minconnections = " + minConns); 439 log.println("maxconnections = " + maxConns); 440 log.println("Total refresh interval = " + maxConnTime + " days"); 441 log.println("-----------------------------------------"); 442 443 444 boolean connectionsSucceeded=false; 450 int dbLoop=20; 451 452 try { 453 for(int i=1; i < dbLoop; i++) { 454 try { 455 for(int j=0; j < currConnections; j++) { 456 createConn(j); 457 } 458 connectionsSucceeded=true; 459 break; 460 } 461 catch (SQLException e){ 462 log.println("--->Attempt (" + String.valueOf(i) + 463 " of " + String.valueOf(dbLoop) + 464 ") failed to create new connections set at startup: "); 465 log.println(" " + e); 466 log.println(" Will try again in 15 seconds..."); 467 try { Thread.sleep(15000); } 468 catch(InterruptedException e1) {} 469 } 470 } 471 if(!connectionsSucceeded) { log.println("\r\nAll attempts at connecting to Database exhausted"); 473 throw new IOException(); 474 } 475 } 476 catch (Exception e) { 477 e.printStackTrace(); 478 throw new IOException(); 479 } 480 481 483 runner = new Thread (this); 484 runner.start(); 485 486 } 488 489 498 public void run() { 499 boolean forever = true; 500 Statement stmt=null; 501 String currCatalog=null; 502 503 while(forever) { 504 try { 507 BufferedReader in = new BufferedReader(new FileReader(logFileString + "pid")); 508 String curr_pid = in.readLine(); 509 if(curr_pid.equals(pid)) { 510 } 512 else { 513 log.close(); 515 516 for(int i=0; i < currConnections; i++) { 518 try { 519 connPool[i].close(); 520 } 521 catch (SQLException e1) {} } 523 return; 525 } 526 in.close(); 527 } 528 catch (IOException e1) { 529 log.println("Can't read the file for pid info: " + 530 logFileString + "pid"); 531 } 532 533 for(int i=0; i < currConnections; i++) { 535 try { 536 currSQLWarning = connPool[i].getWarnings(); 537 if(currSQLWarning != null) { 538 log.println("Warnings on connection " + 539 String.valueOf(i) + " " + currSQLWarning); 540 connPool[i].clearWarnings(); 541 } 542 } 543 catch(SQLException e) { 544 log.println("Cannot access Warnings: " + e); 545 } 546 } 547 548 for(int i=0; i < currConnections; i++) { long age = System.currentTimeMillis() - connCreateDate[i]; 550 551 synchronized(connStatus) { 552 if(connStatus[i] > 0) { continue; 554 } 555 connStatus[i] = 2; } 557 558 try { if(age > maxConnMSec) { throw new SQLException(); 561 } 562 563 stmt = connPool[i].createStatement(); 564 connStatus[i] = 0; 568 if(connPool[i].isClosed()) { 570 throw new SQLException(); 571 } 572 } 574 catch(SQLException e) { 575 try { 576 log.println(new Date ().toString() + 577 " ***** Recycling connection " + 578 String.valueOf(i) + ":" 579 ); 580 581 connPool[i].close(); 582 createConn(i); 583 } 584 catch(SQLException e1) { 585 log.println("Failed: " + e1); 586 connStatus[i] = 0; } 588 } 589 finally { 590 try { 591 if(stmt != null) { 592 stmt.close(); 593 } 594 } 595 catch(SQLException e1){}; 596 } 597 } 598 599 try { 600 Thread.sleep(20000); 601 } catch(InterruptedException e) { 603 return; 608 } 609 } 610 } 612 625 public Connection getConnection() { 626 627 Connection conn=null; 628 629 if(available){ 630 boolean gotOne = false; 631 632 for(int outerloop=1; outerloop<=10; outerloop++) { 633 634 try { 635 int loop=0; 636 int roundRobin = connLast + 1; 637 if(roundRobin >= currConnections) roundRobin=0; 638 639 do { 640 synchronized(connStatus) { 641 if((connStatus[roundRobin] < 1) && 642 (! connPool[roundRobin].isClosed())) 643 { 644 conn = connPool[roundRobin]; 645 connStatus[roundRobin]=1; 646 connLockTime[roundRobin] = 647 System.currentTimeMillis(); 648 connLast = roundRobin; 649 gotOne = true; 650 break; 651 } 652 else { 653 loop++; 654 roundRobin++; 655 if(roundRobin >= currConnections) roundRobin=0; 656 } 657 } 658 } 659 while((gotOne==false)&&(loop < currConnections)); 660 } 661 catch (SQLException e1) {} 662 663 if(gotOne) { 664 break; 665 } 666 else { 667 synchronized(this) { if(currConnections < maxConns) { 669 try { 670 createConn(currConnections); 671 currConnections++; 672 } 673 catch(SQLException e) { 674 log.println("Unable to create new connection: " + e); 675 } 676 } 677 } 678 679 try { Thread.sleep(2000); } 680 catch(InterruptedException e) {} 681 log.println("-----> Connections Exhausted! Will wait and try " + 682 "again in loop " + 683 String.valueOf(outerloop)); 684 } 685 } 687 } 688 else { 689 log.println("Unsuccessful getConnection() request during destroy()"); 690 } 692 return conn; 693 } 694 695 698 public int idOfConnection(Connection conn) { 699 int match; 700 String tag; 701 702 try { 703 tag = conn.toString(); 704 } 705 catch (NullPointerException e1) { 706 tag = "none"; 707 } 708 709 match=-1; 710 711 for(int i=0; i< currConnections; i++) { 712 if(connID[i].equals(tag)) { 713 match = i; 714 break; 715 } 716 } 717 return match; 718 } 719 720 724 public String freeConnection(Connection conn) { 725 String res=""; 726 727 int thisconn = idOfConnection(conn); 728 if(thisconn >= 0) { 729 connStatus[thisconn]=0; 730 res = "freed " + conn.toString(); 731 } 734 else { 735 log.println("----> Could not free connection!!!"); 736 } 737 738 return res; 739 } 740 741 745 public long getAge(Connection conn) { int thisconn = idOfConnection(conn); 747 return System.currentTimeMillis() - connLockTime[thisconn]; 748 } 749 750 private void createConn(int i) throws SQLException { 751 Date now = new Date (); 752 try { 753 Class.forName (dbDriver); 754 connPool[i] = DriverManager.getConnection 755 (dbServer,dbLogin,dbPassword); 756 connStatus[i]=0; 757 connID[i]=connPool[i].toString(); 758 connLockTime[i]=0; 759 connCreateDate[i] = now.getTime(); 760 761 log.println(now.toString() + " Opening connection " + String.valueOf(i) + 762 " " + connPool[i].toString() + ":"); 763 } 764 catch (ClassNotFoundException e2) { 765 e2.printStackTrace(); 766 throw new SQLException(e2.getMessage()); 767 } 768 } 769 770 774 775 795 public void destroy(int millis) throws SQLException { 796 797 800 available=false; 802 803 runner.interrupt(); 805 806 try { runner.join(millis); } 808 catch(InterruptedException e){} 810 815 long startTime=System.currentTimeMillis(); 816 817 int useCount; 820 while((useCount=getUseCount())>0 && System.currentTimeMillis() - startTime <= millis) { 821 try { Thread.sleep(500); } 822 catch(InterruptedException e) {} } 824 825 for(int i=0; i < currConnections; i++) { 827 try { 828 connPool[i].close(); 829 } 830 catch (SQLException e1) 831 { 832 log.println("Cannot close connections on Destroy"); 833 } 834 } 835 836 if(useCount > 0) { 837 String msg="Unsafe shutdown: Had to close "+useCount+ 839 " active DB connections after "+millis+"ms"; 840 log.println(msg); 841 log.close(); 843 throw new SQLException(msg); 846 } 847 848 log.close(); 850 851 } 853 854 862 public void destroy() { 863 try { 864 destroy(10000); 865 } 866 catch(SQLException e) {} 867 } 868 869 872 public int getUseCount() { 879 int useCount=0; 880 synchronized(connStatus) { 881 for(int i=0; i < currConnections; i++) { 882 if(connStatus[i] > 0) { useCount++; 884 } 885 } 886 } 887 return useCount; 888 } 890 893 public int getSize() { 894 return currConnections; 895 } 897 } 899 904 public class ConnectionWrapper implements Connection { 905 906 private Connection connection; 907 private ConnectionPool connectionPool; 908 909 public ConnectionWrapper(Connection connection, ConnectionPool connectionPool) { 910 this.connection = connection; 911 this.connectionPool = connectionPool; 912 } 913 914 918 public void close() throws SQLException { 919 connectionPool.freeConnection(this.connection); 920 connection = null; 923 connectionPool = null; 924 } 925 926 public String toString() { 927 if (connection != null) { 928 return connection.toString(); 929 } 930 else { 931 return "CoolServlets connection wrapper"; 932 } 933 } 934 935 public Statement createStatement() throws SQLException { 936 return connection.createStatement(); 937 } 938 939 public void setHoldability(int holdability) throws SQLException { 940 connection.setHoldability(holdability); 941 } 942 943 public int getHoldability() throws SQLException { 944 return connection.getHoldability(); 945 } 946 947 public Savepoint setSavepoint() throws SQLException { 948 return connection.setSavepoint(); 949 } 950 951 public Savepoint setSavepoint(String name) throws SQLException { 952 return connection.setSavepoint(name); 953 } 954 955 public void rollback(Savepoint savepoint) throws SQLException { 956 connection.rollback(savepoint); 957 } 958 959 960 public PreparedStatement prepareStatement(String sql) throws SQLException { 961 return connection.prepareStatement(sql); 962 } 963 964 public CallableStatement prepareCall(String sql) throws SQLException { 965 return connection.prepareCall(sql); 966 } 967 968 public String nativeSQL(String sql) throws SQLException { 969 return connection.nativeSQL(sql); 970 } 971 972 public void setAutoCommit(boolean autoCommit) throws SQLException { 973 connection.setAutoCommit(autoCommit); 974 } 975 976 public boolean getAutoCommit() throws SQLException { 977 return connection.getAutoCommit(); 978 } 979 980 public void commit() throws SQLException { 981 connection.commit(); 982 } 983 984 public void rollback() throws SQLException { 985 connection.rollback(); 986 } 987 988 public boolean isClosed() throws SQLException { 989 return connection.isClosed(); 990 } 991 992 public DatabaseMetaData getMetaData() throws SQLException { 993 return connection.getMetaData(); 994 } 995 996 public void setReadOnly(boolean readOnly) throws SQLException { 997 connection.setReadOnly(readOnly); 998 } 999 1000 public boolean isReadOnly() throws SQLException { 1001 return connection.isReadOnly(); 1002 } 1003 1004 public void setCatalog(String catalog) throws SQLException { 1005 connection.setCatalog(catalog); 1006 } 1007 1008 public String getCatalog() throws SQLException { 1009 return connection.getCatalog(); 1010 } 1011 1012 public void setTransactionIsolation(int level) throws SQLException { 1013 connection.setTransactionIsolation(level); 1014 } 1015 1016 public int getTransactionIsolation() throws SQLException { 1017 return connection.getTransactionIsolation(); 1018 } 1019 1020 public SQLWarning getWarnings() throws SQLException { 1021 return connection.getWarnings(); 1022 } 1023 1024 public void clearWarnings() throws SQLException { 1025 connection.clearWarnings(); 1026 } 1027 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 1028 connection.releaseSavepoint(savepoint); 1029 } 1030 public Statement createStatement(int resultSetType, int resultSetConcurrency) 1031 throws SQLException 1032 { 1033 return connection.createStatement(resultSetType, resultSetConcurrency); 1034 } 1035 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) 1036 throws SQLException 1037 { 1038 return connection.createStatement(resultSetType, resultSetConcurrency,resultSetHoldability); 1039 } 1040 1041 1042 public PreparedStatement prepareStatement(String sql, int resultSetType, 1043 int resultSetConcurrency) throws SQLException 1044 { 1045 return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); 1046 } 1047 1048 public CallableStatement prepareCall(String sql, int resultSetType, 1049 int resultSetConcurrency) throws SQLException 1050 { 1051 return connection.prepareCall(sql, resultSetType, resultSetConcurrency); 1052 } 1053 1054 public Map getTypeMap() throws SQLException { 1055 return connection.getTypeMap(); 1056 } 1057 1058 public PreparedStatement prepareStatement(String sql, String [] columnNames) throws SQLException { 1059 return connection.prepareStatement(sql,columnNames); 1060 } 1061 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { 1062 return connection.prepareStatement(sql,columnIndexes); 1063 } 1064 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { 1065 return connection.prepareStatement(sql,autoGeneratedKeys); 1066 } 1067 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { 1068 return connection.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability); 1069 } 1070 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { 1071 return connection.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability); 1072 } 1073 1074 1075 public void setTypeMap(Map map) throws SQLException { 1076 connection.setTypeMap(map); 1077 } 1078 1079 } 1080} 1081 | Popular Tags |