1 23 24 package org.apache.slide.transaction; 25 26 import java.io.PrintWriter; 27 import java.io.StringWriter; 28 import java.util.Enumeration; 29 import java.util.Hashtable; 30 import java.util.Vector; 31 32 import javax.transaction.HeuristicMixedException; 33 import javax.transaction.HeuristicRollbackException; 34 import javax.transaction.RollbackException; 35 import javax.transaction.Status; 36 import javax.transaction.Synchronization; 37 import javax.transaction.SystemException; 38 import javax.transaction.Transaction; 39 import javax.transaction.xa.XAException; 40 import javax.transaction.xa.XAResource; 41 import javax.transaction.xa.Xid; 42 43 import org.apache.slide.util.Messages; 44 import org.apache.slide.util.logger.Logger; 45 46 51 public final class SlideTransaction implements Transaction { 52 53 54 56 57 protected static final String LOG_CHANNEL = 58 SlideTransaction.class.getName(); 59 60 61 63 64 67 public SlideTransaction(SlideTransactionManager transactionManager) { 68 globalCreatedTransactions++; 70 currentTransactionNumber = globalCreatedTransactions; 71 currentThreadName = Thread.currentThread().getName(); 72 xid = new SlideXid 73 ((currentThreadName + "-" + System.currentTimeMillis() + "-" 74 + currentTransactionNumber).getBytes(), 75 0, new byte[0]); 76 this.transactionManager = transactionManager; 77 } 78 79 80 82 83 86 private SlideXid xid; 87 88 89 93 private Hashtable branches = new Hashtable(); 94 95 96 100 private Hashtable activeBranches = new Hashtable(); 101 102 103 106 private Vector enlistedResources = new Vector(); 107 108 109 113 private Hashtable suspendedResources = new Hashtable(); 114 115 116 119 private int status = Status.STATUS_ACTIVE; 120 121 122 125 private Vector synchronizationObjects = new Vector(); 126 127 128 131 private int branchCounter = 1; 132 133 134 137 private static int globalCreatedTransactions = 0; 138 139 140 143 private int currentTransactionNumber = 0; 144 145 146 149 private String currentThreadName = null; 150 151 152 155 private SlideTransactionManager transactionManager; 156 157 158 160 161 163 164 182 public void commit() 183 throws RollbackException, HeuristicMixedException, 184 HeuristicRollbackException, SecurityException, IllegalStateException, 185 SystemException { 186 187 189 if (status == Status.STATUS_MARKED_ROLLBACK) { 190 rollback(); 191 return; 192 } 193 194 if (status != Status.STATUS_ACTIVE) 196 throw new IllegalStateException(); 197 198 Enumeration syncList = synchronizationObjects.elements(); 200 while (syncList.hasMoreElements()) { 201 Synchronization sync = (Synchronization) syncList.nextElement(); 202 sync.beforeCompletion(); 203 } 204 205 Vector exceptions = new Vector(); 206 boolean fail = false; 207 208 Enumeration enum = branches.keys(); 209 210 if (enlistedResources.size() == 1) { 211 212 status = Status.STATUS_COMMITTING; 214 while (enum.hasMoreElements()) { 215 Object key = enum.nextElement(); 216 XAResource resourceManager = 217 (XAResource) branches.get(key); 218 try { 219 if (!fail) 220 resourceManager.commit(xid, true); 221 else 222 resourceManager.rollback(xid); 223 } catch (Throwable e) { 224 String logMessage = Messages.format 226 (SlideTransaction.class.getName() + ".commitFail", 227 resourceManager, getXAErrorCode(e), toString()); 228 transactionManager.getLogger().log 229 (logMessage, e, LOG_CHANNEL, Logger.WARNING); 230 exceptions.addElement(e); 231 fail = true; 232 status = Status.STATUS_MARKED_ROLLBACK; 233 } 234 } 235 if (!fail) { 236 status = Status.STATUS_COMMITTED; 237 } else { 238 status = Status.STATUS_ROLLEDBACK; 239 } 240 241 } else if (enlistedResources.size() != 0) { 242 243 status = Status.STATUS_PREPARING; 245 while ((!fail) && (enum.hasMoreElements())) { 246 Object key = enum.nextElement(); 247 XAResource resourceManager = 248 (XAResource) branches.get(key); 249 try { 250 resourceManager.prepare((Xid) key); 252 } catch (Throwable e) { 253 String logMessage = Messages.format 254 (SlideTransaction.class.getName() + ".prepareFail", 255 resourceManager, getXAErrorCode(e), toString()); 256 transactionManager.getLogger().log 257 (logMessage, e, LOG_CHANNEL, Logger.WARNING); 258 exceptions.addElement(e); 260 fail = true; 261 status = Status.STATUS_MARKED_ROLLBACK; 262 } 263 } 264 265 if (!fail) 266 status = Status.STATUS_PREPARED; 267 268 if (fail) { 270 status = Status.STATUS_ROLLING_BACK; 271 fail = false; 272 enum = branches.keys(); 274 while (enum.hasMoreElements()) { 275 Object key = enum.nextElement(); 276 XAResource resourceManager = 277 (XAResource) branches.get(key); 278 try { 279 resourceManager.rollback((Xid) key); 280 } catch(Throwable e) { 281 String logMessage = Messages.format 282 (SlideTransaction.class.getName() + ".rollbackFail", 283 resourceManager, getXAErrorCode(e), toString()); 284 transactionManager.getLogger().log 285 (logMessage, e, LOG_CHANNEL, Logger.WARNING); 286 exceptions.addElement(e); 287 fail = true; 288 } 289 } 290 status = Status.STATUS_ROLLEDBACK; 291 } else { 292 status = Status.STATUS_COMMITTING; 293 enum = branches.keys(); 295 while (enum.hasMoreElements()) { 296 Object key = enum.nextElement(); 297 XAResource resourceManager = 298 (XAResource) branches.get(key); 299 try { 300 resourceManager.commit((Xid) key, false); 301 } catch(Throwable e) { 302 String logMessage = Messages.format 303 (SlideTransaction.class.getName() + ".commitFail", 304 resourceManager, getXAErrorCode(e), toString()); 305 transactionManager.getLogger().log 306 (logMessage, e, LOG_CHANNEL, Logger.WARNING); 307 exceptions.addElement(e); 308 fail = true; 309 } 310 } 311 status = Status.STATUS_COMMITTED; 312 } 313 314 } 315 316 syncList = synchronizationObjects.elements(); 318 while (syncList.hasMoreElements()) { 319 Synchronization sync = 320 (Synchronization) syncList.nextElement(); 321 sync.afterCompletion(status); 322 } 323 324 enum = exceptions.elements(); 326 if (enum.hasMoreElements()) { 327 if ((status == Status.STATUS_ROLLEDBACK) && (!fail)) 328 throw new RollbackException(); 329 if (status == Status.STATUS_ROLLEDBACK) 330 throw new HeuristicRollbackException(); 331 if ((status == Status.STATUS_COMMITTED) && (fail)) 332 throw new HeuristicMixedException(); 333 } 334 335 } 336 337 338 349 public boolean delistResource(XAResource xaRes, int flag) 350 throws IllegalStateException, SystemException { 351 352 354 if (status != Status.STATUS_ACTIVE) 356 throw new IllegalStateException(); 357 358 Xid xid = (Xid) activeBranches.get(xaRes); 359 360 if (xid == null) 361 throw new IllegalStateException(); 362 363 activeBranches.remove(xaRes); 364 365 if (transactionManager.getLogger().isEnabled 366 (LOG_CHANNEL, Logger.DEBUG)) { 367 String logMessage = Messages.format 368 (SlideTransaction.class.getName() + ".delist", xaRes, 369 getXAFlag(flag), toString()); 370 transactionManager.getLogger().log 371 (logMessage, LOG_CHANNEL, Logger.DEBUG); 372 } 373 374 XAException exception = null; 375 376 try { 377 xaRes.end(xid, flag); 378 } catch (XAException e) { 379 exception = e; 380 } 381 382 if (exception != null) { 383 String logMessage = Messages.format 384 (SlideTransaction.class.getName() + ".delistFail", 385 xaRes, getXAErrorCode(exception), toString()); 386 transactionManager.getLogger().log 387 (logMessage, LOG_CHANNEL, Logger.WARNING); 388 return false; 389 } 390 391 if (flag == XAResource.TMSUSPEND) 392 suspendedResources.put(xaRes, xid); 393 394 396 return true; 397 398 } 399 400 401 414 public boolean enlistResource(XAResource xaRes) 415 throws RollbackException, IllegalStateException, SystemException { 416 417 419 if (status == Status.STATUS_MARKED_ROLLBACK) 420 throw new RollbackException(); 421 422 if (status != Status.STATUS_ACTIVE) 424 throw new IllegalStateException(); 425 426 Xid activeXid = (Xid) activeBranches.get(xaRes); 429 if (activeXid != null) 430 return false; 431 432 boolean alreadyEnlisted = false; 433 int flag = XAResource.TMNOFLAGS; 434 435 Xid branchXid = (Xid) suspendedResources.get(xaRes); 436 437 if (branchXid == null) { 438 Enumeration enum = enlistedResources.elements(); 439 while ((!alreadyEnlisted) && (enum.hasMoreElements())) { 440 XAResource resourceManager = (XAResource) enum.nextElement(); 441 try { 442 if (resourceManager.isSameRM(xaRes)) { 443 flag = XAResource.TMJOIN; 444 alreadyEnlisted = true; 445 } 446 } catch (XAException e) { 447 } 448 } 449 branchXid = this.xid.newBranch(branchCounter++); 450 451 453 } else { 454 alreadyEnlisted = true; 455 flag = XAResource.TMRESUME; 456 suspendedResources.remove(xaRes); 457 } 458 459 if (transactionManager.getLogger().isEnabled 460 (LOG_CHANNEL, Logger.DEBUG)) { 461 String logMessage = Messages.format 462 (SlideTransaction.class.getName() + ".enlist", xaRes, 463 getXAFlag(flag), toString()); 464 transactionManager.getLogger().log 465 (logMessage, LOG_CHANNEL, Logger.DEBUG); 466 } 467 468 try { 469 471 xaRes.start(branchXid, flag); 472 } catch (XAException e) { 473 String logMessage = Messages.format 474 (SlideTransaction.class.getName() + ".enlistFail", 475 xaRes, getXAErrorCode(e), toString()); 476 transactionManager.getLogger().log 477 (logMessage, LOG_CHANNEL, Logger.WARNING); 478 return false; 479 } 480 481 if (!alreadyEnlisted) { 482 enlistedResources.addElement(xaRes); 483 } 484 485 branches.put(branchXid, xaRes); 486 activeBranches.put(xaRes, branchXid); 487 488 return true; 489 490 } 491 492 493 505 public void rollback() 506 throws SecurityException, IllegalStateException, SystemException { 507 508 510 if (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK) 512 throw new IllegalStateException(); 513 514 Vector exceptions = new Vector(); 515 516 Enumeration enum = branches.keys(); 517 518 status = Status.STATUS_ROLLING_BACK; 519 while (enum.hasMoreElements()) { 520 Xid xid = (Xid) enum.nextElement(); 521 XAResource resourceManager = (XAResource) branches.get(xid); 522 try { 523 resourceManager.rollback(xid); 524 } catch (Throwable e) { 525 exceptions.addElement(e); 526 String logMessage = Messages.format 527 (SlideTransaction.class.getName() + ".rollbackFail", 528 resourceManager, getXAErrorCode(e), toString()); 529 transactionManager.getLogger().log 530 (logMessage, LOG_CHANNEL, Logger.WARNING); 531 } 532 } 533 status = Status.STATUS_ROLLEDBACK; 534 535 } 536 537 538 548 public void setRollbackOnly() 549 throws IllegalStateException, SystemException { 550 status = Status.STATUS_MARKED_ROLLBACK; 551 } 552 553 554 562 public int getStatus() 563 throws SystemException { 564 return status; 565 } 566 567 568 584 public void registerSynchronization(Synchronization sync) 585 throws RollbackException, IllegalStateException, SystemException { 586 587 if (status == Status.STATUS_MARKED_ROLLBACK) 588 throw new RollbackException(); 589 590 if (status != Status.STATUS_ACTIVE) 591 throw new IllegalStateException(); 592 593 synchronizationObjects.addElement(sync); 594 595 } 596 597 598 600 601 605 public static String getXAErrorCode(Throwable throww) { 606 String result = null; 607 if (throww instanceof XAException) 608 result = getXAErrorCode((XAException)throww); 609 else { 610 StringWriter sw = new StringWriter(); 611 throww.printStackTrace( new PrintWriter(sw, true) ); result = sw.toString(); 613 } 614 return result; 615 } 616 620 public static String getXAErrorCode(XAException xae) { 621 switch (xae.errorCode) { 622 case XAException.XA_HEURCOM: 623 return "XA_HEURCOM"; 624 case XAException.XA_HEURHAZ: 625 return "XA_HEURHAZ"; 626 case XAException.XA_HEURMIX: 627 return "XA_HEURMIX"; 628 case XAException.XA_HEURRB: 629 return "XA_HEURRB"; 630 case XAException.XA_NOMIGRATE: 631 return "XA_NOMIGRATE"; 632 case XAException.XA_RBBASE: 633 return "XA_RBBASE"; 634 case XAException.XA_RBCOMMFAIL: 635 return "XA_RBCOMMFAIL"; 636 case XAException.XA_RBDEADLOCK: 637 return "XA_RBBEADLOCK"; 638 case XAException.XA_RBEND: 639 return "XA_RBEND"; 640 case XAException.XA_RBINTEGRITY: 641 return "XA_RBINTEGRITY"; 642 case XAException.XA_RBOTHER: 643 return "XA_RBOTHER"; 644 case XAException.XA_RBPROTO: 645 return "XA_RBPROTO"; 646 case XAException.XA_RBTIMEOUT: 647 return "XA_RBTIMEOUT"; 648 case XAException.XA_RDONLY: 649 return "XA_RDONLY"; 650 case XAException.XA_RETRY: 651 return "XA_RETRY"; 652 case XAException.XAER_ASYNC: 653 return "XAER_ASYNC"; 654 case XAException.XAER_DUPID: 655 return "XAER_DUPID"; 656 case XAException.XAER_INVAL: 657 return "XAER_INVAL"; 658 case XAException.XAER_NOTA: 659 return "XAER_NOTA"; 660 case XAException.XAER_OUTSIDE: 661 return "XAER_OUTSIDE"; 662 case XAException.XAER_PROTO: 663 return "XAER_PROTO"; 664 case XAException.XAER_RMERR: 665 return "XAER_RMERR"; 666 case XAException.XAER_RMFAIL: 667 return "XAER_RMFAIL"; 668 default: 669 return "UNKNOWN"; 670 } 671 } 672 673 674 677 public static String getXAFlag(int flag) { 678 switch (flag) { 679 case XAResource.TMENDRSCAN: 680 return "TMENDRSCAN"; 681 case XAResource.TMFAIL: 682 return "TMFAIL"; 683 case XAResource.TMJOIN: 684 return "TMJOIN"; 685 case XAResource.TMNOFLAGS: 686 return "TMNOFLAGS"; 687 case XAResource.TMONEPHASE: 688 return "TMONEPHASE"; 689 case XAResource.TMRESUME: 690 return "TMRESUME"; 691 case XAResource.TMSTARTRSCAN: 692 return "TMSTARTRSCAN"; 693 case XAResource.TMSUCCESS: 694 return "TMSUCCESS"; 695 case XAResource.TMSUSPEND: 696 return "TMSUSPEND"; 697 default: 698 return "UNKNOWN"; 699 } 700 } 701 702 703 706 public String toString() { 707 return "Transaction " + currentTransactionNumber 708 + " xid " + xid + " in thread " + currentThreadName + 709 (currentThreadName.equals(Thread.currentThread().getName())?"": 710 " current= " + Thread.currentThread().getName()); 711 } 712 713 714 } 715 716 717 | Popular Tags |