1 package com.protomatter.jdbc.pool; 2 3 52 53 import com.protomatter.util.*; 54 import com.protomatter.pool.*; 55 import com.protomatter.syslog.*; 56 import java.util.*; 57 import java.text.*; 58 import java.sql.*; 59 import java.io.*; 60 61 183 public class JdbcConnectionPool 184 extends GrowingObjectPool 185 implements SyslogChannelAware 186 { 187 private String url = null; 188 private String driverName = null; 189 private Properties props = null; 190 private String poolName = null; 191 private String checkStatement = null; 192 private boolean initialized = false; 193 private boolean validateOnCheckout = false; 194 private boolean verboseValidate = false; 195 196 private int maxCheckoutRefreshAttempts = 5; 197 private int checkoutRefreshWaitTime = 500; 198 199 private RefreshThread refreshThread = null; 200 private MaidThread maidThread = null; 201 private int maxConnectionIdleTime = 0; 202 private Driver driver = null; 203 204 private Object syslogChannel = null; 205 206 private boolean useSyslog = true; 207 208 protected static Debug DEBUG = Debug.forPackage(JdbcConnectionPool.class); 209 protected static Channel log = Channel.forPackage(JdbcConnectionPool.class); 210 211 int getMaxCheckoutRefreshAttempts() 212 { 213 return this.maxCheckoutRefreshAttempts; 214 } 215 int getCheckoutRefreshWaitTime() 216 { 217 return this.checkoutRefreshWaitTime; 218 } 219 220 229 public JdbcConnectionPool(String name, Map args) 230 throws Exception 231 { 232 this(name); 233 init(args); 234 } 235 236 295 public JdbcConnectionPool(String name, Properties props) 296 throws Exception 297 { 298 this(name); 299 300 304 String prefix = "com.protomatter.jdbc.pool."; 305 int prefixLen = prefix.length(); 306 String suffix = ".jdbcProperties"; 307 308 Enumeration e = props.keys(); 309 while (e.hasMoreElements()) 310 { 311 String key = (String )e.nextElement(); 312 if (key.startsWith(prefix) && !key.endsWith(suffix)) 313 { 314 String pName = key.substring(prefixLen); 315 if (pName.equals(name)) 316 { 317 String value = props.getProperty(key); 318 Properties poolProps = getProperties(value); 319 Properties jdbcProps = getProperties(props.getProperty(prefix + pName + suffix)); 320 createPoolFromProps(poolProps, jdbcProps); 321 } 322 } 323 } 324 } 325 326 331 public Object getSyslogChannel() 332 { 333 return syslogChannel; 334 } 335 336 341 public void setSyslogChannel(String channelName) 342 { 343 this.syslogChannel = channelName; 344 } 345 346 351 public void setSyslogChannelList(List channelList) 352 { 353 this.syslogChannel = (Object )channelList.toArray(); 354 } 355 356 359 boolean useSyslog() 360 { 361 return this.useSyslog; 362 } 363 364 373 public static List createPools(Properties props) 374 throws Exception 375 { 376 String prefix = "com.protomatter.jdbc.pool."; 377 int prefixLen = prefix.length(); 378 String suffix = ".jdbcProperties"; 379 380 List list = new ArrayList(); 381 Enumeration e = props.keys(); 382 while (e.hasMoreElements()) 383 { 384 String key = (String )e.nextElement(); 385 if (key.startsWith(prefix) && !key.endsWith(suffix)) 386 { 387 String pName = key.substring(prefixLen); 388 list.add(new JdbcConnectionPool(pName, props)); 389 } 390 } 391 return list; 392 } 393 394 private Properties getProperties(String s) 395 { 396 String tok; 397 StringTokenizer st; 398 Properties props = new Properties(); 399 int i; 400 401 if (s == null) 402 return props; 403 404 st = new StringTokenizer(s, ","); 405 406 while (st.hasMoreElements()) { 407 tok= st.nextToken(); 408 409 if (-1 == (i= tok.indexOf('='))) 410 throw new IllegalArgumentException ("Invalid property: " + tok); 411 412 props.put(tok.substring(0,i), tok.substring(i+1)); 413 } 414 415 return props; 416 } 417 418 private void createPoolFromProps(Properties props, Properties jdbcProps) 419 throws Exception 420 { 421 Map ht = new HashMap(); 425 426 if (props.get("pool.useSyslog") != null) 427 { 428 ht.put("pool.useSyslog", Boolean.valueOf(props.getProperty("pool.useSyslog"))); 429 } 430 431 if (props.get("jdbc.driver") != null) 432 { 433 ht.put("jdbc.driver", props.getProperty("jdbc.driver")); 434 } 435 else 436 { 437 throw new PoolException(MessageFormat.format( 438 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_PROP_MESSAGE), 439 new Object [] { "jdbc.driver" })); 440 } 441 442 if (props.get("jdbc.URL") != null) 443 { 444 ht.put("jdbc.URL", props.getProperty("jdbc.URL")); 445 } 446 else 447 { 448 throw new PoolException(MessageFormat.format( 449 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_PROP_MESSAGE), 450 new Object [] { "jdbc.URL" })); 451 } 452 453 if (props.get("pool.maxCheckoutRefreshAttempts") != null) 454 { 455 try 456 { 457 ht.put("pool.maxCheckoutRefreshAttempts", 458 new Integer ( 459 Integer.parseInt( 460 props.getProperty("pool.maxCheckoutRefreshAttempts")))); 461 } 462 catch (NumberFormatException x) 463 { 464 throw new PoolException(MessageFormat.format( 465 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_INT_PROP_MESSAGE), 466 new Object [] { "pool.maxCheckoutRefreshAttempts" })); 467 } 468 } 469 470 if (props.get("pool.checkoutRefreshWaitTime") != null) 471 { 472 try 473 { 474 ht.put("pool.checkoutRefreshWaitTime", 475 new Integer ( 476 Integer.parseInt( 477 props.getProperty("pool.checkoutRefreshWaitTime")))); 478 } 479 catch (NumberFormatException x) 480 { 481 throw new PoolException(MessageFormat.format( 482 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_INT_PROP_MESSAGE), 483 new Object [] { "pool.checkoutRefreshWaitTime" })); 484 } 485 } 486 487 ht.put("jdbc.properties", jdbcProps); 488 489 if (props.get("jdbc.validityCheckStatement") != null) 490 { 491 ht.put("jdbc.validityCheckStatement", 492 props.getProperty("jdbc.validityCheckStatement")); 493 } 494 495 if (props.get("pool.syslogChannelList") != null) 496 { 497 ht.put("pool.syslogChannelList", 498 props.getProperty("pool.syslogChannelList")); 499 } 500 501 String tmp = props.getProperty("pool.verboseValidate"); 502 boolean verboseValidate = false; 503 if (tmp != null && tmp.equalsIgnoreCase("true")) 504 verboseValidate = true; 505 ht.put("pool.verboseValidate", new Boolean (verboseValidate)); 506 507 if (props.get("pool.refreshThreadCheckInterval") != null) 508 { 509 int i = Integer.parseInt(props.getProperty("pool.refreshThreadCheckInterval")); 510 String verboseString = props.getProperty("pool.verboseRefresh"); 511 boolean verboseRefresh = false; 512 if (verboseString != null && verboseString.equalsIgnoreCase("true")) 513 verboseRefresh = true; 514 ht.put("pool.verboseRefresh", new Boolean (verboseRefresh)); 515 if (i > 0) 516 { 517 if (props.get("jdbc.validityCheckStatement") == null) 518 { 519 throw new PoolException(MessageFormat.format( 520 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_IF_PROP_MESSAGE), 521 new Object [] { "jdbc.validityCheckStatement", "pool.refreshThreadCheckInterval" })); 522 } 523 } 524 ht.put("pool.refreshThreadCheckInterval", new Integer (i)); 525 } 526 527 if (props.get("pool.initialSize") != null) 528 { 529 ht.put("pool.initialSize", 530 new Integer (props.getProperty("pool.initialSize"))); 531 } 532 533 if (props.get("pool.maxSize") != null) 534 { 535 ht.put("pool.maxSize", 536 new Integer (props.getProperty("pool.maxSize"))); 537 } 538 539 if (props.get("pool.growBlock") != null) 540 { 541 ht.put("pool.growBlock", 542 new Integer (props.getProperty("pool.growBlock"))); 543 } 544 545 if (props.get("pool.createWaitTime") != null) 546 { 547 ht.put("pool.createWaitTime", 548 new Integer (props.getProperty("pool.createWaitTime"))); 549 } 550 551 if (props.get("pool.maidThreadCheckInterval") != null) 552 { 553 ht.put("pool.maidThreadCheckInterval", 554 new Integer (props.getProperty("pool.maidThreadCheckInterval"))); 555 } 556 557 if (props.get("pool.maxConnectionIdleTime") != null) 558 { 559 ht.put("pool.maxConnectionIdleTime", 560 new Integer (props.getProperty("pool.maxConnectionIdleTime"))); 561 } 562 563 if (props.get("pool.validateOnCheckout") != null) 564 { 565 ht.put("pool.validateOnCheckout", 566 new Boolean (props.getProperty("pool.validateOnCheckout"))); 567 } 568 569 init(ht); 571 } 572 573 574 581 public JdbcConnectionPool(String name) 582 { 583 super(); 584 this.poolName = name; 585 JdbcConnectionPoolDriver.registerPool(this); 586 } 587 588 592 public void unRegisterPool() 593 { 594 JdbcConnectionPoolDriver.unRegisterPool(this); 595 } 596 597 600 public String getName() 601 { 602 return this.poolName; 603 } 604 605 610 public void closeAllConnections() 611 { 612 if (DEBUG.debug()) 613 log.debug(this, "Closing connections in pool " + poolName); 614 List pool = getPool(); 615 synchronized (getSyncObject()) 616 { 617 Iterator i = pool.iterator(); 618 while (i.hasNext()) 619 { 620 ((JdbcConnectionPoolConnection)i.next()).reallyClose(); 621 } 622 } 623 } 624 625 636 public void refreshConnections(boolean verbose) 637 throws SQLException 638 { 639 if (DEBUG.debug()) 640 log.debug(this, "Refreshing connections in pool " + poolName); 641 SQLException x = null; 642 synchronized (getSyncObject()) 643 { 644 List pool = getPool(); 645 List newPool = new ArrayList(); 647 Iterator i = pool.iterator(); 648 while (i.hasNext()) 649 newPool.add(i.next()); 650 651 pool.clear(); 654 i = newPool.iterator(); 655 while (i.hasNext()) 656 { 657 JdbcConnectionPoolConnection c = (JdbcConnectionPoolConnection)i.next(); 658 if (DEBUG.debug()) 659 log.debug(this, "Refreshing connection: " + c); 660 boolean done = false; 661 try 662 { 663 c.refresh(verbose); 664 pool.add(c); 665 done = true; 666 } 667 catch (SQLException sx) 668 { 669 if (DEBUG.debug()) 670 log.debug(this, "Caught SQLException refreshing connection: " + sx.toString()); 671 x = sx; 672 c.deleteObjectPoolObject(); 673 } 674 } 675 getSyncObject().notifyAll(); 676 } 677 if (x != null) 678 { 679 throw x; 680 } 681 } 682 683 688 public void refreshConnections() 689 throws SQLException 690 { 691 refreshConnections(false); 692 } 693 694 793 public void init(Map args) 794 throws Exception 795 { 796 if (this.initialized == true) 798 return; 799 this.initialized = true; 800 801 if (DEBUG.debug()) 802 { 803 log.debug(this, "Initializing new JDBC connection pool:"); 804 Iterator it = args.keySet().iterator(); 805 while (it.hasNext()) 806 { 807 Object key = it.next(); 808 log.debug(this, " " + key + " = " + args.get(key)); 809 } 810 } 811 812 if (args.get("pool.useSyslog") != null) 813 this.useSyslog = ((Boolean )args.get("pool.useSyslog")).booleanValue(); 814 815 int maxSize = -1; 817 if (args.get("pool.maxSize") != null) 818 maxSize = ((Integer )args.get("pool.maxSize")).intValue(); 819 820 this.driverName = (String )args.get("jdbc.driver"); 821 try 822 { 823 DatabaseUtil.registerDriver(driverName); 825 driver = (Driver)Class.forName(driverName).newInstance(); 826 } 827 catch (Exception x) 828 { 829 if (useSyslog) 830 Syslog.log(this, x); 831 throw new SQLException(MessageFormat.format( 832 PoolResources.getResourceString(MessageConstants.CANNOT_LOAD_DRIVER_MESSAGE), 833 new Object [] { driverName, x.toString() })); 834 } 835 this.url = (String )args.get("jdbc.URL"); 836 this.checkStatement = (String )args.get("jdbc.validityCheckStatement"); 837 this.props = (Properties)args.get("jdbc.properties"); 838 839 if (args.get("pool.maxCheckoutRefreshAttempts") != null) 840 { 841 this.maxCheckoutRefreshAttempts = ((Integer )args.get("pool.maxCheckoutRefreshAttempts")).intValue(); 842 } 843 if (args.get("pool.checkoutRefreshWaitTime") != null) 844 { 845 this.checkoutRefreshWaitTime = ((Integer )args.get("pool.checkoutRefreshWaitTime")).intValue(); 846 } 847 848 super.init(args); 849 850 Boolean verboseValidate = (Boolean )args.get("pool.verboseValidate"); 851 if (verboseValidate != null) 852 this.verboseValidate = verboseValidate.booleanValue(); 853 854 if (args.get("pool.refreshThreadCheckInterval") != null) 855 { 856 Boolean verboseFlag = (Boolean )args.get("pool.verboseRefresh"); 857 boolean verbose = false; 858 if (verboseFlag != null) 859 verbose = verboseFlag.booleanValue(); 860 861 if (this.checkStatement == null) 862 throw new IllegalArgumentException (MessageFormat.format( 863 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_IF_PROP_MESSAGE), 864 new Object [] { "jdbc.validityCheckStatement", "pool.refreshThreadCheckInterval" })); 865 int sleepTime = ((Integer )args.get("pool.refreshThreadCheckInterval")).intValue() * 1000; 866 if (sleepTime > 0) 867 { 868 refreshThread = new RefreshThread(this, sleepTime, verbose); 869 refreshThread.start(); 870 } 871 } 872 873 if (args.get("pool.maxConnectionIdleTime") != null) 874 { 875 maxConnectionIdleTime = ((Integer )args.get("pool.maxConnectionIdleTime")).intValue(); 876 } 877 878 if (args.get("pool.syslogChannelList") != null) 879 { 880 String tmp = (String )args.get("pool.syslogChannelList"); 881 StringTokenizer st = new StringTokenizer(tmp, ", "); 882 Vector list = new Vector(); 883 while (st.hasMoreTokens()) 884 list.add(st.nextToken()); 885 setSyslogChannelList(list); 886 } 887 888 if (args.get("pool.validateOnCheckout") != null) 889 { 890 validateOnCheckout = ((Boolean )args.get("pool.validateOnCheckout")).booleanValue(); 891 } 892 893 if (args.get("pool.maidThreadCheckInterval") != null) 894 { 895 if (this.maxConnectionIdleTime == 0) 896 throw new IllegalArgumentException (MessageFormat.format( 897 PoolResources.getResourceString(MessageConstants.MUST_SPECIFY_LESS_THAN_IF_PROP_MESSAGE), 898 new Object [] { "pool.maxConnectionIdleTime", "0", "pool.maidThreadCheckInterval" })); 899 int sleepTime = ((Integer )args.get("pool.maidThreadCheckInterval")).intValue() * 1000; 900 if (sleepTime > 0) 901 { 902 maidThread = new MaidThread(this, sleepTime); 903 maidThread.start(); 904 } 905 } 906 } 907 908 912 void performMaidCheck() 913 { 914 synchronized (getSyncObject()) 915 { 916 try 917 { 918 if (DEBUG.debug()) 919 { 920 log.debug(this, MessageFormat.format( 921 PoolResources.getResourceString(MessageConstants.LOOKING_FOR_IDLE_CONNECTIONS_MESSAGE), 922 new Object [] { getName() })); 923 } 924 else 925 { 926 PrintWriter writer = DriverManager.getLogWriter(); 927 if (writer != null) 928 { 929 writer.println("JdbcConnectionPool: " + 930 MessageFormat.format( 931 PoolResources.getResourceString(MessageConstants.LOOKING_FOR_IDLE_CONNECTIONS_MESSAGE), 932 new Object [] { getName() })); 933 } 934 } 935 936 List checkedOutObjects = getCheckedOutObjects(); 937 Iterator i = checkedOutObjects.iterator(); 938 while (i.hasNext()) 939 { 940 JdbcConnectionPoolConnection c = (JdbcConnectionPoolConnection)i.next(); 941 long now = System.currentTimeMillis(); 942 long idleTime = (int)((now - c.getLastTimeUsed())/1000); 943 if (idleTime > maxConnectionIdleTime) 944 { 945 if (useSyslog) 947 { 948 Syslog.warning(this, MessageFormat.format( 949 PoolResources.getResourceString(MessageConstants.CLOSING_IDLE_CONNECTION_MESSAGE), 950 new Object [] { String.valueOf(idleTime), c.toString() })); 951 Syslog.warning(this, PoolResources.getResourceString(MessageConstants.CONNECTION_CHECKOUT_MESSAGE), c.getCheckoutStackTrace()); 952 } 953 else 954 { 955 PrintWriter pw = DriverManager.getLogWriter(); 956 if (pw != null) 957 { 958 pw.println("JdbcConnectionPool: " + MessageFormat.format( 959 PoolResources.getResourceString(MessageConstants.CLOSING_IDLE_CONNECTION_MESSAGE), 960 new Object [] { String.valueOf(idleTime), c.toString() })); 961 pw.println("JdbcConnectionPool: " 962 + PoolResources.getResourceString(MessageConstants.CONNECTION_CHECKOUT_MESSAGE)); 963 c.getCheckoutStackTrace().printStackTrace(pw); 964 } 965 } 966 967 try 968 { 969 c.close(); 970 } 971 catch (Exception x) 972 { 973 if (useSyslog) 974 { 975 Syslog.error(this, PoolResources.getResourceString(MessageConstants.EXCEPTION_CLOSE_CONNECTION_MESSAGE), x); 976 } 977 else 978 { 979 PrintWriter pw = DriverManager.getLogWriter(); 980 if (pw != null) 981 { 982 pw.println("JdbcConnectionPool: " 983 + PoolResources.getResourceString(MessageConstants.EXCEPTION_CLOSE_CONNECTION_MESSAGE)); 984 x.printStackTrace(pw); 985 } 986 } 987 } 988 } 989 } 990 } 991 catch (Exception x) 992 { 993 if (useSyslog) 994 { 995 Syslog.error(this, MessageFormat.format( 996 PoolResources.getResourceString(MessageConstants.MAID_EXCEPTION_MESSAGE), 997 new Object [] { getName() }), x); 998 } 999 else 1000 { 1001 PrintWriter pw = DriverManager.getLogWriter(); 1002 if (pw != null) 1003 { 1004 pw.println("JdbcConnectionPool: " + MessageFormat.format( 1005 PoolResources.getResourceString(MessageConstants.MAID_EXCEPTION_MESSAGE), 1006 new Object [] { getName() })); 1007 x.printStackTrace(pw); 1008 } 1009 } 1010 } 1011 } 1012 } 1013 1014 1017 Driver getDriver() 1018 { 1019 return this.driver; 1020 } 1021 1022 1027 protected ObjectPoolObject createObjectPoolObject() 1028 throws SQLException 1029 { 1030 return new JdbcConnectionPoolConnection(this, url, props); 1031 } 1032 1033 1038 public String getValidityCheckStatement() 1039 { 1040 return this.checkStatement; 1041 } 1042 1043 1046 boolean getValidateOnCheckout() 1047 { 1048 return this.validateOnCheckout; 1049 } 1050 1051 1054 boolean getVerboseValidate() 1055 { 1056 return this.verboseValidate; 1057 } 1058 1059 1062 public void destroy() 1063 { 1064 unRegisterPool(); 1065 1066 if (refreshThread != null) 1067 { 1068 if (refreshThread.isAlive()) 1069 { 1070 refreshThread.stopRunning(); 1071 refreshThread = null; 1072 } 1073 } 1074 1075 if (maidThread != null) 1076 { 1077 if (maidThread.isAlive()) 1078 { 1079 maidThread.stopRunning(); 1080 maidThread = null; 1081 } 1082 } 1083 1084 closeAllConnections(); 1085 } 1086 1087 1090 class RefreshThread 1091 extends Thread 1092 implements SyslogChannelAware 1093 { 1094 private JdbcConnectionPool pool = null; 1095 private int sleepTime; 1096 private boolean verbose = false; 1097 1098 public Object getSyslogChannel() 1099 { 1100 if (pool != null) 1101 return pool.getSyslogChannel(); 1102 return null; 1103 } 1104 1105 public void stopRunning() 1106 { 1107 this.pool = null; 1108 } 1109 1110 public RefreshThread(JdbcConnectionPool pool, int sleepTime, boolean verbose) 1111 { 1112 super("JdbcConnectionPoolRefreshThread[poolname=" + pool.getName() + "]"); 1113 setPriority(Thread.MIN_PRIORITY); 1114 setDaemon(true); this.pool = pool; 1116 this.sleepTime = sleepTime; 1117 this.verbose = verbose; 1118 } 1119 1120 public void run() 1121 { 1122 while (pool != null) 1123 { 1124 try 1125 { 1126 sleep(sleepTime); 1127 } 1128 catch (InterruptedException x) 1129 { 1130 ; 1131 } 1132 try 1133 { 1134 if (verbose && pool != null) 1135 { 1136 if (useSyslog) 1137 { 1138 Syslog.info(this, MessageFormat.format( 1139 PoolResources.getResourceString(MessageConstants.REFRESHING_CONNECTIONS_MESSAGE), 1140 new Object [] { pool.getName() })); 1141 } 1142 else 1143 { 1144 PrintWriter writer = DriverManager.getLogWriter(); 1145 if (writer != null) 1146 { 1147 writer.println(MessageFormat.format( 1148 PoolResources.getResourceString(MessageConstants.REFRESHING_CONNECTIONS_MESSAGE), 1149 new Object [] { pool.getName() })); 1150 } 1151 } 1152 } 1153 if (pool != null) 1154 pool.refreshConnections(verbose); 1155 } 1156 catch (Exception x) 1157 { 1158 } 1160 } 1161 } 1162 } 1163 1164 1170 class MaidThread 1171 extends Thread 1172 implements SyslogChannelAware 1173 { 1174 private JdbcConnectionPool pool = null; 1175 private int sleepTime; 1176 1177 public MaidThread(JdbcConnectionPool pool, int sleepTime) 1178 { 1179 super("JdbcConnectionPoolMaidThread[poolname=" + pool.getName() + "]"); 1180 setPriority(Thread.MIN_PRIORITY); 1181 setDaemon(true); this.pool = pool; 1183 this.sleepTime = sleepTime; 1184 } 1185 1186 public Object getSyslogChannel() 1187 { 1188 if (pool != null) 1189 return pool.getSyslogChannel(); 1190 return null; 1191 } 1192 1193 public void stopRunning() 1194 { 1195 this.pool = null; 1196 } 1197 1198 public void run() 1199 { 1200 while (pool != null) 1201 { 1202 try 1203 { 1204 sleep(sleepTime); 1205 } 1206 catch (InterruptedException x) 1207 { 1208 ; 1209 } 1210 if (pool != null) 1211 pool.performMaidCheck(); 1212 } 1213 } 1214 } 1215} 1216 | Popular Tags |