1 29 30 package com.caucho.sql; 31 32 import com.caucho.log.Log; 33 import com.caucho.sql.spy.SpyConnection; 34 import com.caucho.sql.spy.SpyXAResource; 35 import com.caucho.util.Alarm; 36 import com.caucho.util.L10N; 37 import com.caucho.util.LruCache; 38 39 import javax.resource.NotSupportedException ; 40 import javax.resource.ResourceException ; 41 import javax.resource.spi.ConnectionEvent ; 42 import javax.resource.spi.ConnectionEventListener ; 43 import javax.resource.spi.ConnectionRequestInfo ; 44 import javax.resource.spi.LocalTransaction ; 45 import javax.resource.spi.ManagedConnection ; 46 import javax.resource.spi.ManagedConnectionMetaData ; 47 import javax.security.auth.Subject ; 48 import javax.sql.PooledConnection ; 49 import javax.sql.XAConnection ; 50 import javax.transaction.xa.XAResource ; 51 import java.io.PrintWriter ; 52 import java.sql.Connection ; 53 import java.sql.PreparedStatement ; 54 import java.sql.ResultSet ; 55 import java.sql.SQLException ; 56 import java.sql.Statement ; 57 import java.util.Iterator ; 58 import java.util.Map ; 59 import java.util.logging.Level ; 60 import java.util.logging.Logger ; 61 62 69 public class ManagedConnectionImpl 70 implements ManagedConnection , javax.sql.ConnectionEventListener { 71 protected static final Logger log = Log.open(ManagedConnectionImpl.class); 72 protected static L10N L = new L10N(ManagedConnectionImpl.class); 73 74 private int _id; 76 77 private ManagedFactoryImpl _factory; 78 private DBPoolImpl _dbPool; 79 80 private DriverConfig _driver; 81 private ConnectionConfig _connConfig; 82 83 private Credential _credentials; 84 85 private PooledConnection _pooledConnection; 86 private Connection _driverConnection; 87 88 private XAResource _xaResource; 89 private LocalTransaction _localTransaction; 90 91 private ConnectionEventListener _listener; 92 private ConnectionEvent _connClosedEvent; 93 94 private ResourceException _connException; 95 96 private long _lastEventTime; 97 98 private LruCache<PreparedStatementKey,PreparedStatementCacheItem> 100 _preparedStatementCache; 101 102 private PreparedStatementKey _key; 104 105 private int _isolation = -1; 107 108 private boolean _autoCommit = true; 110 private boolean _readOnly = false; 112 private String _catalog = null; 114 private int _oldIsolation = -1; 116 private Map _typeMap; 118 119 ManagedConnectionImpl(ManagedFactoryImpl factory, 120 DriverConfig driver, 121 ConnectionConfig connConfig, 122 Credential credentials) 123 throws SQLException 124 { 125 _factory = factory; 126 _dbPool = factory.getDBPool(); 127 _id = _dbPool.newSpyId(); 128 129 _driver = driver; 130 _connConfig = connConfig; 131 _credentials = credentials; 132 133 _connClosedEvent = new ConnectionEvent (this, 134 ConnectionEvent.CONNECTION_CLOSED); 135 136 initDriverConnection(); 137 138 _lastEventTime = Alarm.getCurrentTime(); 139 140 int preparedStatementCacheSize = _dbPool.getPreparedStatementCacheSize(); 141 142 if (preparedStatementCacheSize > 0) { 143 _preparedStatementCache = new LruCache<PreparedStatementKey,PreparedStatementCacheItem>(preparedStatementCacheSize); 144 _key = new PreparedStatementKey(); 145 } 146 } 147 148 151 DBPoolImpl getDBPool() 152 { 153 return _dbPool; 154 } 155 156 159 Credential getCredentials() 160 { 161 return _credentials; 162 } 163 164 167 boolean isWrapStatements() 168 { 169 return _dbPool.isWrapStatements(); 170 } 171 172 175 public Object getConnection(Subject subject, 176 ConnectionRequestInfo info) 177 throws ResourceException 178 { 179 if (_connException != null) 180 throw _connException; 181 182 ping(); 183 _lastEventTime = Alarm.getCurrentTime(); 184 185 return new UserConnection(this); 186 } 187 188 191 public void associateConnection(Object connection) 192 throws ResourceException 193 { 194 _lastEventTime = Alarm.getCurrentTime(); 195 196 UserConnection uConn = (UserConnection) connection; 197 198 uConn.associate(this); 199 } 200 201 204 public void addConnectionEventListener(ConnectionEventListener listener) 205 { 206 if (_listener != null && _listener != listener) 207 throw new IllegalStateException (); 208 209 _listener = listener; 210 } 211 212 215 public void removeConnectionEventListener(ConnectionEventListener listener) 216 { 217 if (_listener == listener) 218 _listener = null; 219 } 220 221 224 private void initDriverConnection() 225 throws SQLException 226 { 227 if (_driverConnection != null) 228 throw new IllegalStateException (); 229 230 String user = _driver.getUser(); 231 String password = _driver.getPassword();; 232 233 if (_credentials != null) { 234 user = _credentials.getUserName(); 235 password = _credentials.getPassword(); 236 } 237 238 _pooledConnection = _driver.createPooledConnection(user, password); 239 240 if (_pooledConnection != null) { 241 _pooledConnection.addConnectionEventListener(this); 242 243 _driverConnection = _pooledConnection.getConnection(); 244 } 245 246 if (_driverConnection == null) 247 _driverConnection = _driver.createDriverConnection(user, password); 248 249 if (_driverConnection == null) 250 throw new SQLException (L.l("Failed to create driver connection.")); 251 252 DBPoolImpl dbPool = getDBPool(); 253 254 long transactionTimeout = dbPool.getTransactionTimeout(); 255 if (dbPool.isXA() && ! _connConfig.isReadOnly()) { 256 if (_pooledConnection instanceof XAConnection ) { 257 try { 258 _xaResource = ((XAConnection ) _pooledConnection).getXAResource(); 259 } catch (SQLException e) { 260 log.log(Level.FINE, e.toString(), e); 261 } 262 } 263 264 if (_xaResource != null && dbPool.isXAForbidSameRM()) 265 _xaResource = new DisjointXAResource(_xaResource); 266 267 if (transactionTimeout > 0 && _xaResource != null) { 268 try { 269 _xaResource.setTransactionTimeout((int) (transactionTimeout / 1000)); 270 } catch (Throwable e) { 271 log.log(Level.FINER, e.toString(), e); 272 } 273 } 274 275 boolean allowLocalTransaction = true; 276 String className = ""; 277 278 if (_pooledConnection != null) 279 className = _pooledConnection.getClass().getName(); 280 281 if (! (_pooledConnection instanceof XAConnection )) { 282 } 283 else if (className.startsWith("oracle")) { 284 allowLocalTransaction = false; 286 } 287 else if (className.equals("com.mysql.jdbc.jdbc2.optional.MysqlXAConnection")) { 288 allowLocalTransaction = false; 289 } 290 291 if (allowLocalTransaction) 292 _localTransaction = new LocalTransactionImpl(); 293 } 294 295 if (dbPool.isSpy()) { 296 _driverConnection = new SpyConnection(_driverConnection, _id); 297 298 if (_xaResource != null) 299 _xaResource = new SpyXAResource(_id, _xaResource); 300 } 301 302 int isolation = _connConfig.getTransactionIsolation(); 303 if (isolation >= 0) 304 _driverConnection.setTransactionIsolation(isolation); 305 306 if (_connConfig.isReadOnly()) 307 _driverConnection.setReadOnly(true); 308 309 if (_connConfig.getCatalog() != null) 310 _driverConnection.setCatalog(_connConfig.getCatalog()); 311 } 312 313 316 Connection getDriverConnection() 317 { 318 return _driverConnection; 319 } 320 321 324 public XAResource getXAResource() 325 throws ResourceException 326 { 327 if (_xaResource != null) 328 return _xaResource; 329 330 throw new NotSupportedException (); 331 } 332 333 336 public LocalTransaction getLocalTransaction() 337 throws ResourceException 338 { 339 return _localTransaction; 340 } 341 342 345 public ManagedConnectionMetaData getMetaData() 346 throws ResourceException 347 { 348 throw new NotSupportedException (); 349 } 350 351 354 public void setLogWriter(PrintWriter out) 355 throws ResourceException 356 { 357 } 358 359 362 public PrintWriter getLogWriter() 363 throws ResourceException 364 { 365 return null; 366 } 367 368 371 public void setIsolation(int isolation) 372 throws SQLException 373 { 374 } 375 376 379 PreparedStatement prepareStatement(UserConnection uConn, 380 String sql, 381 int resultType) 382 throws SQLException 383 { 384 Connection conn = getDriverConnection(); 385 386 if (conn == null) 387 throw new IllegalStateException (L.l("can't prepare statement from closed connection")); 388 389 if (resultType > 0) 390 return conn.prepareStatement(sql, resultType); 391 else 392 return conn.prepareStatement(sql); 393 } 394 395 398 PreparedStatement prepareStatement(UserConnection uConn, String sql) 399 throws SQLException 400 { 401 PreparedStatementKey key = _key; 402 403 Connection conn = getDriverConnection(); 404 405 if (conn == null) 406 throw new IllegalStateException (L.l("can't prepare statement from closed connection")); 407 408 if (key == null) { 409 return conn.prepareStatement(sql); 410 } 411 412 boolean hasItem = false; 413 414 synchronized (key) { 415 key.init(sql); 416 417 PreparedStatementCacheItem item = _preparedStatementCache.get(key); 418 419 if (item != null) { 420 UserPreparedStatement upStmt = item.toActive(uConn); 421 422 if (upStmt != null) 423 return upStmt; 424 425 hasItem = ! item.isRemoved(); 426 } 427 } 428 429 PreparedStatement pStmt; 430 pStmt = conn.prepareStatement(sql); 431 432 if (hasItem) 433 return pStmt; 434 435 key = new PreparedStatementKey(sql); 436 437 PreparedStatementCacheItem item; 438 item = new PreparedStatementCacheItem(key, pStmt, this); 439 440 UserPreparedStatement upStmt = item.toActive(uConn); 441 442 if (upStmt == null) 443 throw new IllegalStateException ("preparedStatement can't activate"); 444 445 _preparedStatementCache.put(key, item); 446 447 return upStmt; 448 } 449 450 453 void remove(PreparedStatementKey key) 454 { 455 _preparedStatementCache.remove(key); 456 } 457 458 public void connectionClosed(javax.sql.ConnectionEvent event) 459 { 460 sendFatalEvent(new SQLException (L.l("unexpected close event from pool"))); 461 closeEvent(null); 462 } 463 464 public void connectionErrorOccurred(javax.sql.ConnectionEvent event) 465 { 466 sendFatalEvent(event.getSQLException()); 467 } 468 469 472 public void closeEvent(UserConnection userConn) 473 { 474 if (_listener != null) { 475 if (_connException != null) { 476 sendFatalEvent(_connException); 477 } 478 479 ConnectionEvent evt; 480 synchronized (this) { 481 evt = _connClosedEvent; 482 _connClosedEvent = null; 483 } 484 485 if (evt == null) 486 evt = new ConnectionEvent (this, ConnectionEvent.CONNECTION_CLOSED); 487 488 evt.setConnectionHandle(userConn); 489 490 _listener.connectionClosed(evt); 491 492 evt.setConnectionHandle(null); 493 494 _connClosedEvent = evt; 495 496 _lastEventTime = Alarm.getCurrentTime(); 497 } 498 } 499 500 503 public void fatalEvent() 504 { 505 fatalEvent(new ResourceException ("fatal event")); 506 } 507 508 511 public void fatalEvent(Exception e) 512 { 513 if (_pooledConnection != null) { 514 } 515 else if (e instanceof ResourceException ) 516 _connException = (ResourceException ) e; 517 else 518 _connException = new ResourceException (e); 519 } 520 521 524 public void sendFatalEvent(Exception e) 525 { 526 if (_listener != null) { 527 ConnectionEvent event; 528 529 event = new ConnectionEvent (this, 530 ConnectionEvent.CONNECTION_ERROR_OCCURRED, 531 e); 532 533 _listener.connectionErrorOccurred(event); 534 } 535 } 536 537 540 public void setAutoCommit(boolean autoCommit) 541 throws SQLException 542 { 543 try { 544 _autoCommit = autoCommit; 545 _driverConnection.setAutoCommit(autoCommit); 546 } catch (SQLException e) { 547 fatalEvent(); 548 throw e; 549 } 550 } 551 552 555 public void setReadOnly(boolean readOnly) 556 throws SQLException 557 { 558 try { 559 _readOnly = readOnly; 560 _driverConnection.setReadOnly(readOnly); 561 } catch (SQLException e) { 562 fatalEvent(); 563 throw e; 564 } 565 } 566 567 570 public void setCatalog(String catalog) 571 throws SQLException 572 { 573 try { 574 if (_catalog == null) 575 _catalog = _driverConnection.getCatalog(); 576 577 _driverConnection.setCatalog(catalog); 578 } catch (SQLException e) { 579 fatalEvent(); 580 throw e; 581 } 582 } 583 584 587 public void setTypeMap(Map map) 588 throws SQLException 589 { 590 try { 591 if (_typeMap == null) 592 _typeMap = _driverConnection.getTypeMap(); 593 594 _driverConnection.setTypeMap(map); 595 } catch (SQLException e) { 596 throw e; 597 } 598 } 599 600 601 604 public void setTransactionIsolation(int isolation) 605 throws SQLException 606 { 607 try { 608 _oldIsolation = _driverConnection.getTransactionIsolation(); 609 _isolation = isolation; 610 611 _driverConnection.setTransactionIsolation(isolation); 612 } catch (SQLException e) { 613 throw e; 614 } 615 } 616 617 620 public void cleanup() 621 throws ResourceException 622 { 623 Connection conn = _driverConnection; 624 625 if (conn == null) 626 return; 627 628 try { 629 638 639 if (_readOnly) 640 conn.setReadOnly(false); 641 _readOnly = false; 642 643 if (_catalog != null && ! _catalog.equals("")) 644 conn.setCatalog(_catalog); 645 _catalog = null; 646 647 if (_typeMap != null) 648 conn.setTypeMap(_typeMap); 649 _typeMap = null; 650 651 boolean needsRollback = ! _autoCommit; 655 if (_isolation != _oldIsolation) { 656 needsRollback = true; 657 conn.setTransactionIsolation(_oldIsolation); 658 } 659 _isolation = _oldIsolation; 660 661 if (needsRollback) 662 conn.rollback(); 663 664 if (! _autoCommit) { 665 conn.setAutoCommit(true); 666 } 667 _autoCommit = true; 668 669 conn.clearWarnings(); 670 } catch (SQLException e) { 671 throw new ResourceException (e); 672 } 673 } 674 675 678 boolean isValid() 679 { 680 try { 681 ping(); 682 683 return true; 684 } catch (Throwable e) { 685 log.log(Level.FINE, e.toString(), e); 686 687 return false; 688 } 689 } 690 691 694 private void ping() 695 throws ResourceException 696 { 697 DBPoolImpl dbPool = _factory.getDBPool(); 698 699 long now = Alarm.getCurrentTime(); 700 701 if (now < _lastEventTime + 1000) 702 return; 703 704 if (! dbPool.isPing()) 705 return; 706 707 long pingInterval = dbPool.getPingInterval(); 708 if (pingInterval > 0 && now < _lastEventTime + pingInterval) 709 return; 710 711 String pingQuery = dbPool.getPingQuery(); 712 713 if (pingQuery == null) 714 return; 715 716 if (_driverConnection == null) 717 return; 718 719 try { 720 Statement stmt = _driverConnection.createStatement(); 721 722 try { 723 ResultSet rs = stmt.executeQuery(pingQuery); 724 rs.close(); 725 } finally { 726 stmt.close(); 727 } 728 } catch (SQLException e) { 729 throw new ResourceException (e); 730 } 731 } 732 733 736 public void destroy() 737 throws ResourceException 738 { 739 log.finer("destroy " + this); 740 741 PooledConnection poolConn = _pooledConnection; 742 _pooledConnection = null; 743 744 Connection driverConn = _driverConnection; 745 _driverConnection = null; 746 747 if (_preparedStatementCache != null) { 748 Iterator <PreparedStatementCacheItem> iter; 749 750 iter = _preparedStatementCache.values(); 751 752 while (iter.hasNext()) { 753 PreparedStatementCacheItem item = iter.next(); 754 755 item.destroy(); 756 } 757 } 758 759 try { 760 if (poolConn != null) { 761 poolConn.close(); 762 driverConn = null; 763 } 764 } catch (SQLException e) { 765 throw new ResourceException (e); 766 } 767 768 try { 769 if (driverConn != null) 770 driverConn.close(); 771 } catch (SQLException e) { 772 log.log(Level.WARNING, e.toString(), e); 773 } 774 } 775 776 class LocalTransactionImpl implements LocalTransaction { 777 private boolean _oldAutoCommit; 778 779 public void begin() 780 throws ResourceException 781 { 782 try { 783 _oldAutoCommit = _autoCommit; 784 785 setAutoCommit(false); 786 } catch (SQLException e) { 787 throw new ResourceException (e) ; 788 } 789 } 790 791 public void commit() 792 throws ResourceException 793 { 794 Connection conn = _driverConnection; 795 796 if (conn == null) 797 throw new ResourceException (L.l("connection is closed")); 798 799 try { 800 conn.commit(); 801 } catch (SQLException e) { 802 throw new ResourceException (e) ; 803 } 804 805 try { 806 setAutoCommit(_oldAutoCommit); 807 } catch (SQLException e) { 808 throw new ResourceException (e) ; 809 } 810 } 811 812 public void rollback() 813 throws ResourceException 814 { 815 Connection conn = _driverConnection; 816 817 if (conn == null) 818 throw new ResourceException (L.l("connection is closed")); 819 820 try { 821 conn.rollback(); 822 } catch (SQLException e) { 823 throw new ResourceException (e) ; 824 } 825 826 try { 827 setAutoCommit(_oldAutoCommit); 828 } catch (SQLException e) { 829 throw new ResourceException (e) ; 830 } 831 } 832 } 833 } 834 | Popular Tags |