| 1 16 17 package org.springframework.aop.framework; 18 19 import java.lang.reflect.Method ; 20 import java.lang.reflect.UndeclaredThrowableException ; 21 import java.util.HashMap ; 22 import java.util.LinkedList ; 23 import java.util.List ; 24 25 import javax.servlet.ServletException ; 26 import javax.transaction.TransactionRequiredException ; 27 28 import junit.framework.TestCase; 29 import org.aopalliance.aop.Advice; 30 import org.aopalliance.aop.AspectException; 31 import org.aopalliance.intercept.MethodInterceptor; 32 import org.aopalliance.intercept.MethodInvocation; 33 34 import org.springframework.aop.Advisor; 35 import org.springframework.aop.AfterReturningAdvice; 36 import org.springframework.aop.DynamicIntroductionAdvice; 37 import org.springframework.aop.MethodBeforeAdvice; 38 import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests; 39 import org.springframework.aop.interceptor.ExposeInvocationInterceptor; 40 import org.springframework.aop.interceptor.NopInterceptor; 41 import org.springframework.aop.interceptor.SerializableNopInterceptor; 42 import org.springframework.aop.support.AopUtils; 43 import org.springframework.aop.support.DefaultIntroductionAdvisor; 44 import org.springframework.aop.support.DefaultPointcutAdvisor; 45 import org.springframework.aop.support.DelegatingIntroductionInterceptor; 46 import org.springframework.aop.support.DynamicMethodMatcherPointcutAdvisor; 47 import org.springframework.aop.support.NameMatchMethodPointcut; 48 import org.springframework.aop.support.Pointcuts; 49 import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; 50 import org.springframework.aop.target.HotSwappableTargetSource; 51 import org.springframework.aop.target.SingletonTargetSource; 52 import org.springframework.beans.IOther; 53 import org.springframework.beans.ITestBean; 54 import org.springframework.beans.Person; 55 import org.springframework.beans.SerializablePerson; 56 import org.springframework.beans.TestBean; 57 import org.springframework.util.SerializationTestUtils; 58 import org.springframework.util.StopWatch; 59 60 65 public abstract class AbstractAopProxyTests extends TestCase { 66 67 protected MockTargetSource mockTargetSource = new MockTargetSource(); 68 69 75 protected void setUp() { 76 mockTargetSource.reset(); 77 } 78 79 protected void tearDown() { 80 mockTargetSource.verify(); 81 } 82 83 86 protected abstract Object createProxy(AdvisedSupport as); 87 88 protected abstract AopProxy createAopProxy(AdvisedSupport as); 89 90 93 protected boolean requiresTarget() { 94 return false; 95 } 96 97 public void testNoInterceptorsAndNoTarget() { 98 AdvisedSupport pc = 99 new AdvisedSupport(new Class [] { ITestBean.class }); 100 try { 102 AopProxy aop = createAopProxy(pc); 103 aop.getProxy(); 104 fail("Shouldn't allow no interceptors"); 105 } catch (AopConfigException ex) { 106 } 108 } 109 110 113 public void testValuesStick() { 114 int age1 = 33; 115 int age2 = 37; 116 String name = "tony"; 117 118 TestBean target1 = new TestBean(); 119 target1.setAge(age1); 120 ProxyFactory pf1 = new ProxyFactory(target1); 121 pf1.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())); 122 pf1.addAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor())); 123 ITestBean tb = target1; 124 125 assertEquals(age1, tb.getAge()); 126 tb.setAge(age2); 127 assertEquals(age2, tb.getAge()); 128 assertNull(tb.getName()); 129 tb.setName(name); 130 assertEquals(name, tb.getName()); 131 } 132 133 138 public void testManyProxies() { 139 int howMany = 10000; 140 StopWatch sw = new StopWatch(); 141 sw.start(getClass() + "." + getName() + ": create " + howMany + " proxies"); 142 testManyProxies(howMany); 143 sw.stop(); 144 System.out.println(sw); 145 assertTrue("Proxy creation was too slow", sw.getTotalTimeSeconds() < 25); 148 } 149 150 private void testManyProxies(int howMany) { 151 int age1 = 33; 152 TestBean target1 = new TestBean(); 153 target1.setAge(age1); 154 ProxyFactory pf1 = new ProxyFactory(target1); 155 pf1.addAdvice(new NopInterceptor()); 156 pf1.addAdvice(new NopInterceptor()); 157 ITestBean proxies[] = new ITestBean[howMany]; 158 for (int i = 0; i < howMany; i++) { 159 proxies[i] = (ITestBean) createAopProxy(pf1).getProxy(); 160 assertEquals(age1, proxies[i].getAge()); 161 } 162 } 163 164 public void testSerializationAdviceAndTargetNotSerializable() throws Exception { 165 TestBean tb = new TestBean(); 166 assertFalse(SerializationTestUtils.isSerializable(tb)); 167 168 ProxyFactory pf = new ProxyFactory(tb); 169 170 pf.addAdvice(new NopInterceptor()); 171 ITestBean proxy = (ITestBean) createAopProxy(pf).getProxy(); 172 173 assertFalse(SerializationTestUtils.isSerializable(proxy)); 174 } 175 176 public void testSerializationAdviceNotSerializable() throws Exception { 177 SerializablePerson sp = new SerializablePerson(); 178 assertTrue(SerializationTestUtils.isSerializable(sp)); 179 180 ProxyFactory pf = new ProxyFactory(sp); 181 182 Advice i = new NopInterceptor(); 184 pf.addAdvice(i); 185 assertFalse(SerializationTestUtils.isSerializable(i)); 186 Object proxy = createAopProxy(pf).getProxy(); 187 188 assertFalse(SerializationTestUtils.isSerializable(proxy)); 189 } 190 191 public void testSerializationSerializableTargetAndAdvice() throws Throwable { 192 SerializablePerson personTarget = new SerializablePerson(); 193 personTarget.setName("jim"); 194 personTarget.setAge(26); 195 196 assertTrue(SerializationTestUtils.isSerializable(personTarget)); 197 198 ProxyFactory pf = new ProxyFactory(personTarget); 199 200 CountingThrowsAdvice cta = new CountingThrowsAdvice(); 201 202 pf.addAdvice(new SerializableNopInterceptor()); 203 pf.addAdvice(new CountingBeforeAdvice()); 205 pf.addAdvice(new CountingAfterReturningAdvice()); 206 pf.addAdvice(cta); 207 Person p = (Person) createAopProxy(pf).getProxy(); 208 209 p.echo(null); 210 assertEquals(0, cta.getCalls()); 211 try { 212 p.echo(new ServletException ()); 213 } 214 catch (ServletException ex) { 215 216 } 217 assertEquals(1, cta.getCalls()); 218 219 Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p); 221 assertNotSame(p, p2); 222 assertEquals(p.getName(), p2.getName()); 223 assertEquals(p.getAge(), p2.getAge()); 224 assertTrue("Deserialized object is an AOP proxy", AopUtils.isAopProxy(p2)); 225 226 Advised a1 = (Advised) p; 227 Advised a2 = (Advised) p2; 228 assertEquals(a1.getAdvisors().length, a2.getAdvisors().length); 230 231 assertEquals("Proxies should be equal, even after one was serialized", p, p2); 233 assertEquals("Proxies should be equal, even after one was serialized", p2, p); 234 235 NopInterceptor ni = new NopInterceptor(); 237 p2.getAge(); 238 assertEquals(0, ni.getCount()); 239 a2.addAdvice(ni); 240 p2.getAge(); 241 assertEquals(1, ni.getCount()); 242 243 cta = (CountingThrowsAdvice) a2.getAdvisors()[3].getAdvice(); 244 p2.echo(null); 245 assertEquals(1, cta.getCalls()); 246 try { 247 p2.echo(new ServletException ()); 248 } 249 catch (ServletException ex) { 250 251 } 252 assertEquals(2, cta.getCalls()); 253 254 } 255 256 261 public void testOneAdvisedObjectCallsAnother() { 262 int age1 = 33; 263 int age2 = 37; 264 265 TestBean target1 = new TestBean(); 266 ProxyFactory pf1 = new ProxyFactory(target1); 267 pf1.setExposeProxy(true); 269 NopInterceptor di1 = new NopInterceptor(); 270 pf1.addAdvice(0, di1); 271 pf1.addAdvice(1, new ProxyMatcherInterceptor()); 272 pf1.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor()); 273 pf1.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor()); 274 pf1.addAdvice(0, ExposeInvocationInterceptor.INSTANCE); 276 ITestBean advised1 = (ITestBean) pf1.getProxy(); 277 advised1.setAge(age1); 279 TestBean target2 = new TestBean(); 280 ProxyFactory pf2 = new ProxyFactory(target2); 281 pf2.setExposeProxy(true); 282 NopInterceptor di2 = new NopInterceptor(); 283 pf2.addAdvice(0, di2); 284 pf2.addAdvice(1, new ProxyMatcherInterceptor()); 285 pf2.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor()); 286 pf2.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor()); 287 pf2.addAdvice(0, ExposeInvocationInterceptor.INSTANCE); 288 ITestBean advised2 = (ITestBean) createProxy(pf2); 290 advised2.setAge(age2); 291 advised1.setSpouse(advised2); 293 assertEquals("Advised one has correct age", age1, advised1.getAge()); assertEquals("Advised two has correct age", age2, advised2.getAge()); 295 assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge()); 298 assertEquals("one was invoked correct number of times", 4, di1.getCount()); 299 assertEquals("one was invoked correct number of times", 3, di2.getCount()); 301 } 302 303 304 public void testReentrance() { 305 int age1 = 33; 306 307 TestBean target1 = new TestBean(); 308 ProxyFactory pf1 = new ProxyFactory(target1); 309 NopInterceptor di1 = new NopInterceptor(); 310 pf1.addAdvice(0, di1); 311 ITestBean advised1 = (ITestBean) createProxy(pf1); 312 advised1.setAge(age1); advised1.setSpouse(advised1); 315 assertEquals("one was invoked correct number of times", 2, di1.getCount()); 316 317 assertEquals("Advised one has correct age", age1, advised1.getAge()); assertEquals("one was invoked correct number of times", 3, di1.getCount()); 319 320 assertEquals("Advised spouse has correct age", age1, advised1.getSpouse().getAge()); 322 323 assertEquals("one was invoked correct number of times", 5, di1.getCount()); 324 } 325 326 public void testTargetCanGetProxy() { 327 NopInterceptor di = new NopInterceptor(); 328 INeedsToSeeProxy target = new TargetChecker(); 329 ProxyFactory proxyFactory = new ProxyFactory(target); 330 proxyFactory.setExposeProxy(true); 331 assertTrue(proxyFactory.isExposeProxy()); 332 333 proxyFactory.addAdvice(0, di); 334 INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(proxyFactory); 335 assertEquals(0, di.getCount()); 336 assertEquals(0, target.getCount()); 337 proxied.incrementViaThis(); 338 assertEquals("Increment happened", 1, target.getCount()); 339 340 assertEquals("Only one invocation via AOP as use of this wasn't proxied", 1, di.getCount()); 341 assertEquals("Increment happened", 1, proxied.getCount()); 343 proxied.incrementViaProxy(); assertEquals("Increment happened", 2, target.getCount()); 345 assertEquals("3 more invocations via AOP as the first call was reentrant through the proxy", 4, di.getCount()); 346 } 347 348 349 public void testTargetCantGetProxyByDefault() { 350 NeedsToSeeProxy et = new NeedsToSeeProxy(); 351 ProxyFactory pf1 = new ProxyFactory(et); 352 assertFalse(pf1.isExposeProxy()); 353 INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(pf1); 354 try { 355 proxied.incrementViaProxy(); 356 fail("Should have failed to get proxy as exposeProxy wasn't set to true"); 357 } 358 catch (AspectException ex) { 359 } 361 } 362 363 public void testContext() throws Throwable { 364 testContext(true); 365 } 366 367 public void testNoContext() throws Throwable { 368 testContext(false); 369 } 370 371 374 private void testContext(final boolean context) throws Throwable { 375 final String s = "foo"; 376 MethodInterceptor mi = new MethodInterceptor() { 378 public Object invoke(MethodInvocation invocation) throws Throwable { 379 if (!context) { 380 assertNoInvocationContext(); 381 } else { 382 assertTrue("have context", ExposeInvocationInterceptor.currentInvocation() != null); 383 } 384 return s; 385 } 386 }; 387 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class }); 388 if (context) { 389 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); 390 } 391 pc.addAdvice(mi); 392 if (requiresTarget()) { 394 pc.setTarget(new TestBean()); 395 } 396 AopProxy aop = createAopProxy(pc); 397 398 assertNoInvocationContext(); 399 ITestBean tb = (ITestBean) aop.getProxy(); 400 assertNoInvocationContext(); 401 assertTrue("correct return value", tb.getName() == s); 402 } 403 404 408 public void testTargetReturnsThis() throws Throwable { 409 TestBean raw = new OwnSpouse(); 411 412 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class }); 413 pc.setTarget(raw); 414 415 ITestBean tb = (ITestBean) createProxy(pc); 416 assertTrue("this return is wrapped in proxy", tb.getSpouse() == tb); 417 } 418 419 442 443 public void testDeclaredException() throws Throwable { 444 final Exception expectedException = new Exception (); 445 MethodInterceptor mi = new MethodInterceptor() { 447 public Object invoke(MethodInvocation invocation) throws Throwable { 448 throw expectedException; 449 } 450 }; 451 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class }); 452 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); 453 pc.addAdvice(mi); 454 455 mockTargetSource.setTarget(new Object ()); 457 pc.setTargetSource(mockTargetSource); 458 AopProxy aop = createAopProxy(pc); 459 460 try { 461 ITestBean tb = (ITestBean) aop.getProxy(); 462 tb.exceptional(expectedException); 464 fail("Should have thrown exception raised by interceptor"); 465 } 466 catch (Exception thrown) { 467 assertEquals("exception matches", expectedException, thrown); 468 } 469 } 470 471 476 public void testUndeclaredCheckedException() throws Throwable { 477 final Exception unexpectedException = new Exception (); 478 MethodInterceptor mi = new MethodInterceptor() { 480 public Object invoke(MethodInvocation invocation) throws Throwable { 481 throw unexpectedException; 482 } 483 }; 484 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class }); 485 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); 486 pc.addAdvice(mi); 487 488 pc.setTarget(new TestBean()); 490 AopProxy aop = createAopProxy(pc); 491 ITestBean tb = (ITestBean) aop.getProxy(); 492 493 try { 494 tb.getAge(); 496 fail("Should have wrapped exception raised by interceptor"); 497 } 498 catch (UndeclaredThrowableException thrown) { 499 assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable()); 500 } 501 catch (Exception ex) { 505 ex.printStackTrace(); 506 fail("Didn't expect exception: " + ex); 507 } 508 } 509 510 public void testUndeclaredUnheckedException() throws Throwable { 511 final RuntimeException unexpectedException = new RuntimeException (); 512 MethodInterceptor mi = new MethodInterceptor() { 514 public Object invoke(MethodInvocation invocation) throws Throwable { 515 throw unexpectedException; 516 } 517 }; 518 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class }); 519 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); 520 pc.addAdvice(mi); 521 522 pc.setTarget(new TestBean()); 524 AopProxy aop = createAopProxy(pc); 525 ITestBean tb = (ITestBean) aop.getProxy(); 526 527 try { 528 tb.getAge(); 530 fail("Should have wrapped exception raised by interceptor"); 531 } 532 catch (RuntimeException thrown) { 533 assertEquals("exception matches", unexpectedException, thrown); 534 } 535 } 539 540 546 public void testTargetCanGetInvocationEvenIfNoAdviceChain() throws Throwable { 547 NeedsToSeeProxy target = new NeedsToSeeProxy(); 548 AdvisedSupport pc = new AdvisedSupport(new Class [] { INeedsToSeeProxy.class } ); 549 pc.setTarget(target); 550 pc.setExposeProxy(true); 551 552 AopProxy aop = createAopProxy(pc); 554 INeedsToSeeProxy proxied = (INeedsToSeeProxy) aop.getProxy(); 555 proxied.incrementViaProxy(); 557 } 558 559 public void testTargetCanGetInvocation() throws Throwable { 560 final InvocationCheckExposedInvocationTestBean expectedTarget = new InvocationCheckExposedInvocationTestBean(); 561 562 AdvisedSupport pc = new AdvisedSupport(new Class [] { ITestBean.class, IOther.class }); 563 pc.addAdvice(ExposeInvocationInterceptor.INSTANCE); 564 TrapTargetInterceptor tii = new TrapTargetInterceptor() { 565 public Object invoke(MethodInvocation invocation) throws Throwable { 566 assertEquals("Target is correct", expectedTarget, invocation.getThis()); 568 return super.invoke(invocation); 569 } 570 }; 571 pc.addAdvice(tii); 572 pc.setTarget(expectedTarget); 573 AopProxy aop = createAopProxy(pc); 574 575 ITestBean tb = (ITestBean) aop.getProxy(); 576 tb.getName(); 577 580 582 } 587 588 591 private void assertNoInvocationContext() { 592 try { 593 ExposeInvocationInterceptor.currentInvocation(); 594 fail("Expected no invocation context"); 595 } catch (AspectException ex) { 596 } 598 } 599 600 603 public void testMixinWithIntroductionAdvisor() throws Throwable { 604 TestBean tb = new TestBean(); 605 ProxyFactory pc = new ProxyFactory(new Class [] { ITestBean.class }); 606 pc.addAdvisor(new LockMixinAdvisor()); 607 pc.setTarget(tb); 608 609 testTestBeanIntroduction(pc); 610 } 611 612 public void testMixinWithIntroductionInfo() throws Throwable { 613 TestBean tb = new TestBean(); 614 ProxyFactory pc = new ProxyFactory(new Class [] { ITestBean.class }); 615 pc.addAdvice(new LockMixin()); 617 pc.setTarget(tb); 618 619 testTestBeanIntroduction(pc); 620 } 621 622 private void testTestBeanIntroduction(ProxyFactory pc) { 623 int newAge = 65; 624 ITestBean itb = (ITestBean) createProxy(pc); 625 itb.setAge(newAge); 626 assertTrue(itb.getAge() == newAge); 627 628 Lockable lockable = (Lockable) itb; 629 assertFalse(lockable.locked()); 630 lockable.lock(); 631 632 assertTrue(itb.getAge() == newAge); 633 try { 634 itb.setAge(1); 635 fail("Setters should fail when locked"); 636 } 637 catch (LockedException ex) { 638 } 640 assertTrue(itb.getAge() == newAge); 641 642 assertTrue(lockable.locked()); 644 lockable.unlock(); 645 itb.setAge(1); 646 assertTrue(itb.getAge() == 1); 647 } 648 649 650 public void testReplaceArgument() throws Throwable { 651 TestBean tb = new TestBean(); 652 ProxyFactory pc = new ProxyFactory(new Class [] { ITestBean.class }); 653 pc.setTarget(tb); 654 pc.addAdvisor(new StringSetterNullReplacementAdvice()); 655 656 ITestBean t = (ITestBean) pc.getProxy(); 657 int newAge = 5; 658 t.setAge(newAge); 659 assertTrue(t.getAge() == newAge); 660 String newName = "greg"; 661 t.setName(newName); 662 assertEquals(newName, t.getName()); 663 664 t.setName(null); 665 assertTrue(t.getName().equals("")); 667 } 668 669 public void testCanCastProxyToProxyConfig() throws Throwable { 670 TestBean tb = new TestBean(); 671 ProxyFactory pc = new ProxyFactory(tb); 672 NopInterceptor di = new NopInterceptor(); 673 pc.addAdvice(0, di); 674 675 ITestBean t = (ITestBean) createProxy(pc); 676 assertEquals(0, di.getCount()); 677 t.setAge(23); 678 assertEquals(23, t.getAge()); 679 assertEquals(2, di.getCount()); 680 681 Advised advised = (Advised) t; 682 assertEquals("Have 1 advisor", 1, advised.getAdvisors().length); 683 assertEquals(di, advised.getAdvisors()[0].getAdvice()); 684 NopInterceptor di2 = new NopInterceptor(); 685 advised.addAdvice(1, di2); 686 t.getName(); 687 assertEquals(3, di.getCount()); 688 assertEquals(1, di2.getCount()); 689 advised.removeAdvisor(0); 691 t.getAge(); 692 assertEquals(3, di.getCount()); 694 assertEquals(2, di2.getCount()); 695 696 CountingBeforeAdvice cba = new CountingBeforeAdvice(); 697 assertEquals(0, cba.getCalls()); 698 advised.addAdvice(cba); 699 t.setAge(16); 700 assertEquals(16, t.getAge()); 701 assertEquals(2, cba.getCalls()); 702 } 703 704 public void testAdviceImplementsIntroductionInfo() throws Throwable { 705 TestBean tb = new TestBean(); 706 String name = "tony"; 707 tb.setName(name); 708 ProxyFactory pc = new ProxyFactory(tb); 709 NopInterceptor di = new NopInterceptor(); 710 pc.addAdvice(di); 711 final long ts = 37; 712 pc.addAdvice(new DelegatingIntroductionInterceptor(new TimeStamped() { 713 public long getTimeStamp() { 714 return ts; 715 } 716 })); 717 718 ITestBean proxied = (ITestBean) createProxy(pc); 719 assertEquals(name, proxied.getName()); 720 TimeStamped intro = (TimeStamped) proxied; 721 assertEquals(ts, intro.getTimeStamp()); 722 } 723 724 public void testCannotAddDynamicIntroductionAdviceExceptInIntroductionAdvice() throws Throwable { 725 TestBean target = new TestBean(); 726 target.setAge(21); 727 ProxyFactory pc = new ProxyFactory(target); 728 try { 729 pc.addAdvice(new DummyIntroductionAdviceImpl()); 730 fail("Shouldn't be able to add introduction interceptor except via introduction advice"); 731 } 732 catch (AopConfigException ex) { 733 assertTrue(ex.getMessage().indexOf("ntroduction") > -1); 734 } 735 ITestBean proxied = (ITestBean) createProxy(pc); 737 assertEquals(target.getAge(), proxied.getAge()); 738 } 739 740 public void |