1 22 23 24 package com.mchange.v2.c3p0.impl; 25 26 import java.lang.reflect.*; 27 import java.sql.*; 28 import java.util.*; 29 import javax.sql.*; 30 import com.mchange.v2.log.*; 31 import com.mchange.v2.sql.*; 32 import com.mchange.v2.sql.filter.*; 33 import com.mchange.v2.c3p0.*; 34 import com.mchange.v2.c3p0.stmt.*; 35 import com.mchange.v2.c3p0.C3P0ProxyConnection; 36 import com.mchange.v2.c3p0.util.ConnectionEventSupport; 37 import com.mchange.v2.lang.ObjectUtils; 38 39 public final class C3P0PooledConnection extends AbstractC3P0PooledConnection 40 { 41 final static MLogger logger = MLog.getLogger( C3P0PooledConnection.class ); 42 43 final static Class [] PROXY_CTOR_ARGS = new Class []{ InvocationHandler.class }; 44 45 final static Constructor CON_PROXY_CTOR; 46 47 final static Method RS_CLOSE_METHOD; 48 final static Method STMT_CLOSE_METHOD; 49 50 final static Object [] CLOSE_ARGS; 51 52 final static Set OBJECT_METHODS; 53 54 57 private static Constructor createProxyConstructor(Class intfc) throws NoSuchMethodException 58 { 59 Class [] proxyInterfaces = new Class [] { intfc }; 60 Class proxyCl = Proxy.getProxyClass(C3P0PooledConnection.class.getClassLoader(), proxyInterfaces); 61 return proxyCl.getConstructor( PROXY_CTOR_ARGS ); 62 } 63 64 static 65 { 66 try 67 { 68 CON_PROXY_CTOR = createProxyConstructor( ProxyConnection.class ); 69 70 Class [] argClasses = new Class [0]; 71 RS_CLOSE_METHOD = ResultSet.class.getMethod("close", argClasses); 72 STMT_CLOSE_METHOD = Statement.class.getMethod("close", argClasses); 73 74 CLOSE_ARGS = new Object [0]; 75 76 OBJECT_METHODS = Collections.unmodifiableSet( new HashSet( Arrays.asList( Object .class.getMethods() ) ) ); 77 } 78 catch (Exception e) 79 { 80 logger.log(MLevel.SEVERE, "An Exception occurred in static initializer of" + C3P0PooledConnection.class.getName(), e); 82 throw new InternalError ("Something is very wrong, or this is a pre 1.3 JVM." + 83 "We cannot set up dynamic proxies and/or methods!"); 84 } 85 } 86 87 final ConnectionTester connectionTester; 89 final boolean autoCommitOnClose; 90 final boolean forceIgnoreUnresolvedTransactions; 91 final boolean supports_setTypeMap; 92 final boolean supports_setHoldability; 93 final int dflt_txn_isolation; 94 final String dflt_catalog; 95 final int dflt_holdability; 96 97 final ConnectionEventSupport ces = new ConnectionEventSupport(this); 99 100 volatile Connection physicalConnection; 102 volatile Exception invalidatingException = null; 103 104 ProxyConnection exposedProxy; 107 108 int connection_status = ConnectionTester.CONNECTION_IS_OKAY; 110 111 117 final Set uncachedActiveStatements = Collections.synchronizedSet( new HashSet() ); 118 119 volatile GooGooStatementCache scache; 121 volatile boolean isolation_lvl_nondefault = false; 122 volatile boolean catalog_nondefault = false; 123 volatile boolean holdability_nondefault = false; 124 125 public C3P0PooledConnection(Connection con, 126 ConnectionTester connectionTester, 127 boolean autoCommitOnClose, 128 boolean forceIgnoreUnresolvedTransactions, 129 ConnectionCustomizer cc, 130 String pdsIdt) throws SQLException 131 { 132 try 133 { 134 if (cc != null) 135 cc.onAcquire( con, pdsIdt ); 136 } 137 catch (Exception e) 138 { throw SqlUtils.toSQLException(e); } 139 140 this.physicalConnection = con; 141 this.connectionTester = connectionTester; 142 this.autoCommitOnClose = autoCommitOnClose; 143 this.forceIgnoreUnresolvedTransactions = forceIgnoreUnresolvedTransactions; 144 this.supports_setTypeMap = C3P0ImplUtils.supportsMethod(con, "setTypeMap", new Class []{ Map.class }); 145 this.supports_setHoldability = C3P0ImplUtils.supportsMethod(con, "setHoldability", new Class []{ Integer .class }); 146 this.dflt_txn_isolation = con.getTransactionIsolation(); 147 this.dflt_catalog = con.getCatalog(); 148 this.dflt_holdability = (supports_setHoldability ? con.getHoldability() : ResultSet.CLOSE_CURSORS_AT_COMMIT); 149 } 150 151 Connection getPhysicalConnection() 153 { return physicalConnection; } 154 155 boolean isClosed() throws SQLException 156 { return (physicalConnection == null); } 157 158 void initStatementCache( GooGooStatementCache scache ) 159 { this.scache = scache; } 160 161 162 165 public synchronized Connection getConnection() 167 throws SQLException 168 { 169 if ( exposedProxy != null) 170 { 171 176 180 logger.warning("c3p0 -- Uh oh... getConnection() was called on a PooledConnection when " + 181 "it had already provided a client with a Connection that has not yet been " + 182 "closed. This probably indicates a bug in the connection pool!!!"); 183 184 return exposedProxy; 185 } 186 else 187 { return getCreateNewConnection(); } 188 } 189 190 private Connection getCreateNewConnection() 193 throws SQLException 194 { 195 try 196 { 197 200 ensureOkay(); 201 205 return (exposedProxy = createProxyConnection()); 207 } 208 catch (SQLException e) 209 { throw e; } 210 catch (Exception e) 211 { 212 logger.log(MLevel.WARNING, "Failed to acquire connection!", e); 214 throw new SQLException("Failed to acquire connection!"); 215 } 216 } 217 218 public void closeAll() throws SQLException 219 { 220 if (scache != null) 221 scache.closeAll( physicalConnection ); 222 } 223 224 public void close() throws SQLException 225 { this.close( false ); } 226 227 private synchronized void close(boolean known_invalid) throws SQLException 229 { 230 if ( physicalConnection != null ) 232 { 233 try 234 { 235 StringBuffer debugOnlyLog = null; 236 if ( Debug.DEBUG && known_invalid ) 237 { 238 debugOnlyLog = new StringBuffer (); 239 debugOnlyLog.append("[ exceptions: "); 240 } 241 242 Exception exc = cleanupUncachedActiveStatements(); 243 if (Debug.DEBUG && exc != null) 244 { 245 if (known_invalid) 246 debugOnlyLog.append( exc.toString() + ' ' ); 247 else 248 logger.log(MLevel.WARNING, "An exception occurred while cleaning up uncached active Statements.", exc); 249 } 251 252 try 253 { 254 if (exposedProxy != null) 263 exposedProxy.silentClose( known_invalid ); 264 } 265 catch (Exception e) 266 { 267 if (Debug.DEBUG) 268 { 269 if (known_invalid) 270 debugOnlyLog.append( e.toString() + ' ' ); 271 else 272 logger.log(MLevel.WARNING, "An exception occurred.", exc); 273 } 275 exc = e; 276 } 277 try 278 { this.closeAll(); } 279 catch (Exception e) 280 { 281 if (Debug.DEBUG) 282 { 283 if (known_invalid) 284 debugOnlyLog.append( e.toString() + ' ' ); 285 else 286 logger.log(MLevel.WARNING, "An exception occurred.", exc); 287 } 289 exc = e; 290 } 291 292 try { physicalConnection.close(); } 293 catch (Exception e) 294 { 295 if (Debug.DEBUG) 296 { 297 if (known_invalid) 298 debugOnlyLog.append( e.toString() + ' ' ); 299 else 300 logger.log(MLevel.WARNING, "An exception occurred.", exc); 301 e.printStackTrace(); 302 } 303 exc = e; 304 } 305 306 if (exc != null) 307 { 308 if (known_invalid) 309 { 310 debugOnlyLog.append(" ]"); 311 if (Debug.DEBUG) 312 { 313 317 318 logger.fine(this + ": while closing a PooledConnection known to be invalid, " + 319 " some exceptions occurred. This is probably not a problem: " + 320 debugOnlyLog.toString() ); 321 } 322 } 323 else 324 throw new SQLException("At least one error occurred while attempting " + 325 "to close() the PooledConnection: " + exc); 326 } 327 if (Debug.TRACE == Debug.TRACE_MAX) 328 logger.fine("C3P0PooledConnection closed. [" + this + ']'); 329 } 331 finally 332 { physicalConnection = null; } 333 } 334 } 335 336 public void addConnectionEventListener(ConnectionEventListener listener) 337 { ces.addConnectionEventListener( listener ); } 338 339 public void removeConnectionEventListener(ConnectionEventListener listener) 340 { ces.removeConnectionEventListener( listener ); } 341 342 private void reset() throws SQLException 343 { reset( false ); } 344 345 private void reset( boolean known_resolved_txn ) throws SQLException 346 { 347 ensureOkay(); 348 C3P0ImplUtils.resetTxnState( physicalConnection, forceIgnoreUnresolvedTransactions, autoCommitOnClose, known_resolved_txn ); 349 if (isolation_lvl_nondefault) 350 { 351 physicalConnection.setTransactionIsolation( dflt_txn_isolation ); 352 isolation_lvl_nondefault = false; 353 } 354 if (catalog_nondefault) 355 { 356 physicalConnection.setCatalog( dflt_catalog ); 357 catalog_nondefault = false; 358 } 359 if (holdability_nondefault) { 361 physicalConnection.setHoldability( dflt_holdability ); 362 holdability_nondefault = false; 363 } 364 365 try 366 { physicalConnection.setReadOnly( false ); } 367 catch ( Throwable t ) 368 { 369 if (logger.isLoggable( MLevel.FINE )) 370 logger.log(MLevel.FINE, "A Throwable occurred while trying to reset the readOnly property of our Connection to false!", t); 371 } 372 373 try 374 { if (supports_setTypeMap) physicalConnection.setTypeMap( Collections.EMPTY_MAP ); } 375 catch ( Throwable t ) 376 { 377 if (logger.isLoggable( MLevel.FINE )) 378 logger.log(MLevel.FINE, "A Throwable occurred while trying to reset the typeMap property of our Connection to Collections.EMPTY_MAP!", t); 379 } 380 } 381 382 boolean closeAndRemoveResultSets(Set rsSet) 383 { 384 boolean okay = true; 385 synchronized (rsSet) 386 { 387 for (Iterator ii = rsSet.iterator(); ii.hasNext(); ) 388 { 389 ResultSet rs = (ResultSet) ii.next(); 390 try 391 { rs.close(); } 392 catch (SQLException e) 393 { 394 if (Debug.DEBUG) 395 logger.log(MLevel.WARNING, "An exception occurred while cleaning up a ResultSet.", e); 396 okay = false; 398 } 399 finally 400 { ii.remove(); } 401 } 402 } 403 return okay; 404 } 405 406 void ensureOkay() throws SQLException 407 { 408 if (physicalConnection == null) 409 throw new SQLException( invalidatingException == null ? 410 "Connection is closed or broken." : 411 "Connection is broken. Invalidating Exception: " + invalidatingException.toString()); 412 } 413 414 boolean closeAndRemoveResourcesInSet(Set s, Method closeMethod) 415 { 416 boolean okay = true; 417 418 Set temp; 419 synchronized (s) 420 { temp = new HashSet( s ); } 421 422 for (Iterator ii = temp.iterator(); ii.hasNext(); ) 423 { 424 Object rsrc = ii.next(); 425 try 426 { closeMethod.invoke(rsrc, CLOSE_ARGS); } 427 catch (Exception e) 428 { 429 Throwable t = e; 430 if (t instanceof InvocationTargetException) 431 t = ((InvocationTargetException) e).getTargetException(); 432 logger.log(MLevel.WARNING, "An exception occurred while cleaning up a resource.", t); 433 okay = false; 435 } 436 finally 437 { s.remove( rsrc ); } 438 } 439 440 471 472 return okay; 473 } 474 475 private SQLException cleanupUncachedActiveStatements() 476 { 477 479 boolean okay = closeAndRemoveResourcesInSet(uncachedActiveStatements, STMT_CLOSE_METHOD); 480 481 483 if (okay) 484 return null; 485 else 486 return new SQLException("An exception occurred while trying to " + 487 "clean up orphaned resources."); 488 } 489 490 ProxyConnection createProxyConnection() throws Exception 491 { 492 InvocationHandler handler = new ProxyConnectionInvocationHandler(); 496 return (ProxyConnection) CON_PROXY_CTOR.newInstance( new Object [] {handler} ); 497 } 498 499 Statement createProxyStatement( Statement innerStmt ) throws Exception 500 { return this.createProxyStatement( false, innerStmt ); } 501 502 503 private static class StatementProxyingSetManagedResultSet extends SetManagedResultSet 504 { 505 private Statement proxyStatement; 506 507 StatementProxyingSetManagedResultSet(Set activeResultSets) 508 { super( activeResultSets ); } 509 510 public void setProxyStatement( Statement proxyStatement ) 511 { this.proxyStatement = proxyStatement; } 512 513 public Statement getStatement() throws SQLException 514 { return (proxyStatement == null ? super.getStatement() : proxyStatement); } 515 } 516 517 521 Statement createProxyStatement( final boolean inner_is_cached, 524 final Statement innerStmt) throws Exception 525 { 526 final Set activeResultSets = Collections.synchronizedSet( new HashSet() ); 527 final Connection parentConnection = exposedProxy; 528 529 if (Debug.DEBUG && parentConnection == null) 530 { 531 534 logger.warning("PROBABLE C3P0 BUG -- " + 535 this + ": created a proxy Statement when there is no active, exposed proxy Connection???"); 536 537 } 538 539 540 final StatementProxyingSetManagedResultSet mainResultSet = new StatementProxyingSetManagedResultSet( activeResultSets ); 544 545 class WrapperStatementHelper 546 { 547 Statement wrapperStmt; 548 Statement nakedInner; 549 550 public WrapperStatementHelper(Statement wrapperStmt, Statement nakedInner) 551 { 552 this.wrapperStmt = wrapperStmt; 553 this.nakedInner = nakedInner; 554 555 if (! inner_is_cached) 556 uncachedActiveStatements.add( wrapperStmt ); 557 } 558 559 private boolean closeAndRemoveActiveResultSets() 560 { return closeAndRemoveResultSets( activeResultSets ); } 561 562 public ResultSet wrap(ResultSet rs) 563 { 564 if (mainResultSet.getInner() == null) 565 { 566 mainResultSet.setInner(rs); 567 mainResultSet.setProxyStatement( wrapperStmt ); 568 return mainResultSet; 569 } 570 else 571 { 572 StatementProxyingSetManagedResultSet out 574 = new StatementProxyingSetManagedResultSet( activeResultSets ); 575 out.setInner( rs ); 576 out.setProxyStatement( wrapperStmt ); 577 return out; 578 } 579 } 580 581 public void doClose() 582 throws SQLException 583 { 584 boolean okay = closeAndRemoveActiveResultSets(); 585 586 if (inner_is_cached) scache.checkinStatement( innerStmt ); 588 else 589 { 590 innerStmt.close(); 591 uncachedActiveStatements.remove( wrapperStmt ); 592 } 593 594 if (!okay) 595 throw new SQLException("Failed to close an orphaned ResultSet properly."); 596 } 597 598 public Object doRawStatementOperation(Method m, Object target, Object [] args) 599 throws IllegalAccessException , InvocationTargetException, SQLException 600 { 601 if (target == C3P0ProxyStatement.RAW_STATEMENT) 602 target = nakedInner; 603 for (int i = 0, len = args.length; i < len; ++i) 604 if (args[i] == C3P0ProxyStatement.RAW_STATEMENT) 605 args[i] = nakedInner; 606 607 Object out = m.invoke(target, args); 608 609 if (out instanceof ResultSet) 610 out = wrap( (ResultSet) out ); 611 612 return out; 613 } 614 } 615 616 if (innerStmt instanceof CallableStatement) 617 { 618 class ProxyCallableStatement extends FilterCallableStatement implements C3P0ProxyStatement 619 { 620 WrapperStatementHelper wsh; 621 622 ProxyCallableStatement(CallableStatement is) 623 { 624 super( is ); 625 this.wsh = new WrapperStatementHelper(this, is); 626 } 627 628 public Connection getConnection() 629 { return parentConnection; } 630 631 public ResultSet getResultSet() throws SQLException 632 { return wsh.wrap( super.getResultSet() ); } 633 634 public ResultSet getGeneratedKeys() throws SQLException 635 { return wsh.wrap( super.getGeneratedKeys() ); } 636 637 public ResultSet executeQuery(String sql) throws SQLException 638 { return wsh.wrap( super.executeQuery(sql) ); } 639 640 public ResultSet executeQuery() throws SQLException 641 { return wsh.wrap( super.executeQuery() ); } 642 643 public Object rawStatementOperation(Method m, Object target, Object [] args) 644 throws IllegalAccessException , InvocationTargetException, SQLException 645 { return wsh.doRawStatementOperation( m, target, args); } 646 647 public void close() throws SQLException 648 { wsh.doClose(); } 649 } 650 651 return new ProxyCallableStatement((CallableStatement) innerStmt ); 652 } 653 else if (innerStmt instanceof PreparedStatement) 654 { 655 class ProxyPreparedStatement extends FilterPreparedStatement implements C3P0ProxyStatement 656 { 657 WrapperStatementHelper wsh; 658 659 ProxyPreparedStatement(PreparedStatement ps) 660 { 661 super( ps ); 662 this.wsh = new WrapperStatementHelper(this, ps); 663 } 664 665 public Connection getConnection() 666 { return parentConnection; } 667 668 public ResultSet getResultSet() throws SQLException 669 { return wsh.wrap( super.getResultSet() ); } 670 671 public ResultSet getGeneratedKeys() throws SQLException 672 { return wsh.wrap( super.getGeneratedKeys() ); } 673 674 public ResultSet executeQuery(String sql) throws SQLException 675 { return wsh.wrap( super.executeQuery(sql) ); } 676 677 public ResultSet executeQuery() throws SQLException 678 { return wsh.wrap( super.executeQuery() ); } 679 680 public Object rawStatementOperation(Method m, Object target, Object [] args) 681 throws IllegalAccessException , InvocationTargetException, SQLException 682 { return wsh.doRawStatementOperation( m, target, args); } 683 684 public void close() throws SQLException 685 { wsh.doClose(); } 686 } 687 688 return new ProxyPreparedStatement((PreparedStatement) innerStmt ); 689 } 690 else 691 { 692 class ProxyStatement extends FilterStatement implements C3P0ProxyStatement 693 { 694 WrapperStatementHelper wsh; 695 696 ProxyStatement(Statement s) 697 { 698 super( s ); 699 this.wsh = new WrapperStatementHelper(this, s); 700 } 701 702 public Connection getConnection() 703 { return parentConnection; } 704 705 public ResultSet getResultSet() throws SQLException 706 { return wsh.wrap( super.getResultSet() ); } 707 708 public ResultSet getGeneratedKeys() throws SQLException 709 { return wsh.wrap( super.getGeneratedKeys() ); } 710 711 public ResultSet executeQuery(String sql) throws SQLException 712 { return wsh.wrap( super.executeQuery(sql) ); } 713 714 public Object rawStatementOperation(Method m, Object target, Object [] args) 715 throws IllegalAccessException , InvocationTargetException, SQLException 716 { return wsh.doRawStatementOperation( m, target, args); } 717 718 public void close() throws SQLException 719 { wsh.doClose(); } 720 } 721 722 return new ProxyStatement( innerStmt ); 723 } 724 } 725 726 final class ProxyConnectionInvocationHandler implements InvocationHandler 727 { 728 Connection activeConnection = physicalConnection; 730 DatabaseMetaData metaData = null; 731 boolean connection_error_signaled = false; 732 733 739 final Set activeMetaDataResultSets = new HashSet(); 740 741 Set doRawResultSets = null; 744 745 boolean txn_known_resolved = true; 746 747 public String toString() 748 { return "C3P0ProxyConnection [Invocation Handler: " + super.toString() + ']'; } 749 750 private Object doRawConnectionOperation(Method m, Object target, Object [] args) 751 throws IllegalAccessException , InvocationTargetException, SQLException, Exception 752 { 753 if (activeConnection == null) 754 throw new SQLException("Connection previously closed. You cannot operate on a closed Connection."); 755 756 if (target == C3P0ProxyConnection.RAW_CONNECTION) 757 target = activeConnection; 758 for (int i = 0, len = args.length; i < len; ++i) 759 if (args[i] == C3P0ProxyConnection.RAW_CONNECTION) 760 args[i] = activeConnection; 761 762 Object out = m.invoke(target, args); 763 764 if (out instanceof Statement) 766 out = createProxyStatement( false, (Statement) out ); 767 else if (out instanceof ResultSet) 768 { 769 if (doRawResultSets == null) 770 doRawResultSets = new HashSet(); 771 out = new NullStatementSetManagedResultSet( (ResultSet) out, doRawResultSets ); 772 } 773 return out; 774 } 775 776 public synchronized Object invoke(Object proxy, Method m, Object [] args) 777 throws Throwable 778 { 779 if ( OBJECT_METHODS.contains( m ) ) 780 return m.invoke( this, args ); 781 782 try 783 { 784 String mname = m.getName(); 785 if (activeConnection != null) 786 { 787 if (mname.equals("rawConnectionOperation")) 788 { 789 ensureOkay(); 790 txn_known_resolved = false; 791 792 return doRawConnectionOperation((Method) args[0], args[1], (Object []) args[2]); 793 } 794 else if (mname.equals("setTransactionIsolation")) 795 { 796 ensureOkay(); 797 798 800 m.invoke( activeConnection, args ); 801 802 int lvl = ((Integer ) args[0]).intValue(); 803 isolation_lvl_nondefault = (lvl != dflt_txn_isolation); 804 805 807 return null; 808 } 809 else if (mname.equals("setCatalog")) 810 { 811 ensureOkay(); 812 813 815 m.invoke( activeConnection, args ); 816 817 String catalog = (String ) args[0]; 818 catalog_nondefault = ObjectUtils.eqOrBothNull(catalog, dflt_catalog); 819 820 return null; 821 } 822 else if (mname.equals("setHoldability")) 823 { 824 ensureOkay(); 825 826 828 m.invoke( activeConnection, args ); 830 int holdability = ((Integer ) args[0]).intValue(); 831 holdability_nondefault = (holdability != dflt_holdability); 832 833 return null; 834 } 835 else if (mname.equals("createStatement")) 836 { 837 ensureOkay(); 838 txn_known_resolved = false; 839 840 Object stmt = m.invoke( activeConnection, args ); 841 return createProxyStatement( (Statement) stmt ); 842 } 843 else if (mname.equals("prepareStatement")) 844 { 845 ensureOkay(); 846 txn_known_resolved = false; 847 848 Object pstmt; 849 if (scache == null) 850 { 851 pstmt = m.invoke( activeConnection, args ); 852 return createProxyStatement( (Statement) pstmt ); 853 } 854 else 855 { 856 pstmt = scache.checkoutStatement( physicalConnection, 857 m, 858 args ); 859 return createProxyStatement( true, 860 (Statement) pstmt ); 861 } 862 } 863 else if (mname.equals("prepareCall")) 864 { 865 ensureOkay(); 866 txn_known_resolved = false; 867 868 Object cstmt; 869 if (scache == null) 870 { 871 cstmt = m.invoke( activeConnection, args ); 872 return createProxyStatement( (Statement) cstmt ); 873 } 874 else 875 { 876 cstmt = scache.checkoutStatement( physicalConnection, m, args ); 877 return createProxyStatement( true, 878 (Statement) cstmt ); 879 } 880 } 881 else if (mname.equals("getMetaData")) 882 { 883 ensureOkay(); 884 txn_known_resolved = false; 886 DatabaseMetaData innerMd = activeConnection.getMetaData(); 887 if (metaData == null) 888 { 889 synchronized (C3P0PooledConnection.this) 891 { metaData = new SetManagedDatabaseMetaData(innerMd, activeMetaDataResultSets, exposedProxy); } 892 } 893 return metaData; 894 } 895 else if (mname.equals("silentClose")) 896 { 897 899 doSilentClose( proxy, ((Boolean ) args[0]).booleanValue(), this.txn_known_resolved ); 900 return null; 901 } 902 else if ( mname.equals("close") ) 903 { 904 906 Exception e = doSilentClose( proxy, false, this.txn_known_resolved ); 907 if (! connection_error_signaled) 908 ces.fireConnectionClosed(); 909 if (e != null) 911 { 912 throw e; 915 } 916 else 917 return null; 918 } 919 else 925 { 926 ensureOkay(); 927 928 929 937 txn_known_resolved = false; 939 940 return m.invoke( activeConnection, args ); 941 } 942 } 943 else 944 { 945 if (mname.equals("close") || 946 mname.equals("silentClose")) 947 return null; 948 else if (mname.equals("isClosed")) 949 return new Boolean (true); 950 else 951 { 952 throw new SQLException("You can't operate on " + 953 "a closed connection!!!"); 954 } 955 } 956 } 957 catch (InvocationTargetException e) 958 { 959 Throwable convertMe = e.getTargetException(); 960 SQLException sqle = handleMaybeFatalToPooledConnection( convertMe, proxy, false ); 961 sqle.fillInStackTrace(); 962 throw sqle; 963 } 964 } 965 966 private Exception doSilentClose(Object proxyConnection, boolean pooled_connection_is_dead) 967 { return doSilentClose( proxyConnection, pooled_connection_is_dead, false ); } 968 969 private Exception doSilentClose(Object proxyConnection, boolean pooled_connection_is_dead, boolean known_resolved_txn) 970 { 971 if ( activeConnection != null ) 972 { 973 synchronized ( C3P0PooledConnection.this ) { 975 if ( C3P0PooledConnection.this.exposedProxy == proxyConnection ) 976 { 977 C3P0PooledConnection.this.exposedProxy = null; 978 980 } 983 else logger.warning("(c3p0 issue) doSilentClose( ... ) called on a proxyConnection " + 985 "other than the current exposed proxy for its PooledConnection. [exposedProxy: " + 986 exposedProxy + ", proxyConnection: " + proxyConnection); 987 } 991 992 Exception out = null; 993 994 Exception exc1 = null, exc2 = null, exc3 = null, exc4 = null; 995 try 996 { 997 if (! pooled_connection_is_dead) 998 C3P0PooledConnection.this.reset(known_resolved_txn); 999 } 1000 catch (Exception e) 1001 { 1002 exc1 = e; 1003 } 1009 1010 exc2 = cleanupUncachedActiveStatements(); 1011 String errSource; 1017 if (doRawResultSets != null) 1018 { 1019 activeMetaDataResultSets.addAll( doRawResultSets ); 1020 errSource = "DataBaseMetaData or raw Connection operation"; 1021 } 1022 else 1023 errSource = "DataBaseMetaData"; 1024 1025 if (!closeAndRemoveResultSets( activeMetaDataResultSets )) 1026 exc3 = new SQLException("Failed to close some " + errSource + " Result Sets."); 1027 if (scache != null) 1033 { 1034 try 1035 { scache.checkinAll( physicalConnection ); } 1036 catch ( Exception e ) 1037 { exc4 = e; } 1038 } 1044 1045 if (exc1 != null) 1046 { 1047 handleMaybeFatalToPooledConnection( exc1, proxyConnection, true ); 1048 out = exc1; 1049 } 1050 else if (exc2 != null) 1051 { 1052 handleMaybeFatalToPooledConnection( exc2, proxyConnection, true ); 1053 out = exc2; 1054 } 1055 else if (exc3 != null) 1056 { 1057 handleMaybeFatalToPooledConnection( exc3, proxyConnection, true ); 1058 out = exc3; 1059 } 1060 else if (exc4 != null) 1061 { 1062 handleMaybeFatalToPooledConnection( exc4, proxyConnection, true ); 1063 out = exc4; 1064 } 1065 1066 1072 activeConnection = null; 1073 return out; 1074 } 1075 else 1076 return null; 1077 } 1078 1079 private SQLException handleMaybeFatalToPooledConnection( Throwable t, Object proxyConnection, boolean already_closed ) 1080 { 1081 1083 SQLException sqle = SqlUtils.toSQLException( t ); 1084 int status = connectionTester.statusOnException( physicalConnection, sqle ); 1085 updateConnectionStatus( status ); 1086 if (status != ConnectionTester.CONNECTION_IS_OKAY) 1087 { 1088 if (Debug.DEBUG) 1089 { 1090 1094 logger.log(MLevel.INFO, 1095 C3P0PooledConnection.this + " will no longer be pooled because it has been marked invalid by an Exception.", 1096 t ); 1097 } 1098 1099 invalidatingException = sqle; 1100 1101 1120 1121 if (! connection_error_signaled) 1122 { 1123 ces.fireConnectionErrorOccurred( sqle ); 1124 connection_error_signaled = true; 1125 } 1126 } 1127 return sqle; 1128 } 1129 1130 1131 } 1132 1133 interface ProxyConnection extends C3P0ProxyConnection 1134 { void silentClose( boolean known_invalid ) throws SQLException; } 1135 1136 public synchronized int getConnectionStatus() 1137 { return this.connection_status; } 1138 1139 private synchronized void updateConnectionStatus(int status) 1140 { 1141 switch ( this.connection_status ) 1142 { 1143 case ConnectionTester.DATABASE_IS_INVALID: 1144 break; 1146 case ConnectionTester.CONNECTION_IS_INVALID: 1147 if (status == ConnectionTester.DATABASE_IS_INVALID) 1148 doBadUpdate(status); 1149 break; 1150 case ConnectionTester.CONNECTION_IS_OKAY: 1151 if (status != ConnectionTester.CONNECTION_IS_OKAY) 1152 doBadUpdate(status); 1153 break; 1154 default: 1155 throw new InternalError (this + " -- Illegal Connection Status: " + this.connection_status); 1156 } 1157 } 1158 1159 private void doBadUpdate(int new_status) 1161 { 1162 this.connection_status = new_status; 1163 try { this.close( true ); } 1164 catch (SQLException e) 1165 { 1166 1169 logger.log(MLevel.WARNING, "Broken Connection Close Error. ", e); 1170 } 1171 } 1172} 1173 1174 1175 1176 1177 1178 1179 1180 | Popular Tags |