1 25 26 package org.objectweb.easybeans.component.jdbcpool; 27 28 import java.sql.Connection ; 29 import java.sql.PreparedStatement ; 30 import java.sql.ResultSet ; 31 import java.sql.SQLException ; 32 import java.util.Collections ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.Vector ; 37 38 import javax.sql.ConnectionEvent ; 39 import javax.sql.ConnectionEventListener ; 40 import javax.sql.XAConnection ; 41 import javax.transaction.Synchronization ; 42 import javax.transaction.Transaction ; 43 import javax.transaction.xa.XAException ; 44 import javax.transaction.xa.XAResource ; 45 import javax.transaction.xa.Xid ; 46 47 import org.objectweb.easybeans.log.JLog; 48 import org.objectweb.easybeans.log.JLogFactory; 49 50 56 public class JManagedConnection implements Comparable , XAConnection , XAResource , Synchronization { 57 58 61 private static JLog logger = JLogFactory.getLog(JManagedConnection.class); 62 63 66 private Connection physicalConnection = null; 67 68 71 private Connection implConn = null; 72 73 76 private int pstmtmax = 0; 77 78 81 private int psOpenNb = 0; 82 83 86 private Vector <ConnectionEventListener > eventListeners = new Vector <ConnectionEventListener >(); 87 88 91 private int open = 0; 92 93 96 private int timeout = 0; 97 98 101 private Transaction tx = null; 102 103 106 private static int objcount = 0; 107 108 111 private final int identifier; 112 113 116 private int reUsedPreparedStatements = 0; 117 118 121 private Map <String , JStatement> psList = null; 122 123 126 private ConnectionManager ds = null; 127 128 131 private long deathTime = 0; 132 133 136 private long closeTime = 0; 137 138 139 144 public JManagedConnection(final Connection physicalConnection, final ConnectionManager ds) { 145 this.physicalConnection = physicalConnection; 146 this.ds = ds; 147 148 this.implConn = new JConnection(this, physicalConnection); 150 151 open = 0; 152 deathTime = System.currentTimeMillis() + ds.getMaxAgeMilli(); 153 154 identifier = objcount++; 155 156 pstmtmax = ds.getPstmtMax(); 158 psOpenNb = 0; 159 psList = Collections.synchronizedMap(new HashMap <String , JStatement>()); 160 161 } 162 163 166 public int getIdentifier() { 167 return identifier; 168 } 169 170 174 public void setPstmtMax(final int max) { 175 pstmtmax = max; 176 if (psList == null) { 177 psList = Collections.synchronizedMap(new HashMap <String , JStatement>(pstmtmax)); 178 } 179 } 180 181 187 public void commit(final Xid xid, final boolean onePhase) throws XAException { 188 logger.debug("XA-COMMIT for {0}", xid); 189 190 try { 192 physicalConnection.commit(); 193 } catch (SQLException e) { 194 logger.error("Cannot commit transaction", e); 195 notifyError(e); 196 throw new XAException ("Error on commit"); 197 } 198 } 199 200 206 public void end(final Xid xid, final int flags) throws XAException { 207 logger.debug("XA-END for {0}", xid); 208 } 209 210 216 public void forget(final Xid xid) throws XAException { 217 logger.debug("XA-FORGET for {0}", xid); 218 } 219 220 226 public int getTransactionTimeout() throws XAException { 227 logger.debug("getTransactionTimeout for {0}", this); 228 return timeout; 229 } 230 231 239 public boolean isSameRM(final XAResource xares) throws XAException { 240 241 if (xares.equals(this)) { 247 logger.debug("isSameRM = true {0}", this); 248 return true; 249 } 250 logger.debug("isSameRM = false {0}", this); 251 return false; 252 } 253 254 261 public int prepare(final Xid xid) throws XAException { 262 logger.debug("XA-PREPARE for {0}", xid); 263 return XA_OK; 265 } 266 267 273 public Xid [] recover(final int flag) throws XAException { 274 logger.debug("XA-RECOVER for {0}", this); 275 return null; 277 } 278 279 285 public void rollback(final Xid xid) throws XAException { 286 logger.debug("XA-ROLLBACK for {0}", xid); 287 288 try { 290 if (physicalConnection.getAutoCommit()) { 291 logger.error("Rollback called on XAResource with AutoCommit set"); 292 throw (new XAException (XAException.XA_HEURCOM)); 293 } 294 } catch (SQLException e) { 295 logger.error("Cannot getAutoCommit", e); 296 notifyError(e); 297 throw (new XAException ("Error on getAutoCommit")); 298 } 299 300 try { 302 physicalConnection.rollback(); 303 } catch (SQLException e) { 304 logger.error("Cannot rollback transaction", e); 305 notifyError(e); 306 throw (new XAException ("Error on rollback")); 307 } 308 } 309 310 316 @SuppressWarnings ("boxing") 317 public boolean setTransactionTimeout(final int seconds) throws XAException { 318 logger.debug("setTransactionTimeout to {0} for {1}", seconds, this); 319 timeout = seconds; 320 return true; 321 } 322 323 329 public void start(final Xid xid, final int flags) throws XAException { 330 logger.debug("XA-START for {0}", xid); 331 } 332 333 338 public XAResource getXAResource() throws SQLException { 339 return this; 340 } 341 342 347 public int compareTo(final Object o) { 348 JManagedConnection other = (JManagedConnection) o; 349 int diff = getReUsedPreparedStatements() - other.getReUsedPreparedStatements(); 350 if (diff == 0) { 351 return getIdentifier() - other.getIdentifier(); 352 } 353 return diff; 354 } 355 356 359 public int getReUsedPreparedStatements() { 360 return reUsedPreparedStatements; 361 } 362 363 368 public Connection getConnection() throws SQLException { 369 return implConn; 371 } 372 373 377 public void close() throws SQLException { 378 379 if (physicalConnection != null) { 381 physicalConnection.close(); 382 } else { 383 logger.error("Connection already closed. Stack of this new close()", new Exception ()); 384 } 385 physicalConnection = null; 386 implConn = null; 387 } 388 389 393 public void addConnectionEventListener(final ConnectionEventListener listener) { 394 eventListeners.addElement(listener); 395 } 396 397 401 public void removeConnectionEventListener(final ConnectionEventListener listener) { 402 eventListeners.removeElement(listener); 403 } 404 405 406 407 410 public void beforeCompletion() { 411 } 413 414 417 public void afterCompletion(final int status) { 418 if (tx != null) { 419 ds.freeConnections(tx); 420 } else { 421 logger.error("NO TX!"); 422 } 423 } 424 425 428 public boolean isAged() { 429 return (deathTime < System.currentTimeMillis()); 430 } 431 432 435 public boolean isOpen() { 436 return (open > 0); 437 } 438 439 442 public int getOpenCount() { 443 return open; 444 } 445 446 451 public boolean inactive() { 452 return (open > 0 && tx == null && closeTime < System.currentTimeMillis()); 453 } 454 455 458 public boolean isClosed() { 459 return (open <= 0); 460 } 461 462 465 public void hold() { 466 open++; 467 closeTime = System.currentTimeMillis() + ds.getMaxOpenTimeMilli(); 468 } 469 470 474 public boolean release() { 475 open--; 476 if (open < 0) { 477 logger.warn("connection was already closed"); 478 open = 0; 479 return false; 480 } 481 if (tx == null && open > 0) { 482 logger.error("connection-open counter overflow"); 483 open = 0; 484 } 485 return true; 486 } 487 488 492 public void setTx(final Transaction tx) { 493 this.tx = tx; 494 } 495 496 499 public Transaction getTx() { 500 return tx; 501 } 502 503 506 public void remove() { 507 try { 509 close(); 510 } catch (java.sql.SQLException ign) { 511 logger.error("Could not close Connection: ", ign); 512 } 513 514 tx = null; 516 517 } 518 519 523 531 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) 532 throws SQLException { 533 534 logger.debug("sql = {0}", sql); 535 if (pstmtmax == 0) { 536 return physicalConnection.prepareStatement(sql, resultSetType, resultSetConcurrency); 537 } 538 JStatement ps = null; 539 synchronized (psList) { 540 ps = psList.get(sql); 541 if (ps != null) { 542 if (!ps.isClosed()) { 543 logger.warn("reuse an open pstmt"); 544 } 545 ps.reuse(); 546 reUsedPreparedStatements++; 547 } else { 548 PreparedStatement aps = physicalConnection.prepareStatement(sql, resultSetType, resultSetConcurrency); 550 ps = new JStatement(aps, this, sql); 551 psList.put(sql, ps); 552 } 553 psOpenNb++; 554 } 555 return ps; 556 } 557 558 564 public PreparedStatement prepareStatement(final String sql) throws SQLException { 565 return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 566 } 567 568 572 public void notifyPsClose(final JStatement ps) { 573 logger.debug(ps.getSql()); 574 synchronized (psList) { 575 psOpenNb--; 576 if (psList.size() >= pstmtmax) { 577 JStatement lru = null; 579 Iterator i = psList.values().iterator(); 580 while (i.hasNext()) { 581 lru = (JStatement) i.next(); 582 if (lru.isClosed()) { 583 i.remove(); 585 lru.forget(); 586 break; 587 } 588 } 589 } 590 } 591 } 592 593 596 @SuppressWarnings ("boxing") 597 public void notifyClose() { 598 599 synchronized (psList) { 603 if (psOpenNb > 0) { 604 JStatement jst = null; 605 Iterator i = psList.values().iterator(); 606 while (i.hasNext()) { 607 jst = (JStatement) i.next(); 608 if (jst.forceClose()) { 609 psOpenNb--; 610 } 611 } 612 if (psOpenNb != 0) { 613 logger.warn("Bad psOpenNb value = {0}", psOpenNb); 614 psOpenNb = 0; 615 } 616 } 617 } 618 619 for (int i = 0; i < eventListeners.size(); i++) { 621 ConnectionEventListener l = eventListeners.elementAt(i); 622 l.connectionClosed(new ConnectionEvent (this)); 623 } 624 } 625 626 630 public void notifyError(final SQLException ex) { 631 for (int i = 0; i < eventListeners.size(); i++) { 633 ConnectionEventListener l = eventListeners.elementAt(i); 634 l.connectionErrorOccurred(new ConnectionEvent (this, ex)); 635 } 636 } 637 638 } 639 | Popular Tags |