1 16 package com.ibatis.common.jdbc; 17 18 import com.ibatis.common.beans.ClassInfo; 19 import com.ibatis.common.exception.NestedRuntimeException; 20 import com.ibatis.common.resources.Resources; 21 import com.ibatis.common.logging.LogFactory; 22 import com.ibatis.common.logging.Log; 23 24 import javax.sql.DataSource ; 25 import java.io.PrintWriter ; 26 import java.lang.reflect.InvocationHandler ; 27 import java.lang.reflect.Method ; 28 import java.lang.reflect.Proxy ; 29 import java.sql.*; 30 import java.util.*; 31 32 52 public class SimpleDataSource implements DataSource { 53 54 private static final Log log = LogFactory.getLog(SimpleDataSource.class); 55 56 private static final String PROP_JDBC_DRIVER = "JDBC.Driver"; 58 private static final String PROP_JDBC_URL = "JDBC.ConnectionURL"; 59 private static final String PROP_JDBC_USERNAME = "JDBC.Username"; 60 private static final String PROP_JDBC_PASSWORD = "JDBC.Password"; 61 private static final String PROP_JDBC_DEFAULT_AUTOCOMMIT = "JDBC.DefaultAutoCommit"; 62 63 private static final String PROP_POOL_MAX_ACTIVE_CONN = "Pool.MaximumActiveConnections"; 65 private static final String PROP_POOL_MAX_IDLE_CONN = "Pool.MaximumIdleConnections"; 66 private static final String PROP_POOL_MAX_CHECKOUT_TIME = "Pool.MaximumCheckoutTime"; 67 private static final String PROP_POOL_TIME_TO_WAIT = "Pool.TimeToWait"; 68 private static final String PROP_POOL_PING_QUERY = "Pool.PingQuery"; 69 private static final String PROP_POOL_PING_CONN_OLDER_THAN = "Pool.PingConnectionsOlderThan"; 70 private static final String PROP_POOL_PING_ENABLED = "Pool.PingEnabled"; 71 private static final String PROP_POOL_PING_CONN_NOT_USED_FOR = "Pool.PingConnectionsNotUsedFor"; 72 private int expectedConnectionTypeCode; 73 private static final String ADD_DRIVER_PROPS_PREFIX = "Driver."; 75 private static final int ADD_DRIVER_PROPS_PREFIX_LENGTH = ADD_DRIVER_PROPS_PREFIX.length(); 76 77 private final Object POOL_LOCK = new Object (); 79 private List idleConnections = new ArrayList(); 80 private List activeConnections = new ArrayList(); 81 private long requestCount = 0; 82 private long accumulatedRequestTime = 0; 83 private long accumulatedCheckoutTime = 0; 84 private long claimedOverdueConnectionCount = 0; 85 private long accumulatedCheckoutTimeOfOverdueConnections = 0; 86 private long accumulatedWaitTime = 0; 87 private long hadToWaitCount = 0; 88 private long badConnectionCount = 0; 89 91 private String jdbcDriver; 93 private String jdbcUrl; 94 private String jdbcUsername; 95 private String jdbcPassword; 96 private boolean jdbcDefaultAutoCommit; 97 private Properties driverProps; 98 private boolean useDriverProps; 99 100 private int poolMaximumActiveConnections; 101 private int poolMaximumIdleConnections; 102 private int poolMaximumCheckoutTime; 103 private int poolTimeToWait; 104 private String poolPingQuery; 105 private boolean poolPingEnabled; 106 private int poolPingConnectionsOlderThan; 107 private int poolPingConnectionsNotUsedFor; 108 110 115 public SimpleDataSource(Map props) { 116 initialize(props); 117 } 118 119 private void initialize(Map props) { 120 try { 121 if (props == null) { 122 throw new NestedRuntimeException("SimpleDataSource: The properties map passed to the initializer was null."); 123 } 124 125 if (!(props.containsKey(PROP_JDBC_DRIVER) 126 && props.containsKey(PROP_JDBC_URL) 127 && props.containsKey(PROP_JDBC_USERNAME) 128 && props.containsKey(PROP_JDBC_PASSWORD))) { 129 throw new NestedRuntimeException("SimpleDataSource: Some properties were not set."); 130 } else { 131 132 jdbcDriver = (String ) props.get(PROP_JDBC_DRIVER); 133 jdbcUrl = (String ) props.get(PROP_JDBC_URL); 134 jdbcUsername = (String ) props.get(PROP_JDBC_USERNAME); 135 jdbcPassword = (String ) props.get(PROP_JDBC_PASSWORD); 136 137 poolMaximumActiveConnections = 138 props.containsKey(PROP_POOL_MAX_ACTIVE_CONN) 139 ? Integer.parseInt((String ) props.get(PROP_POOL_MAX_ACTIVE_CONN)) 140 : 10; 141 142 poolMaximumIdleConnections = 143 props.containsKey(PROP_POOL_MAX_IDLE_CONN) 144 ? Integer.parseInt((String ) props.get(PROP_POOL_MAX_IDLE_CONN)) 145 : 5; 146 147 poolMaximumCheckoutTime = 148 props.containsKey(PROP_POOL_MAX_CHECKOUT_TIME) 149 ? Integer.parseInt((String ) props.get(PROP_POOL_MAX_CHECKOUT_TIME)) 150 : 20000; 151 152 poolTimeToWait = 153 props.containsKey(PROP_POOL_TIME_TO_WAIT) 154 ? Integer.parseInt((String ) props.get(PROP_POOL_TIME_TO_WAIT)) 155 : 20000; 156 157 poolPingEnabled = 158 props.containsKey(PROP_POOL_PING_ENABLED) 159 ? Boolean.valueOf((String ) props.get(PROP_POOL_PING_ENABLED)).booleanValue() 160 : false; 161 162 poolPingQuery = 163 props.containsKey(PROP_POOL_PING_QUERY) 164 ? (String ) props.get(PROP_POOL_PING_QUERY) 165 : "NO PING QUERY SET"; 166 167 poolPingConnectionsOlderThan = 168 props.containsKey(PROP_POOL_PING_CONN_OLDER_THAN) 169 ? Integer.parseInt((String ) props.get(PROP_POOL_PING_CONN_OLDER_THAN)) 170 : 0; 171 172 poolPingConnectionsNotUsedFor = 173 props.containsKey(PROP_POOL_PING_CONN_NOT_USED_FOR) 174 ? Integer.parseInt((String ) props.get(PROP_POOL_PING_CONN_NOT_USED_FOR)) 175 : 0; 176 177 jdbcDefaultAutoCommit = 178 props.containsKey(PROP_JDBC_DEFAULT_AUTOCOMMIT) 179 ? Boolean.valueOf((String ) props.get(PROP_JDBC_DEFAULT_AUTOCOMMIT)).booleanValue() 180 : false; 181 182 useDriverProps = false; 183 Iterator propIter = props.keySet().iterator(); 184 driverProps = new Properties(); 185 driverProps.put("user", jdbcUsername); 186 driverProps.put("password", jdbcPassword); 187 while (propIter.hasNext()) { 188 String name = (String ) propIter.next(); 189 String value = (String ) props.get(name); 190 if (name.startsWith(ADD_DRIVER_PROPS_PREFIX)) { 191 driverProps.put(name.substring(ADD_DRIVER_PROPS_PREFIX_LENGTH), value); 192 useDriverProps = true; 193 } 194 } 195 196 expectedConnectionTypeCode = assembleConnectionTypeCode(jdbcUrl, jdbcUsername, jdbcPassword); 197 198 Resources.instantiate(jdbcDriver); 199 } 200 201 } catch (Exception e) { 202 log.error("SimpleDataSource: Error while loading properties. Cause: " + e.toString(), e); 203 throw new NestedRuntimeException("SimpleDataSource: Error while loading properties. Cause: " + e, e); 204 } 205 } 206 207 private int assembleConnectionTypeCode(String url, String username, String password) { 208 return ("" + url + username + password).hashCode(); 209 } 210 211 214 public Connection getConnection() throws SQLException { 215 return popConnection(jdbcUsername, jdbcPassword).getProxyConnection(); 216 } 217 218 221 public Connection getConnection(String username, String password) throws SQLException { 222 return popConnection(username, password).getProxyConnection(); 223 } 224 225 228 public void setLoginTimeout(int loginTimeout) throws SQLException { 229 DriverManager.setLoginTimeout(loginTimeout); 230 } 231 232 235 public int getLoginTimeout() throws SQLException { 236 return DriverManager.getLoginTimeout(); 237 } 238 239 242 public void setLogWriter(PrintWriter logWriter) throws SQLException { 243 DriverManager.setLogWriter(logWriter); 244 } 245 246 249 public PrintWriter getLogWriter() throws SQLException { 250 return DriverManager.getLogWriter(); 251 } 252 253 258 public int getPoolPingConnectionsNotUsedFor() { 259 return poolPingConnectionsNotUsedFor; 260 } 261 262 266 public String getJdbcDriver() { 267 return jdbcDriver; 268 } 269 270 274 public String getJdbcUrl() { 275 return jdbcUrl; 276 } 277 278 282 public String getJdbcUsername() { 283 return jdbcUsername; 284 } 285 286 290 public String getJdbcPassword() { 291 return jdbcPassword; 292 } 293 294 298 public int getPoolMaximumActiveConnections() { 299 return poolMaximumActiveConnections; 300 } 301 302 306 public int getPoolMaximumIdleConnections() { 307 return poolMaximumIdleConnections; 308 } 309 310 315 public int getPoolMaximumCheckoutTime() { 316 return poolMaximumCheckoutTime; 317 } 318 319 323 public int getPoolTimeToWait() { 324 return poolTimeToWait; 325 } 326 327 331 public String getPoolPingQuery() { 332 return poolPingQuery; 333 } 334 335 339 public boolean isPoolPingEnabled() { 340 return poolPingEnabled; 341 } 342 343 347 public int getPoolPingConnectionsOlderThan() { 348 return poolPingConnectionsOlderThan; 349 } 350 351 private int getExpectedConnectionTypeCode() { 352 return expectedConnectionTypeCode; 353 } 354 355 359 public long getRequestCount() { 360 synchronized (POOL_LOCK) { 361 return requestCount; 362 } 363 } 364 365 369 public long getAverageRequestTime() { 370 synchronized (POOL_LOCK) { 371 return requestCount == 0 ? 0 : accumulatedRequestTime / requestCount; 372 } 373 } 374 375 379 public long getAverageWaitTime() { 380 synchronized (POOL_LOCK) { 381 return hadToWaitCount == 0 ? 0 : accumulatedWaitTime / hadToWaitCount; 382 } 383 } 384 385 389 public long getHadToWaitCount() { 390 synchronized (POOL_LOCK) { 391 return hadToWaitCount; 392 } 393 } 394 395 399 public long getBadConnectionCount() { 400 synchronized (POOL_LOCK) { 401 return badConnectionCount; 402 } 403 } 404 405 409 public long getClaimedOverdueConnectionCount() { 410 synchronized (POOL_LOCK) { 411 return claimedOverdueConnectionCount; 412 } 413 } 414 415 419 public long getAverageOverdueCheckoutTime() { 420 synchronized (POOL_LOCK) { 421 return claimedOverdueConnectionCount == 0 ? 0 : accumulatedCheckoutTimeOfOverdueConnections / claimedOverdueConnectionCount; 422 } 423 } 424 425 426 430 public long getAverageCheckoutTime() { 431 synchronized (POOL_LOCK) { 432 return requestCount == 0 ? 0 : accumulatedCheckoutTime / requestCount; 433 } 434 } 435 436 440 public String getStatus() { 441 StringBuffer buffer = new StringBuffer (); 442 443 buffer.append("\n==============================================================="); 444 buffer.append("\n jdbcDriver " + jdbcDriver); 445 buffer.append("\n jdbcUrl " + jdbcUrl); 446 buffer.append("\n jdbcUsername " + jdbcUsername); 447 buffer.append("\n jdbcPassword " + (jdbcPassword == null ? "NULL" : "************")); 448 buffer.append("\n poolMaxActiveConnections " + poolMaximumActiveConnections); 449 buffer.append("\n poolMaxIdleConnections " + poolMaximumIdleConnections); 450 buffer.append("\n poolMaxCheckoutTime " + poolMaximumCheckoutTime); 451 buffer.append("\n poolTimeToWait " + poolTimeToWait); 452 buffer.append("\n poolPingEnabled " + poolPingEnabled); 453 buffer.append("\n poolPingQuery " + poolPingQuery); 454 buffer.append("\n poolPingConnectionsOlderThan " + poolPingConnectionsOlderThan); 455 buffer.append("\n poolPingConnectionsNotUsedFor " + poolPingConnectionsNotUsedFor); 456 buffer.append("\n --------------------------------------------------------------"); 457 buffer.append("\n activeConnections " + activeConnections.size()); 458 buffer.append("\n idleConnections " + idleConnections.size()); 459 buffer.append("\n requestCount " + getRequestCount()); 460 buffer.append("\n averageRequestTime " + getAverageRequestTime()); 461 buffer.append("\n averageCheckoutTime " + getAverageCheckoutTime()); 462 buffer.append("\n claimedOverdue " + getClaimedOverdueConnectionCount()); 463 buffer.append("\n averageOverdueCheckoutTime " + getAverageOverdueCheckoutTime()); 464 buffer.append("\n hadToWait " + getHadToWaitCount()); 465 buffer.append("\n averageWaitTime " + getAverageWaitTime()); 466 buffer.append("\n badConnectionCount " + getBadConnectionCount()); 467 buffer.append("\n==============================================================="); 468 return buffer.toString(); 469 } 470 471 474 public void forceCloseAll() { 475 synchronized (POOL_LOCK) { 476 for (int i = activeConnections.size(); i > 0; i--) { 477 try { 478 SimplePooledConnection conn = (SimplePooledConnection) activeConnections.remove(i - 1); 479 conn.invalidate(); 480 481 Connection realConn = conn.getRealConnection(); 482 if (!realConn.getAutoCommit()) { 483 realConn.rollback(); 484 } 485 realConn.close(); 486 } catch (Exception e) { 487 } 489 } 490 for (int i = idleConnections.size(); i > 0; i--) { 491 try { 492 SimplePooledConnection conn = (SimplePooledConnection) idleConnections.remove(i - 1); 493 conn.invalidate(); 494 495 Connection realConn = conn.getRealConnection(); 496 if (!realConn.getAutoCommit()) { 497 realConn.rollback(); 498 } 499 realConn.close(); 500 } catch (Exception e) { 501 } 503 } 504 } 505 if (log.isDebugEnabled()) { 506 log.debug("SimpleDataSource forcefully closed/removed all connections."); 507 } 508 } 509 510 private void pushConnection(SimplePooledConnection conn) 511 throws SQLException { 512 513 synchronized (POOL_LOCK) { 514 activeConnections.remove(conn); 515 if (conn.isValid()) { 516 if (idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == getExpectedConnectionTypeCode()) { 517 accumulatedCheckoutTime += conn.getCheckoutTime(); 518 if (!conn.getRealConnection().getAutoCommit()) { 519 conn.getRealConnection().rollback(); 520 } 521 SimplePooledConnection newConn = new SimplePooledConnection(conn.getRealConnection(), this); 522 idleConnections.add(newConn); 523 newConn.setCreatedTimestamp(conn.getCreatedTimestamp()); 524 newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp()); 525 conn.invalidate(); 526 if (log.isDebugEnabled()) { 527 log.debug("Returned connection " + newConn.getRealHashCode() + " to pool."); 528 } 529 POOL_LOCK.notifyAll(); 530 } else { 531 accumulatedCheckoutTime += conn.getCheckoutTime(); 532 if (!conn.getRealConnection().getAutoCommit()) { 533 conn.getRealConnection().rollback(); 534 } 535 conn.getRealConnection().close(); 536 if (log.isDebugEnabled()) { 537 log.debug("Closed connection " + conn.getRealHashCode() + "."); 538 } 539 conn.invalidate(); 540 } 541 } else { 542 if (log.isDebugEnabled()) { 543 log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection."); 544 } 545 badConnectionCount++; 546 } 547 } 548 } 549 550 private SimplePooledConnection popConnection(String username, String password) 551 throws SQLException { 552 boolean countedWait = false; 553 SimplePooledConnection conn = null; 554 long t = System.currentTimeMillis(); 555 int localBadConnectionCount = 0; 556 557 while (conn == null) { 558 synchronized (POOL_LOCK) { 559 if (idleConnections.size() > 0) { 560 conn = (SimplePooledConnection) idleConnections.remove(0); 562 if (log.isDebugEnabled()) { 563 log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); 564 } 565 } else { 566 if (activeConnections.size() < poolMaximumActiveConnections) { 568 if (useDriverProps) { 570 conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, driverProps), this); 571 } else { 572 conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword), this); 573 } 574 Connection realConn = conn.getRealConnection(); 575 if (realConn.getAutoCommit() != jdbcDefaultAutoCommit) { 576 realConn.setAutoCommit(jdbcDefaultAutoCommit); 577 } 578 if (log.isDebugEnabled()) { 579 log.debug("Created connection " + conn.getRealHashCode() + "."); 580 } 581 } else { 582 SimplePooledConnection oldestActiveConnection = (SimplePooledConnection) activeConnections.get(0); 584 long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); 585 if (longestCheckoutTime > poolMaximumCheckoutTime) { 586 claimedOverdueConnectionCount++; 588 accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; 589 accumulatedCheckoutTime += longestCheckoutTime; 590 activeConnections.remove(oldestActiveConnection); 591 if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { 592 oldestActiveConnection.getRealConnection().rollback(); 593 } 594 conn = new SimplePooledConnection(oldestActiveConnection.getRealConnection(), this); 595 oldestActiveConnection.invalidate(); 596 if (log.isDebugEnabled()) { 597 log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); 598 } 599 } else { 600 try { 602 if (!countedWait) { 603 hadToWaitCount++; 604 countedWait = true; 605 } 606 if (log.isDebugEnabled()) { 607 log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection."); 608 } 609 long wt = System.currentTimeMillis(); 610 POOL_LOCK.wait(poolTimeToWait); 611 accumulatedWaitTime += System.currentTimeMillis() - wt; 612 } catch (InterruptedException e) { 613 break; 614 } 615 } 616 } 617 } 618 if (conn != null) { 619 if (conn.isValid()) { 620 if (!conn.getRealConnection().getAutoCommit()) { 621 conn.getRealConnection().rollback(); 622 } 623 conn.setConnectionTypeCode(assembleConnectionTypeCode(jdbcUrl, username, password)); 624 conn.setCheckoutTimestamp(System.currentTimeMillis()); 625 conn.setLastUsedTimestamp(System.currentTimeMillis()); 626 activeConnections.add(conn); 627 requestCount++; 628 accumulatedRequestTime += System.currentTimeMillis() - t; 629 } else { 630 if (log.isDebugEnabled()) { 631 log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); 632 } 633 badConnectionCount++; 634 localBadConnectionCount++; 635 conn = null; 636 if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) { 637 if (log.isDebugEnabled()) { 638 log.debug("SimpleDataSource: Could not get a good connection to the database."); 639 } 640 throw new SQLException("SimpleDataSource: Could not get a good connection to the database."); 641 } 642 } 643 } 644 } 645 646 } 647 648 if (conn == null) { 649 if (log.isDebugEnabled()) { 650 log.debug("SimpleDataSource: Unknown severe error condition. The connection pool returned a null connection."); 651 } 652 throw new SQLException("SimpleDataSource: Unknown severe error condition. The connection pool returned a null connection."); 653 } 654 655 return conn; 656 } 657 658 664 private boolean pingConnection(SimplePooledConnection conn) { 665 boolean result = true; 666 667 try { 668 result = !conn.getRealConnection().isClosed(); 669 } catch (SQLException e) { 670 result = false; 671 } 672 673 if (result) { 674 if (poolPingEnabled) { 675 if ((poolPingConnectionsOlderThan > 0 && conn.getAge() > poolPingConnectionsOlderThan) 676 || (poolPingConnectionsNotUsedFor > 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor)) { 677 678 try { 679 if (log.isDebugEnabled()) { 680 log.debug("Testing connection " + conn.getRealHashCode() + "..."); 681 } 682 Connection realConn = conn.getRealConnection(); 683 Statement statement = realConn.createStatement(); 684 ResultSet rs = statement.executeQuery(poolPingQuery); 685 rs.close(); 686 statement.close(); 687 if (!realConn.getAutoCommit()) { 688 realConn.rollback(); 689 } 690 result = true; 691 if (log.isDebugEnabled()) { 692 log.debug("Connection " + conn.getRealHashCode() + " is GOOD!"); 693 } 694 } catch (Exception e) { 695 try { 696 conn.getRealConnection().close(); 697 } catch (Exception e2) { 698 } 700 result = false; 701 if (log.isDebugEnabled()) { 702 log.debug("Connection " + conn.getRealHashCode() + " is BAD!"); 703 } 704 } 705 } 706 } 707 } 708 return result; 709 } 710 711 717 public static Connection unwrapConnection(Connection conn) { 718 if (conn instanceof SimplePooledConnection) { 719 return ((SimplePooledConnection) conn).getRealConnection(); 720 } else { 721 return conn; 722 } 723 } 724 725 protected void finalize() throws Throwable { 726 forceCloseAll(); 727 } 728 729 734 private static class SimplePooledConnection implements InvocationHandler { 735 736 private static final String CLOSE = "close"; 737 private static final Class [] IFACES = new Class []{Connection.class}; 738 739 private int hashCode = 0; 740 private SimpleDataSource dataSource; 741 private Connection realConnection; 742 private Connection proxyConnection; 743 private long checkoutTimestamp; 744 private long createdTimestamp; 745 private long lastUsedTimestamp; 746 private int connectionTypeCode; 747 private boolean valid; 748 749 755 public SimplePooledConnection(Connection connection, SimpleDataSource dataSource) { 756 this.hashCode = connection.hashCode(); 757 this.realConnection = connection; 758 this.dataSource = dataSource; 759 this.createdTimestamp = System.currentTimeMillis(); 760 this.lastUsedTimestamp = System.currentTimeMillis(); 761 this.valid = true; 762 763 proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this); 764 } 765 766 769 public void invalidate() { 770 valid = false; 771 } 772 773 778 public boolean isValid() { 779 return valid && realConnection != null && dataSource.pingConnection(this); 780 } 781 782 786 public Connection getRealConnection() { 787 return realConnection; 788 } 789 790 794 public Connection getProxyConnection() { 795 return proxyConnection; 796 } 797 798 803 public int getRealHashCode() { 804 if (realConnection == null) { 805 return 0; 806 } else { 807 return realConnection.hashCode(); 808 } 809 } 810 811 815 public int getConnectionTypeCode() { 816 return connectionTypeCode; 817 } 818 819 823 public void setConnectionTypeCode(int connectionTypeCode) { 824 this.connectionTypeCode = connectionTypeCode; 825 } 826 827 831 public long getCreatedTimestamp() { 832 return createdTimestamp; 833 } 834 835 839 public void setCreatedTimestamp(long createdTimestamp) { 840 this.createdTimestamp = createdTimestamp; 841 } 842 843 847 public long getLastUsedTimestamp() { 848 return lastUsedTimestamp; 849 } 850 851 855 public void setLastUsedTimestamp(long lastUsedTimestamp) { 856 this.lastUsedTimestamp = lastUsedTimestamp; 857 } 858 859 863 public long getTimeElapsedSinceLastUse() { 864 return System.currentTimeMillis() - lastUsedTimestamp; 865 } 866 867 871 public long getAge() { 872 return System.currentTimeMillis() - createdTimestamp; 873 } 874 875 879 public long getCheckoutTimestamp() { 880 return checkoutTimestamp; 881 } 882 883 887 public void setCheckoutTimestamp(long timestamp) { 888 this.checkoutTimestamp = timestamp; 889 } 890 891 895 public long getCheckoutTime() { 896 return System.currentTimeMillis() - checkoutTimestamp; 897 } 898 899 private Connection getValidConnection() { 900 if (!valid) { 901 throw new NestedRuntimeException("Error accessing SimplePooledConnection. Connection has been invalidated (probably released back to the pool)."); 902 } 903 return realConnection; 904 } 905 906 public int hashCode() { 907 return hashCode; 908 } 909 910 916 public boolean equals(Object obj) { 917 if (obj instanceof SimplePooledConnection) { 918 return realConnection.hashCode() == (((SimplePooledConnection) obj).realConnection.hashCode()); 919 } else if (obj instanceof Connection) { 920 return hashCode == obj.hashCode(); 921 } else { 922 return false; 923 } 924 } 925 926 930 938 public Object invoke(Object proxy, Method method, Object [] args) 939 throws Throwable { 940 String methodName = method.getName(); 941 if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) { 942 dataSource.pushConnection(this); 943 return null; 944 } else { 945 try { 946 return method.invoke(getValidConnection(), args); 947 } catch (Throwable t) { 948 throw ClassInfo.unwrapThrowable(t); 949 } 950 } 951 } 952 953 public Statement createStatement() throws SQLException { 954 return getValidConnection().createStatement(); 955 } 956 957 public PreparedStatement prepareStatement(String sql) throws SQLException { 958 return getValidConnection().prepareStatement(sql); 959 } 960 961 public CallableStatement prepareCall(String sql) throws SQLException { 962 return getValidConnection().prepareCall(sql); 963 } 964 965 public String nativeSQL(String sql) throws SQLException { 966 return getValidConnection().nativeSQL(sql); 967 } 968 969 public void setAutoCommit(boolean autoCommit) throws SQLException { 970 getValidConnection().setAutoCommit(autoCommit); 971 } 972 973 public boolean getAutoCommit() throws SQLException { 974 return getValidConnection().getAutoCommit(); 975 } 976 977 public void commit() throws SQLException { 978 getValidConnection().commit(); 979 } 980 981 public void rollback() throws SQLException { 982 getValidConnection().rollback(); 983 } 984 985 public void close() throws SQLException { 986 dataSource.pushConnection(this); 987 } 988 989 public boolean isClosed() throws SQLException { 990 return getValidConnection().isClosed(); 991 } 992 993 public DatabaseMetaData getMetaData() throws SQLException { 994 return getValidConnection().getMetaData(); 995 } 996 997 public void setReadOnly(boolean readOnly) throws SQLException { 998 getValidConnection().setReadOnly(readOnly); 999 } 1000 1001 public boolean isReadOnly() throws SQLException { 1002 return getValidConnection().isReadOnly(); 1003 } 1004 1005 public void setCatalog(String catalog) throws SQLException { 1006 getValidConnection().setCatalog(catalog); 1007 } 1008 1009 public String getCatalog() throws SQLException { 1010 return getValidConnection().getCatalog(); 1011 } 1012 1013 public void setTransactionIsolation(int level) throws SQLException { 1014 getValidConnection().setTransactionIsolation(level); 1015 } 1016 1017 public int getTransactionIsolation() throws SQLException { 1018 return getValidConnection().getTransactionIsolation(); 1019 } 1020 1021 public SQLWarning getWarnings() throws SQLException { 1022 return getValidConnection().getWarnings(); 1023 } 1024 1025 public void clearWarnings() throws SQLException { 1026 getValidConnection().clearWarnings(); 1027 } 1028 1029 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { 1030 return getValidConnection().createStatement(resultSetType, resultSetConcurrency); 1031 } 1032 1033 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { 1034 return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency); 1035 } 1036 1037 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { 1038 return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency); 1039 } 1040 1041 public Map getTypeMap() throws SQLException { 1042 return getValidConnection().getTypeMap(); 1043 } 1044 1045 public void setTypeMap(Map map) throws SQLException { 1046 getValidConnection().setTypeMap(map); 1047 } 1048 1049 1053 public void setHoldability(int holdability) throws SQLException { 1054 getValidConnection().setHoldability(holdability); 1055 } 1056 1057 public int getHoldability() throws SQLException { 1058 return getValidConnection().getHoldability(); 1059 } 1060 1061 public Savepoint setSavepoint() throws SQLException { 1062 return getValidConnection().setSavepoint(); 1063 } 1064 1065 public Savepoint setSavepoint(String name) throws SQLException { 1066 return getValidConnection().setSavepoint(name); 1067 } 1068 1069 public void rollback(Savepoint savepoint) throws SQLException { 1070 getValidConnection().rollback(savepoint); 1071 } 1072 1073 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 1074 getValidConnection().releaseSavepoint(savepoint); 1075 } 1076 1077 public Statement createStatement(int resultSetType, int resultSetConcurrency, 1078 int resultSetHoldability) throws SQLException { 1079 return getValidConnection().createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); 1080 } 1081 1082 public PreparedStatement prepareStatement(String sql, int resultSetType, 1083 int resultSetConcurrency, int resultSetHoldability) 1084 throws SQLException { 1085 return getValidConnection().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 1086 } 1087 1088 public CallableStatement prepareCall(String sql, int resultSetType, 1089 int resultSetConcurrency, 1090 int resultSetHoldability) throws SQLException { 1091 return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 1092 } 1093 1094 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) 1095 throws SQLException { 1096 return getValidConnection().prepareStatement(sql, autoGeneratedKeys); 1097 } 1098 1099 public PreparedStatement prepareStatement(String sql, int columnIndexes[]) 1100 throws SQLException { 1101 return getValidConnection().prepareStatement(sql, columnIndexes); 1102 } 1103 1104 public PreparedStatement prepareStatement(String sql, String columnNames[]) 1105 throws SQLException { 1106 return getValidConnection().prepareStatement(sql, columnNames); 1107 } 1108 1109 1110 } 1111} 1112 | Popular Tags |