1 28 29 package com.caucho.ejb.xa; 30 31 import com.caucho.amber.manager.AmberConnection; 32 import com.caucho.ejb.EJBExceptionWrapper; 33 import com.caucho.ejb.entity.EntityServer; 34 import com.caucho.ejb.entity.QEntity; 35 import com.caucho.log.Log; 36 import com.caucho.transaction.TransactionImpl; 37 import com.caucho.util.Alarm; 38 import com.caucho.util.L10N; 39 40 import javax.ejb.EJBException ; 41 import javax.ejb.SessionSynchronization ; 42 import javax.transaction.Status ; 43 import javax.transaction.Synchronization ; 44 import javax.transaction.Transaction ; 45 import javax.transaction.UserTransaction ; 46 import java.rmi.RemoteException ; 47 import java.util.logging.Level ; 48 import java.util.logging.Logger ; 49 50 53 public class TransactionContext implements Synchronization { 54 static final L10N L = new L10N(TransactionContext.class); 55 protected static final Logger log = Log.open(TransactionContext.class); 56 57 public static final TransactionContext NULL_TRANSACTION = 58 new TransactionContext(null); 59 60 private EjbTransactionManager _container; 61 private AmberConnection _amberConn; 62 63 private UserTransaction _userTransaction; 64 private Transaction _transaction; 65 66 TransactionContext _old; 68 Transaction _oldTrans; 70 71 private long _startTime; 72 73 private TransactionObject []_objects = new TransactionObject[16]; 74 private int _objectTop; 75 76 private SessionSynchronization []_sessions = new SessionSynchronization [16]; 77 private int _sessionTop; 78 79 private boolean _isRowLocking; 80 private boolean _rollbackOnly; 81 82 private boolean _isUserTransaction; 83 private int _depth; 84 private boolean _isAlive; 85 private boolean _isCommitting; 86 87 TransactionContext(EjbTransactionManager container) 88 { 89 _container = container; 90 91 if (container != null) 92 _userTransaction = container.getUserTransaction(); 93 } 94 95 void init(boolean pushDepth) 96 { 97 if (_isAlive) { 98 log.warning(L.l("Transaction {0} nested start. This is an internal Resin error, please report it as a bug at bugs@caucho.com.", this)); 99 100 throw new IllegalStateException (L.l("nested transaction start")); 101 } 102 103 _transaction = null; 104 _old = null; 105 _oldTrans = null; 106 _objectTop = 0; 107 _sessionTop = 0; 108 _rollbackOnly = false; 109 _depth = pushDepth ? 1 : 0; 110 _isUserTransaction = false; 111 _isAlive = true; 112 _isRowLocking = false; 113 _startTime = Alarm.getCurrentTime(); 114 } 115 116 public void setTransaction(Transaction transaction) 117 { 118 if (_transaction != null && _transaction != transaction) 119 throw new IllegalStateException ("can't set transaction twice."); 120 _transaction = transaction; 121 122 if (transaction != null) { 123 try { 124 transaction.registerSynchronization(this); 125 } catch (Exception e) { 126 throw new EJBExceptionWrapper(e); 127 } 128 } 129 } 130 131 public Transaction getTransaction() 132 { 133 return _transaction; 134 } 135 136 139 public boolean isReadOnly() 140 { 141 return _transaction == null; 142 } 143 144 147 public boolean isRowLocking() 148 { 149 return _transaction != null && _isRowLocking; 150 } 151 152 155 public void setRowLocking(boolean isRowLocking) 156 { 157 _isRowLocking = isRowLocking; 158 } 159 160 TransactionContext getOld() 161 { 162 return _old; 163 } 164 165 void setOld(TransactionContext old) 166 { 167 _old = old; 168 } 169 170 Transaction getOldTrans() 171 { 172 return _oldTrans; 173 } 174 175 void setOldTrans(Transaction old) 176 { 177 if (old == _transaction && old != null) 178 throw new IllegalStateException (); 179 180 _oldTrans = old; 181 } 182 183 public void pushDepth() 184 { 185 if (_depth == 0) { 186 _isAlive = true; 187 } 188 189 _depth++; 190 } 191 192 public void setUserTransaction(boolean isUserTransaction) 193 { 194 if (_depth == 0) 195 _isAlive = true; 196 197 _isUserTransaction = isUserTransaction; 198 } 199 200 203 public boolean getRollbackOnly() 204 { 205 return _rollbackOnly; 206 } 207 208 211 public void setRollbackOnly() 212 { 213 _rollbackOnly = true; 214 215 if (_transaction != null) { 216 try { 217 _transaction.setRollbackOnly(); 218 } catch (Exception e) { 219 throw new EJBExceptionWrapper(e); 220 } 221 } 222 } 223 224 227 public RuntimeException setRollbackOnly(Throwable exn) 228 { 229 _rollbackOnly = true; 230 231 if (log.isLoggable(Level.FINER)) 232 log.log(Level.FINER, "rollback only: " + exn, exn); 233 234 if (_transaction != null) { 235 try { 236 if (_transaction instanceof TransactionImpl) 237 ((TransactionImpl) _transaction).setRollbackOnly(exn); 238 else 239 _transaction.setRollbackOnly(); 240 } catch (Exception e) { 241 return EJBExceptionWrapper.createRuntime(exn); 242 } 243 } 244 245 return EJBExceptionWrapper.createRuntime(exn); 246 } 247 248 253 public void addObject(TransactionObject object) 254 { 255 if (_objectTop + 1 >= _objects.length) { 256 TransactionObject []newObjects; 257 newObjects = new TransactionObject[_objects.length * 2]; 258 for (int i = 0; i < _objectTop; i++) 259 newObjects[i] = _objects[i]; 260 _objects = newObjects; 261 } 262 263 _objects[_objectTop++] = object; 264 } 265 266 271 public void removeObject(TransactionObject object) 272 { 273 for (int i = 0; i < _objectTop; i++) { 274 if (_objects[i] == object) { 275 for (int j = i; j + 1 < _objectTop; j++) 276 _objects[j] = _objects[j + 1]; 277 i--; 278 _objectTop--; 279 } 280 } 281 } 282 283 286 public QEntity getEntity(EntityServer server, Object primaryKey) 287 { 288 for (int i = _objectTop - 1; i >= 0; i--) { 289 TransactionObject obj = _objects[i]; 290 291 if (obj instanceof QEntity) { 292 QEntity entity = (QEntity) obj; 293 294 if (entity._caucho_isMatch(server, primaryKey)) { 295 return entity; 296 } 297 } 298 } 299 300 return null; 301 } 302 303 306 public AmberConnection getAmberConnection() 307 { 308 if (_amberConn == null) { 309 _amberConn = _container.getEJBManager().getAmberManager().getThreadConnection(); 310 } 311 312 try { 313 _amberConn.setXA(_transaction != null); 314 } catch (Exception e) { 315 log.log(Level.WARNING, e.toString(), e); 316 } 317 318 return _amberConn; 319 } 320 321 326 public void addSession(SessionSynchronization session) 327 throws EJBException 328 { 329 for (int i = _sessionTop - 1; i >= 0; i--) 330 if (_sessions[i] == session) 331 return; 332 333 if (_sessionTop + 1 >= _sessions.length) { 334 SessionSynchronization []newSessions; 335 newSessions = new SessionSynchronization [_sessions.length * 2]; 336 337 for (int i = 0; i < _sessionTop; i++) 338 newSessions[i] = _sessions[i]; 339 _sessions = newSessions; 340 } 341 342 _sessions[_sessionTop++] = session; 343 try { 344 session.afterBegin(); 345 } catch (RemoteException e) { 346 EJBException exn = new EJBException (e.toString()); 347 exn.initCause(e); 348 throw exn; 349 } 350 } 351 352 355 public void sync() 356 throws EJBException 357 { 358 try { 359 for (int i = _objectTop - 1; i >= 0; i--) { 360 _objects[i]._caucho_sync(); 361 } 362 } catch (Exception e) { 363 throw setRollbackOnly(e); 364 } 365 } 366 367 370 public boolean isEmpty() 371 { 372 if (! _isAlive) 373 return true; 374 else if (_transaction == null) 375 return true; 376 else if (! (_transaction instanceof TransactionImpl)) 377 return false; 378 else 379 return ((TransactionImpl) _transaction).isEmpty(); 380 } 381 382 385 public void commit() 386 throws EJBException 387 { 388 if (_isCommitting || --_depth > 0) 389 return; 390 391 boolean hasCompletion = false; 392 try { 393 _isCommitting = true; 394 395 if (! _isAlive) { 396 log.warning(L.l("Transaction has died")); 397 } 398 else if (_transaction == null) { 399 hasCompletion = true; 400 try { 401 beforeCompletion(); 402 } finally { 403 afterCompletion(_rollbackOnly ? 404 Status.STATUS_ROLLEDBACK : 405 Status.STATUS_COMMITTED); 406 } 407 } 408 else if (_rollbackOnly || 409 _transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK) { 410 hasCompletion = true; 411 _userTransaction.rollback(); 412 } 413 else if (_transaction.getStatus() != Status.STATUS_NO_TRANSACTION) { 414 hasCompletion = true; 415 _userTransaction.commit(); 416 } 417 } catch (Exception e) { 418 throw EJBExceptionWrapper.createRuntime(e); 419 } finally { 420 _isCommitting = false; 421 422 if (! hasCompletion) 423 afterCompletion(Status.STATUS_ROLLEDBACK); 424 } 425 } 426 427 430 public void rollback() 431 throws EJBException 432 { 433 if (_isCommitting || --_depth > 0) 434 return; 435 436 try { 437 _isCommitting = true; 438 439 if (! _rollbackOnly) 440 setRollbackOnly(); 441 442 if (_transaction == null && _isAlive) { 443 try { 444 beforeCompletion(); 445 } finally { 446 afterCompletion(Status.STATUS_ROLLEDBACK); 447 } 448 } 449 else 450 _userTransaction.rollback(); 451 } catch (EJBException e) { 452 throw e; 453 } catch (Exception e) { 454 throw new EJBExceptionWrapper(e); 455 } finally { 456 _isCommitting = false; 457 458 if (_depth <= 0 && _transaction != null) 459 afterCompletion(Status.STATUS_ROLLEDBACK); 460 } 461 } 462 463 466 public void beforeCompletion() 467 { 468 try { 469 if (_transaction != null && 470 _transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK) 471 _rollbackOnly = true; 472 473 for (int i = _sessionTop - 1; i >= 0; i--) 474 _sessions[i].beforeCompletion(); 475 476 for (int i = _objectTop - 1; i >= 0; i--) { 477 _objects[i]._caucho_beforeCompletion(! _rollbackOnly); 478 } 479 480 } catch (Throwable e) { 487 throw setRollbackOnly(e); 488 } 489 } 490 491 public boolean isDead() 492 { 493 return ! _isAlive; 494 } 495 496 499 public void afterCompletion(int status) 500 { 501 506 507 if (! _isAlive) { 508 IllegalStateException e = new IllegalStateException ("after completion called for dead transaction."); 509 log.log(Level.WARNING, e.toString(), e); 510 return; 511 } 512 513 boolean wasCommitted = status == Status.STATUS_COMMITTED; 514 int sessionTop = _sessionTop; 515 int objectTop = _objectTop; 516 TransactionContext old = _old; 517 Transaction transaction = _transaction; 518 Transaction oldTrans = _oldTrans; 519 520 _sessionTop = 0; 521 _objectTop = 0; 522 _old = null; 523 if (oldTrans == transaction) 524 oldTrans = null; 525 _oldTrans = null; 526 _rollbackOnly = false; 527 528 Throwable exn = null; 529 530 try { 531 AmberConnection amberConn = _amberConn; 532 _amberConn = null; 533 if (amberConn != null) { 534 amberConn.afterCommit(wasCommitted); 535 amberConn.freeConnection(); 536 } 537 } catch (Throwable e) { 538 log.log(Level.WARNING, e.toString(), e); 539 } 540 541 for (int i = sessionTop - 1; i >= 0; i--) { 542 try { 543 _sessions[i].afterCompletion(wasCommitted); 544 _sessions[i] = null; 545 } catch (Throwable e) { 546 exn = e; 547 log.log(Level.WARNING, e.toString(), e); 548 } 549 } 550 551 for (int i = objectTop - 1; i >= 0; i--) { 552 try { 553 _objects[i]._caucho_afterCompletion(wasCommitted); 554 _objects[i] = null; 555 } catch (Throwable e) { 556 exn = e; 557 log.log(Level.WARNING, e.toString(), e); 558 } 559 } 560 561 _transaction = null; 562 _isAlive = false; 563 564 if (_depth == 0 || _isUserTransaction && _depth == 1) { 565 _container.resume(old, oldTrans, transaction); 566 _container.freeTransaction(this); 567 } 568 569 if (exn != null) 570 throw EJBExceptionWrapper.createRuntime(exn); 571 } 572 } 573 | Popular Tags |