1 16 17 package org.springframework.transaction.interceptor; 18 19 import java.lang.reflect.Method ; 20 21 import junit.framework.TestCase; 22 import org.easymock.MockControl; 23 24 import org.springframework.beans.ITestBean; 25 import org.springframework.beans.TestBean; 26 import org.springframework.transaction.CannotCreateTransactionException; 27 import org.springframework.transaction.NoTransactionException; 28 import org.springframework.transaction.PlatformTransactionManager; 29 import org.springframework.transaction.TransactionDefinition; 30 import org.springframework.transaction.TransactionStatus; 31 import org.springframework.transaction.TransactionSystemException; 32 import org.springframework.transaction.UnexpectedRollbackException; 33 import org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo; 34 import org.springframework.transaction.support.DefaultTransactionStatus; 35 36 48 public abstract class AbstractTransactionAspectTests extends TestCase { 49 50 protected Method exceptionalMethod; 51 52 protected Method getNameMethod; 53 54 protected Method setNameMethod; 55 56 public AbstractTransactionAspectTests() { 57 try { 58 exceptionalMethod = ITestBean.class.getMethod("exceptional", new Class [] { Throwable .class }); 60 getNameMethod = ITestBean.class.getMethod("getName", (Class []) null); 61 setNameMethod = ITestBean.class.getMethod("setName", new Class [] { String .class} ); 62 } 63 catch (NoSuchMethodException ex) { 64 throw new RuntimeException ("Shouldn't happen", ex); 65 } 66 } 67 68 78 protected abstract Object advised( 79 Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) throws Exception ; 80 81 public void testNoTransaction() throws Exception { 82 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 83 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 84 85 ptxControl.replay(); 87 88 TestBean tb = new TestBean(); 89 TransactionAttributeSource tas = new MapTransactionAttributeSource(); 90 91 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 95 96 checkTransactionStatus(false); 97 itb.getName(); 98 checkTransactionStatus(false); 99 100 ptxControl.verify(); 101 } 102 103 106 public void testTransactionShouldSucceed() throws Exception { 107 TransactionAttribute txatt = new DefaultTransactionAttribute(); 108 109 Method m = getNameMethod; 110 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 111 tas.register(m, txatt); 112 113 TransactionStatus status = transactionStatusForNewTransaction(); 114 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 115 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 116 ptm.getTransaction(txatt); 118 ptxControl.setReturnValue(status, 1); 119 ptm.commit(status); 120 ptxControl.setVoidCallable(1); 121 ptxControl.replay(); 122 123 TestBean tb = new TestBean(); 124 125 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 126 127 checkTransactionStatus(false); 128 itb.getName(); 130 checkTransactionStatus(false); 131 132 ptxControl.verify(); 133 } 134 135 138 public void testTransactionShouldSucceedWithNotNew() throws Exception { 139 TransactionAttribute txatt = new DefaultTransactionAttribute(); 140 141 Method m = getNameMethod; 142 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 143 tas.register(m, txatt); 144 145 TransactionStatus status = new DefaultTransactionStatus(new Object (), false, false, false, false, null); 146 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 147 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 148 ptm.getTransaction(txatt); 150 ptxControl.setReturnValue(status, 1); 151 ptm.commit(status); 152 ptxControl.setVoidCallable(1); 153 ptxControl.replay(); 154 155 TestBean tb = new TestBean(); 156 157 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 158 159 checkTransactionStatus(false); 160 itb.getName(); 162 checkTransactionStatus(false); 163 164 ptxControl.verify(); 165 } 166 167 public void testEnclosingTransactionWithNonTransactionMethodOnAdvisedInside() throws Throwable { 168 TransactionAttribute txatt = new DefaultTransactionAttribute(); 169 170 Method m = exceptionalMethod; 171 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 172 tas.register(m, txatt); 173 174 TransactionStatus status = transactionStatusForNewTransaction(); 175 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 176 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 177 ptm.getTransaction(txatt); 179 ptxControl.setReturnValue(status, 1); 180 ptm.commit(status); 181 ptxControl.setVoidCallable(1); 182 ptxControl.replay(); 183 184 final String spouseName = "innerName"; 185 186 TestBean outer = new TestBean() { 187 public void exceptional(Throwable t) throws Throwable { 188 TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); 189 assertTrue(ti.hasTransaction()); 190 assertEquals(spouseName, getSpouse().getName()); 191 } 192 }; 193 TestBean inner = new TestBean() { 194 public String getName() { 195 TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); 197 assertFalse(ti.hasTransaction()); 198 return spouseName; 199 } 200 }; 201 202 ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas); 203 ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas); 204 outer.setSpouse(innerProxy); 205 206 checkTransactionStatus(false); 207 208 outerProxy.exceptional(null); 210 211 checkTransactionStatus(false); 212 213 ptxControl.verify(); 214 } 215 216 public void testEnclosingTransactionWithNestedTransactionOnAdvisedInside() throws Throwable { 217 final TransactionAttribute outerTxatt = new DefaultTransactionAttribute(); 218 final TransactionAttribute innerTxatt = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_NESTED); 219 220 Method outerMethod = exceptionalMethod; 221 Method innerMethod = getNameMethod; 222 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 223 tas.register(outerMethod, outerTxatt); 224 tas.register(innerMethod, innerTxatt); 225 226 TransactionStatus outerStatus = transactionStatusForNewTransaction(); 227 TransactionStatus innerStatus = transactionStatusForNewTransaction(); 228 229 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 230 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 231 ptm.getTransaction(outerTxatt); 233 ptxControl.setReturnValue(outerStatus, 1); 234 235 ptm.getTransaction(innerTxatt); 236 ptxControl.setReturnValue(innerStatus, 1); 237 238 ptm.commit(innerStatus); 239 ptxControl.setVoidCallable(1); 240 241 ptm.commit(outerStatus); 242 ptxControl.setVoidCallable(1); 243 ptxControl.replay(); 244 245 final String spouseName = "innerName"; 246 247 TestBean outer = new TestBean() { 248 public void exceptional(Throwable t) throws Throwable { 249 TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); 250 assertTrue(ti.hasTransaction()); 251 assertEquals(outerTxatt, ti.getTransactionAttribute()); 252 assertEquals(spouseName, getSpouse().getName()); 253 } 254 }; 255 TestBean inner = new TestBean() { 256 public String getName() { 257 TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo(); 259 assertTrue(ti.hasTransaction()); 261 assertEquals(innerTxatt, ti.getTransactionAttribute()); 262 return spouseName; 263 } 264 }; 265 266 ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas); 267 ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas); 268 outer.setSpouse(innerProxy); 269 270 checkTransactionStatus(false); 271 272 outerProxy.exceptional(null); 274 275 checkTransactionStatus(false); 276 277 ptxControl.verify(); 278 } 279 280 public void testRollbackOnCheckedException() throws Throwable { 281 doTestRollbackOnException(new Exception (), true, false); 282 } 283 284 public void testNoRollbackOnCheckedException() throws Throwable { 285 doTestRollbackOnException(new Exception (), false, false); 286 } 287 288 public void testRollbackOnUncheckedException() throws Throwable { 289 doTestRollbackOnException(new RuntimeException (), true, false); 290 } 291 292 public void testNoRollbackOnUncheckedException() throws Throwable { 293 doTestRollbackOnException(new RuntimeException (), false, false); 294 } 295 296 public void testRollbackOnCheckedExceptionWithRollbackException() throws Throwable { 297 doTestRollbackOnException(new Exception (), true, true); 298 } 299 300 public void testNoRollbackOnCheckedExceptionWithRollbackException() throws Throwable { 301 doTestRollbackOnException(new Exception (), false, true); 302 } 303 304 public void testRollbackOnUncheckedExceptionWithRollbackException() throws Throwable { 305 doTestRollbackOnException(new RuntimeException (), true, true); 306 } 307 308 public void testNoRollbackOnUncheckedExceptionWithRollbackException() throws Throwable { 309 doTestRollbackOnException(new RuntimeException (), false, true); 310 } 311 312 318 protected void doTestRollbackOnException( 319 final Exception ex, final boolean shouldRollback, boolean rollbackException) throws Exception { 320 321 TransactionAttribute txatt = new DefaultTransactionAttribute() { 322 public boolean rollbackOn(Throwable t) { 323 assertTrue(t == ex); 324 return shouldRollback; 325 } 326 }; 327 328 Method m = exceptionalMethod; 329 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 330 tas.register(m, txatt); 331 332 TransactionStatus status = new DefaultTransactionStatus(null, false, false, false, false, null); 333 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 334 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 335 337 ptm.getTransaction(txatt); 338 ptxControl.setReturnValue(status, 1); 339 340 if (shouldRollback) { 341 ptm.rollback(status); 342 } 343 else { 344 ptm.commit(status); 345 } 346 TransactionSystemException tex = new TransactionSystemException("system exception"); 347 if (rollbackException) { 348 ptxControl.setThrowable(tex, 1); 349 } 350 else { 351 ptxControl.setVoidCallable(1); 352 } 353 ptxControl.replay(); 354 355 TestBean tb = new TestBean(); 356 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 357 358 try { 359 itb.exceptional(ex); 360 fail("Should have thrown exception"); 361 } 362 catch (Throwable t) { 363 if (rollbackException) { 364 assertEquals("Caught wrong exception", tex, t ); 365 } 366 else { 367 assertEquals("Caught wrong exception", ex, t); 368 } 369 } 370 371 ptxControl.verify(); 372 } 373 374 378 public void testProgrammaticRollback() throws Exception { 379 TransactionAttribute txatt = new DefaultTransactionAttribute(); 380 381 Method m = getNameMethod; 382 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 383 tas.register(m, txatt); 384 385 TransactionStatus status = transactionStatusForNewTransaction(); 386 assertTrue(status.isNewTransaction()); 387 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 388 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 389 390 ptm.getTransaction(txatt); 391 ptxControl.setReturnValue(status, 1); 392 ptm.commit(status); 393 ptxControl.setVoidCallable(1); 394 ptxControl.replay(); 395 396 final String name = "jenny"; 397 TestBean tb = new TestBean() { 398 public String getName() { 399 TransactionStatus txStatus = TransactionInterceptor.currentTransactionStatus(); 400 txStatus.setRollbackOnly(); 401 return name; 402 } 403 }; 404 405 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 406 407 assertTrue(name.equals(itb.getName())); 409 410 ptxControl.verify(); 411 } 412 413 416 private TransactionStatus transactionStatusForNewTransaction() { 417 return new DefaultTransactionStatus(new Object (), true, false, false, false, null); 418 } 419 420 424 public void testCannotCreateTransaction() throws Exception { 425 TransactionAttribute txatt = new DefaultTransactionAttribute(); 426 427 Method m = getNameMethod; 428 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 429 tas.register(m, txatt); 430 431 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 432 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 433 ptm.getTransaction(txatt); 435 CannotCreateTransactionException ex = new CannotCreateTransactionException("foobar", null); 436 ptxControl.setThrowable(ex); 437 ptxControl.replay(); 438 439 TestBean tb = new TestBean() { 440 public String getName() { 441 throw new UnsupportedOperationException ( 442 "Shouldn't have invoked target method when couldn't create transaction for transactional method"); 443 } 444 }; 445 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 446 447 try { 448 itb.getName(); 449 fail("Shouldn't have invoked method"); 450 } 451 catch (CannotCreateTransactionException thrown) { 452 assertTrue(thrown == ex); 453 } 454 ptxControl.verify(); 455 } 456 457 462 public void testCannotCommitTransaction() throws Exception { 463 TransactionAttribute txatt = new DefaultTransactionAttribute(); 464 465 Method m = setNameMethod; 466 MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); 467 tas.register(m, txatt); 468 Method m2 = getNameMethod; 469 471 MockControl ptxControl = MockControl.createControl(PlatformTransactionManager.class); 472 PlatformTransactionManager ptm = (PlatformTransactionManager) ptxControl.getMock(); 473 474 TransactionStatus status = transactionStatusForNewTransaction(); 475 ptm.getTransaction(txatt); 476 ptxControl.setReturnValue(status); 477 UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); 478 ptm.commit(status); 479 ptxControl.setThrowable(ex); 480 ptxControl.replay(); 481 482 TestBean tb = new TestBean(); 483 ITestBean itb = (ITestBean) advised(tb, ptm, tas); 484 485 String name = "new name"; 486 try { 487 itb.setName(name); 488 fail("Shouldn't have succeeded"); 489 } 490 catch (UnexpectedRollbackException thrown) { 491 assertTrue(thrown == ex); 492 } 493 494 assertTrue(itb.getName() == name); 496 ptxControl.verify(); 497 } 498 499 protected void checkTransactionStatus(boolean expected) { 500 try { 501 TransactionInterceptor.currentTransactionStatus(); 502 if (!expected) { 503 fail("Should have thrown NoTransactionException"); 504 } 505 } 506 catch (NoTransactionException ex) { 507 if (expected) { 508 fail("Should have current TransactionStatus"); 509 } 510 } 511 } 512 513 } 514 | Popular Tags |