1 22 package org.enhydra.jdbc.standard; 23 24 import java.sql.Connection ; 25 import java.sql.SQLException ; 26 import javax.sql.XAConnection ; 27 import javax.transaction.xa.XAException ; 28 import javax.transaction.xa.XAResource ; 29 import javax.transaction.xa.Xid ; 30 import javax.naming.NamingException ; 31 import javax.naming.Reference ; 32 import javax.naming.Referenceable ; 33 import javax.naming.StringRefAddr ; 34 import javax.transaction.Status ; 35 import javax.transaction.TransactionManager ; 36 37 55 public class StandardXAConnection 56 extends StandardPooledConnection 57 implements XAConnection , XAResource , Referenceable , Runnable { 58 59 protected StandardXAStatefulConnection curCon; 60 private boolean commitOnPrepare; 62 boolean isClosed; private int timeoutSecs; private long timeoutPeriod = 60000; private long nextTimeout; public Thread timerThread; public TransactionManager transactionManager; 69 public StandardXAConnectionHandle connectionHandle; 70 protected StandardXADataSource xaDataSource; 71 public boolean thisAutoCommit = true; 72 73 76 public StandardXAConnection( 77 StandardXADataSource dataSource, 78 String user, 79 String password) 80 throws SQLException { 81 super(dataSource, user, password); 82 84 this.xaDataSource = dataSource; 86 curCon = new StandardXAStatefulConnection(dataSource, con); 87 89 93 107 dataSource.log.debug("StandardXAConnection created"); 108 } 109 110 115 public XAResource getXAResource() { 116 return this; 117 } 118 119 129 public synchronized Connection getConnection() throws SQLException { 130 dataSource.log.debug("StandardXAConnection:getConnection"); 131 if (connectionHandle != null) { 132 if (!connectionHandle.isClosed()) connectionHandle.close(); } 136 if (curCon == null) { 138 curCon = xaDataSource.getFreeConnection(); 139 con = curCon.con; } 142 143 146 this.newConnectionHandle(); 147 dataSource.log.debug( 148 "StandardXAConnection:getConnection return a connection"); 149 return connectionHandle; 150 } 151 152 protected void newConnectionHandle() { 153 connectionHandle = 154 new StandardXAConnectionHandle( 155 this, 156 dataSource.getMasterPrepStmtCache(), 157 dataSource.getPreparedStmtCacheSize(), 158 transactionManager); 159 } 160 161 public void setTransactionManager(TransactionManager tm) { 162 this.transactionManager = tm; 163 } 164 165 168 public synchronized void close() throws java.sql.SQLException { 169 dataSource.log.debug("StandardXAConnection:close the XAConnection"); 170 if (curCon != null && !curCon.con.isClosed()) 180 { curCon.con.close(); dataSource.getMasterPrepStmtCache().remove(curCon.toString()); 183 } 184 else { if (xaDataSource.freeConnections.size() > 1) { 186 curCon = xaDataSource.getFreeConnection(); 189 curCon.con.close(); dataSource.getMasterPrepStmtCache().remove( 192 curCon.con.toString()); 193 } 194 } 195 curCon = null; con = null; xaDataSource.connectionClosed(); 198 200 isClosed = true; connectionHandle = null; 202 nextTimeout = 0; } 208 209 214 public synchronized void doStart(Xid xid, int flags) throws XAException { 215 dataSource.log.debug( 216 "StandardXAConnection:doStart xid='" 217 + xid 218 + "' flags='" 219 + flags 220 + "'"); 221 if (xid == null) 222 throw new XAException (XAException.XAER_INVAL); 223 224 235 236 243 244 if (flags == TMRESUME 245 || flags == TMJOIN) { 246 try { 248 xaDataSource.processToWait(); 249 } catch (Exception e) { 250 throw new XAException ("Exception : " + e.toString()); 251 } 252 synchronized (xaDataSource) { 253 if(curCon != null) 254 { 255 if(!xaDataSource.freeConnections.contains(curCon)) 259 { 260 xaDataSource.freeConnections.addElement(curCon); 261 } 262 } 263 } 265 curCon = xaDataSource.getConnection(xid, true); 266 con = curCon.con; } 274 if (curCon == null) { 277 try { 278 curCon = xaDataSource.getFreeConnection(); 279 con = curCon.con; 280 } catch (Exception e) { 281 dataSource.log.error("error while gettting connection "+e,e); 282 } 283 dataSource.log.debug("StandardXAConnection:doStart curCon is null"); 284 } 286 287 288 StandardXAConnectionHandle xad = connectionHandle; 292 try { 293 xad.setGlobalTransaction(true); 294 if(flags == TMRESUME && xad.resetTxonResume) 295 { 296 xad.resetTxonResume = false; 297 if(transactionManager != null && xad.tx == null) 298 { 299 try 300 { 301 connectionHandle.tx =transactionManager.getTransaction(); 302 } 303 catch(javax.transaction.SystemException se) 304 { 305 throw new XAException (se.toString()); 306 } 307 } 308 } 309 310 } catch (SQLException e) { 312 throw new XAException (e.toString()); 313 } 314 315 if (timeoutSecs != 0) { curCon.timeout = System.currentTimeMillis() +timeoutSecs * 1000; 318 if (nextTimeout == 0) { 319 nextTimeout = curCon.timeout; notify(); 322 } else { if (curCon.timeout < nextTimeout) { 325 nextTimeout = curCon.timeout; } 328 } 329 } 330 331 curCon.xid = xid; curCon.timedOut = false; curCon.commitOnPrepare = commitOnPrepare; 334 if (!xaDataSource.xidConnections.containsKey(xid)) { 336 try { 337 log.debug("StandardXAConnection:dostart before processToWait"); 338 xaDataSource.processToWait(); 339 log.debug("StandardXAConnection:dostart after processToWait"); 340 } catch (Exception e) { 341 throw new XAException ("Exception : " + e.toString()); 342 } 343 synchronized (xaDataSource) { 344 xaDataSource.xidConnections.put(xid, curCon); 345 } 347 } 348 curCon.setState(Status.STATUS_ACTIVE); } 350 351 358 public synchronized void start(Xid xid, int flags) throws XAException { 359 dataSource.log.debug( 360 "StandardXAConnection:start associate the current connection with a global transaction"); 361 doStart(xid, flags); curCon = null; } 365 366 376 public synchronized void end(Xid xid, int flags) 377 throws XAException { dataSource.log.debug("StandardXAConnection:end"); 379 dataSource.log.debug( 380 "StandardXAConnection:end xid='" + xid + "' flags='" + flags + "'"); 381 382 if (xid == null) 383 throw new XAException (XAException.XAER_INVAL); 384 StandardXAStatefulConnection statecon = 385 xaDataSource.getConnection(xid, true); 386 int state = statecon.getState(); if (state != Status.STATUS_ACTIVE) throw new XAException (XAException.XAER_PROTO); 390 398 400 if(connectionHandle.tx != null) 404 { 405 connectionHandle.resetTxonResume =true; 406 } 407 connectionHandle.tx = null; 408 connectionHandle.globalTransaction = false; 409 410 415 } 416 417 422 public StandardXAStatefulConnection checkPreparedState(Xid xid) 423 throws XAException { 424 dataSource.log.debug("StandardXAConnection:checkPreparedState"); 425 if (xid == null) 426 throw new XAException (XAException.XAER_INVAL); 427 StandardXAStatefulConnection statecon = 428 xaDataSource.getConnection(xid, true); 429 431 try { 432 if (statecon.commitOnPrepare) { statecon.con.commit(); statecon.setState(Status.STATUS_PREPARING); 435 } else { 437 statecon.setState(Status.STATUS_PREPARED); } 439 } catch (SQLException e) { 440 dataSource.log.error( 441 "StandardXAConnection:checkPrepareState Exception on prepare, rolling back"); 442 statecon.setState(Status.STATUS_NO_TRANSACTION); 443 throw new XAException (XAException.XA_RBROLLBACK); 445 } 447 448 return statecon; 449 } 450 451 455 public int prepare(Xid xid) throws XAException { 456 dataSource.log.debug( 457 "StandardXAConnection:prepare prepare to perform a commit"); 458 checkPreparedState(xid); 459 return XA_OK; 460 } 461 462 466 public synchronized void commit(Xid xid, boolean onePhase) 467 throws XAException { 468 dataSource.log.debug("StandardXAConnection:commit perform a commit"); 469 if (xid == null) 470 throw new XAException (XAException.XAER_INVAL); 471 472 StandardXAStatefulConnection statecon = 473 xaDataSource.getConnection(xid, true); 474 dataSource.log.debug("StandardXAConnection:commit case(state)"); 476 477 try { 478 switch (statecon.getState()) { case Status.STATUS_PREPARING : break; case Status.STATUS_PREPARED : try { 483 dataSource.log.debug( 484 "StandardXAConnection:commit try to commit a connection (STATUS_PREPARED)"); 485 statecon.con.commit(); 486 dataSource.log.debug( 488 "StandardXAConnection:commit commit is ok"); 489 } catch (SQLException e) { 490 throw new XAException (XAException.XA_RBROLLBACK); 491 } 493 break; 494 case Status.STATUS_COMMITTED : case Status.STATUS_ACTIVE : 496 if (!onePhase) { throw new XAException (XAException.XAER_PROTO); 498 } 499 500 try { 501 dataSource.log.debug( 502 "StandardXAConnection:commit try to commit a connection (STATUS_ACTIVE)"); 503 statecon.con.commit(); 504 dataSource.log.debug( 506 "StandardXAConnection:commit commit is ok"); 507 } catch (SQLException e) { 508 throw new XAException (XAException.XA_RBROLLBACK); 509 } 511 break; 512 default : 513 { 514 dataSource.log.debug( 515 "StandardXAConnection:commit UNKNOWN STATUS!:" 516 + statecon.getState()); 517 throw new XAException (XAException.XAER_PROTO); 518 } 519 } 520 } catch (XAException e) { 521 throw e; 522 } finally { 523 try { 524 dataSource.log.debug( 525 "StandardXAConnection:commit setAutoCommit to '" 526 + thisAutoCommit 527 + "'"); 528 statecon.con.setAutoCommit(thisAutoCommit); 529 } catch (SQLException e) { 530 dataSource.log.debug( 531 "StandardXAConnection:commit setAutoCommit problem"); 532 } 533 534 xaDataSource.freeConnection(xid, false); 535 } 536 } 537 538 542 public synchronized void rollback(Xid xid) throws XAException { 543 dataSource.log.debug("StandardXAConnection:rollback"); 544 if (xid == null) 545 throw new XAException (XAException.XAER_INVAL); 546 547 StandardXAStatefulConnection statecon = 548 xaDataSource.getConnection(xid, true); 549 551 try { 552 switch (statecon.getState()) { case Status.STATUS_PREPARING : throw new XAException (XAException.XA_HEURCOM); 555 case Status.STATUS_PREPARED : case Status.STATUS_ROLLING_BACK : 557 case Status.STATUS_ACTIVE : 558 try { 559 dataSource.log.debug( 560 "StandardXAConnection:rollback try to perform the rollback operation"); 561 statecon.con.rollback(); 562 dataSource.log.debug( 564 "StandardXAConnection:rollback performed the rollback"); 565 } catch (SQLException e) { 566 throw new XAException (XAException.XA_RBROLLBACK); 567 } 569 break; 570 default : 571 throw new XAException (XAException.XAER_PROTO); 572 } 573 } catch (XAException e) { 574 throw e; 575 } finally { 576 try { 577 dataSource.log.debug( 578 "StandardXAConnection:rollback setAutoCommit to '" 579 + thisAutoCommit 580 + "'"); 581 statecon.con.setAutoCommit(thisAutoCommit); 582 } catch (SQLException e) { 583 dataSource.log.debug( 584 "StandardXAConnection:rollback setAutoCommit problem"); 585 } 586 xaDataSource.freeConnection(xid, false); 587 } 588 } 589 590 public boolean isSameRM(XAResource xares) throws XAException { 591 dataSource.log.debug("StandardXAConnection:isSameRM"); 592 if (equals(xares)) { dataSource.log.debug("StandardXAConnection:isSameRM isSameRM"); 594 return true; } 596 if (!(xares instanceof StandardXAConnection)) { 597 dataSource.log.debug("StandardXAConnection:isSameRM not isSameRM"); 599 return false; } 601 StandardXAConnection xac = (StandardXAConnection) xares; 602 if (dataSource.equals(xac.dataSource)) { 604 dataSource.log.debug( 606 "StandardXAConnection:isSameRM isSameRM (equal datasource)"); 607 return true; } else { 609 dataSource.log.debug( 610 "StandardXAConnection:isSameRM not isSameRM (not equal datasource)"); 611 return false; 612 } 613 } 614 615 620 public void forget(Xid xid) throws XAException { 621 dataSource.log.debug("StandardXAConnection:forget forget with Xid"); 622 if (xid == null) 623 throw new XAException (XAException.XAER_INVAL); 624 625 xaDataSource.freeConnection(xid, false); 627 } 629 630 636 public Xid [] recover(int flag) throws XAException { 637 dataSource.log.debug( 638 "StandardXAConnection:recover recover flag=" + flag); 639 if (flag != TMSTARTRSCAN && flag != TMENDRSCAN && flag != TMNOFLAGS) { 640 throw new XAException (XAException.XAER_INVAL); 641 } 642 643 Xid [] retval = null; 644 retval = xaDataSource.recover(); return retval; 646 } 647 648 651 public boolean setTransactionTimeout(int seconds) { 652 timeoutSecs = seconds; 653 return false; 654 } 655 656 public int getTransactionTimeout() { 657 return timeoutSecs; 658 } 659 660 public void setCommitOnPrepare(boolean commitOnPrepare) { 661 this.commitOnPrepare = commitOnPrepare; 662 } 663 664 public boolean getCommitOnPrepare() { 665 return commitOnPrepare; 666 } 667 668 671 public void run() { 672 while (true) { 680 try { 681 synchronized (this) { 682 while (nextTimeout == 0) { 683 wait(); 684 } 685 } 686 } catch (InterruptedException e) { 687 } 688 689 if (isClosed) { 690 return; 691 } 692 693 try { 694 Thread.sleep(timeoutPeriod); if (isClosed) 696 return; } catch (InterruptedException e) { 698 e.printStackTrace(); } 700 701 long curTime = System.currentTimeMillis(); if (curTime < nextTimeout) 703 continue; 705 try { 707 nextTimeout = xaDataSource.checkTimeouts(curTime); 708 } catch (Exception e) { 710 e.printStackTrace(); } 712 } 713 } 714 715 public Reference getReference() throws NamingException { 716 dataSource.log.debug( 720 "StandardXAConnection:getReference return a reference of the object"); 721 Reference ref = 722 new Reference (getClass().getName(), getClass().getName(), null); 723 ref.add( 724 new StringRefAddr ( 725 "commitOnPrepare", 726 String.valueOf(getCommitOnPrepare()))); 727 ref.add( 728 new StringRefAddr ( 729 "timeoutSecs", 730 Integer.toString(getTransactionTimeout()))); 731 return ref; 732 } 733 734 public String toString() { 735 StringBuffer sb = new StringBuffer (); 736 sb.append("StandardXAConnection:\n"); 737 sb.append(" commit on prepare =<"+this.commitOnPrepare+">\n"); 738 sb.append(" is closed =<"+this.isClosed + ">\n"); 739 sb.append(" this autoCommit =<"+this.thisAutoCommit + ">\n"); 740 sb.append(" listeners size =<"+this.listeners.size() + ">\n"); 741 sb.append(" next timeOut =<"+this.nextTimeout + ">\n"); 742 sb.append(" timeOut period =<"+this.timeoutPeriod + ">\n"); 743 sb.append(" timeOut secs =<"+this.timeoutSecs + ">\n"); 744 sb.append(" transaction manager=<"+this.transactionManager + ">\n"); 745 sb.append(this.xaDataSource.toString()); 746 sb.append(this.dataSource.toString()); 747 if (curCon != null) 748 sb.append(this.curCon.toString()); 749 if (connectionHandle != null) 750 sb.append(this.connectionHandle.toString()); 751 sb.append(this.con.toString()); 752 753 return sb.toString(); 754 755 } 756 } 757 | Popular Tags |