KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > aop > framework > AbstractAopProxyTests


1 /*
2  * Copyright 2002-2005 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.aop.framework;
18
19 import java.lang.reflect.Method JavaDoc;
20 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.LinkedList JavaDoc;
23 import java.util.List JavaDoc;
24
25 import javax.servlet.ServletException JavaDoc;
26 import javax.transaction.TransactionRequiredException JavaDoc;
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 /**
61  * @author Rod Johnson
62  * @author Juergen Hoeller
63  * @since 13.03.2003
64  */

65 public abstract class AbstractAopProxyTests extends TestCase {
66     
67     protected MockTargetSource mockTargetSource = new MockTargetSource();
68
69     /**
70      * Make a clean target source available if code wants to use it.
71      * The target must be set. Verification will be automatic in tearDown
72      * to ensure that it was used appropriately by code.
73      * @see junit.framework.TestCase#setUp()
74      */

75     protected void setUp() {
76         mockTargetSource.reset();
77     }
78
79     protected void tearDown() {
80         mockTargetSource.verify();
81     }
82     
83     /**
84      * Set in CGLIB or JDK mode.
85      */

86     protected abstract Object JavaDoc createProxy(AdvisedSupport as);
87     
88     protected abstract AopProxy createAopProxy(AdvisedSupport as);
89     
90     /**
91      * Is a target always required?
92      */

93     protected boolean requiresTarget() {
94         return false;
95     }
96     
97     public void testNoInterceptorsAndNoTarget() {
98         AdvisedSupport pc =
99             new AdvisedSupport(new Class JavaDoc[] { ITestBean.class });
100         // Add no interceptors
101
try {
102             AopProxy aop = createAopProxy(pc);
103             aop.getProxy();
104             fail("Shouldn't allow no interceptors");
105         } catch (AopConfigException ex) {
106             // Ok
107
}
108     }
109     
110     /**
111      * Simple test that if we set values we can get them out again.
112      */

113     public void testValuesStick() {
114         int age1 = 33;
115         int age2 = 37;
116         String JavaDoc 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     /**
134      * This is primarily a test for the efficiency of our
135      * usage of CGLIB. If we create too many classes with
136      * CGLIB this will be slow or will run out of memory.
137      */

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         // Set a performance benchmark.
146
// It's pretty generous so as not to cause failures on slow machines.
147
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 JavaDoc {
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 JavaDoc {
177         SerializablePerson sp = new SerializablePerson();
178         assertTrue(SerializationTestUtils.isSerializable(sp));
179         
180         ProxyFactory pf = new ProxyFactory(sp);
181         
182         // This isn't serializable
183
Advice i = new NopInterceptor();
184         pf.addAdvice(i);
185         assertFalse(SerializationTestUtils.isSerializable(i));
186         Object JavaDoc proxy = createAopProxy(pf).getProxy();
187         
188         assertFalse(SerializationTestUtils.isSerializable(proxy));
189     }
190     
191     public void testSerializationSerializableTargetAndAdvice() throws Throwable JavaDoc {
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         // Try various advice types
204
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 JavaDoc());
213         }
214         catch (ServletException JavaDoc ex) {
215             
216         }
217         assertEquals(1, cta.getCalls());
218         
219         // Will throw exception if it fails
220
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         // Check we can manipulate state of p2
229
assertEquals(a1.getAdvisors().length, a2.getAdvisors().length);
230         
231         // This should work as SerializablePerson is equal
232
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         // Check we can add a new advisor to the target
236
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 JavaDoc());
248         }
249         catch (ServletException JavaDoc ex) {
250             
251         }
252         assertEquals(2, cta.getCalls());
253         
254     }
255     
256     /**
257      * Check that the two MethodInvocations necessary are independent and
258      * don't conflict.
259      * Check also proxy exposure.
260      */

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         // Permit proxy and invocation checkers to get context from AopContext
268
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         // Must be first
275
pf1.addAdvice(0, ExposeInvocationInterceptor.INSTANCE);
276         ITestBean advised1 = (ITestBean) pf1.getProxy();
277         advised1.setAge(age1); // = 1 invocation
278

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         //System.err.println(pf2.toProxyConfigString());
289
ITestBean advised2 = (ITestBean) createProxy(pf2);
290         advised2.setAge(age2);
291         advised1.setSpouse(advised2); // = 2 invocations
292

293         assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
294
assertEquals("Advised two has correct age", age2, advised2.getAge());
295         // Means extra call on advised 2
296
assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge()); // = 4 invocations on 1 and another one on 2
297

298         assertEquals("one was invoked correct number of times", 4, di1.getCount());
299         // Got hit by call to advised1.getSpouse().getAge()
300
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); // = 1 invocation
313
advised1.setSpouse(advised1); // = 2 invocations
314

315         assertEquals("one was invoked correct number of times", 2, di1.getCount());
316         
317         assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
318
assertEquals("one was invoked correct number of times", 3, di1.getCount());
319         
320         // = 5 invocations, as reentrant call to spouse is advised also
321
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         // 1 invocation
342
assertEquals("Increment happened", 1, proxied.getCount());
343         proxied.incrementViaProxy(); // 2 invoocations
344
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             // Ok
360
}
361     }
362
363     public void testContext() throws Throwable JavaDoc {
364         testContext(true);
365     }
366
367     public void testNoContext() throws Throwable JavaDoc {
368         testContext(false);
369     }
370
371     /**
372      * @param context if true, want context
373      */

374     private void testContext(final boolean context) throws Throwable JavaDoc {
375         final String JavaDoc s = "foo";
376         // Test return value
377
MethodInterceptor mi = new MethodInterceptor() {
378             public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
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 JavaDoc[] { ITestBean.class });
388         if (context) {
389             pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
390         }
391         pc.addAdvice(mi);
392         // Keep CGLIB happy
393
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     /**
405      * Test that the proxy returns itself when the
406      * target returns <code>this</code>
407      */

408     public void testTargetReturnsThis() throws Throwable JavaDoc {
409         // Test return value
410
TestBean raw = new OwnSpouse();
411     
412         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { 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 /*
420     public void testCanAttach() throws Throwable {
421         final TrapInterceptor tii = new TrapInvocationInterceptor();
422
423         ProxyConfig pc = new ProxyConfigSupport(new Class[] { ITestBean.class }, false);
424         pc.addAdvice(tii);
425         pc.addAdvice(new MethodInterceptor() {
426             public Object invoke(MethodInvocation invocation) throws Throwable {
427                 assertTrue("Saw same interceptor", invocation == tii.invocation);
428                 return null;
429             }
430         });
431         AopProxy aop = new AopProxy(pc, new MethodInvocationFactorySupport());
432
433         ITestBean tb = (ITestBean) aop.getProxy();
434         tb.getSpouse();
435         assertTrue(tii.invocation != null);
436         
437         // TODO strengthen this
438     // assertTrue(tii.invocation.getProxy() == tb);
439         assertTrue(tii.invocation.getThis() == null);
440     }
441 */

442
443     public void testDeclaredException() throws Throwable JavaDoc {
444         final Exception JavaDoc expectedException = new Exception JavaDoc();
445         // Test return value
446
MethodInterceptor mi = new MethodInterceptor() {
447             public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
448                 throw expectedException;
449             }
450         };
451         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { ITestBean.class });
452         pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
453         pc.addAdvice(mi);
454         
455         // We don't care about the object
456
mockTargetSource.setTarget(new Object JavaDoc());
457         pc.setTargetSource(mockTargetSource);
458         AopProxy aop = createAopProxy(pc);
459
460         try {
461             ITestBean tb = (ITestBean) aop.getProxy();
462             // Note: exception param below isn't used
463
tb.exceptional(expectedException);
464             fail("Should have thrown exception raised by interceptor");
465         }
466         catch (Exception JavaDoc thrown) {
467             assertEquals("exception matches", expectedException, thrown);
468         }
469     }
470     
471     /**
472      * An interceptor throws a checked exception not on the method signature.
473      * For efficiency, we don't bother unifying java.lang.reflect and
474      * net.sf.cglib UndeclaredThrowableException
475      */

476     public void testUndeclaredCheckedException() throws Throwable JavaDoc {
477         final Exception JavaDoc unexpectedException = new Exception JavaDoc();
478         // Test return value
479
MethodInterceptor mi = new MethodInterceptor() {
480             public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
481                 throw unexpectedException;
482             }
483         };
484         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { ITestBean.class });
485         pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
486         pc.addAdvice(mi);
487     
488         // We don't care about the object
489
pc.setTarget(new TestBean());
490         AopProxy aop = createAopProxy(pc);
491         ITestBean tb = (ITestBean) aop.getProxy();
492         
493         try {
494             // Note: exception param below isn't used
495
tb.getAge();
496             fail("Should have wrapped exception raised by interceptor");
497         }
498         catch (UndeclaredThrowableException JavaDoc thrown) {
499             assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable());
500         }
501         //catch (net.sf.cglib.proxy.UndeclaredThrowableException thrown) {
502
// assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable());
503
//}
504
catch (Exception JavaDoc ex) {
505             ex.printStackTrace();
506             fail("Didn't expect exception: " + ex);
507         }
508     }
509     
510     public void testUndeclaredUnheckedException() throws Throwable JavaDoc {
511         final RuntimeException JavaDoc unexpectedException = new RuntimeException JavaDoc();
512         // Test return value
513
MethodInterceptor mi = new MethodInterceptor() {
514             public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
515                 throw unexpectedException;
516             }
517         };
518         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { ITestBean.class });
519         pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
520         pc.addAdvice(mi);
521     
522         // We don't care about the object
523
pc.setTarget(new TestBean());
524         AopProxy aop = createAopProxy(pc);
525         ITestBean tb = (ITestBean) aop.getProxy();
526         
527         try {
528             // Note: exception param below isn't used
529
tb.getAge();
530             fail("Should have wrapped exception raised by interceptor");
531         }
532         catch (RuntimeException JavaDoc thrown) {
533             assertEquals("exception matches", unexpectedException, thrown);
534         }
535         //catch (net.sf.cglib.proxy.UndeclaredThrowableException thrown) {
536
// assertEquals("exception matches", unexpectedException, thrown.getUndeclaredThrowable());
537
//}
538
}
539     
540     /**
541      * Check that although a method is eligible for advice chain optimization and
542      * direct reflective invocation, it doesn't happen if we've asked to see the proxy,
543      * so as to guarantee a consistent programming model.
544      * @throws Throwable
545      */

546     public void testTargetCanGetInvocationEvenIfNoAdviceChain() throws Throwable JavaDoc {
547         NeedsToSeeProxy target = new NeedsToSeeProxy();
548         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { INeedsToSeeProxy.class } );
549         pc.setTarget(target);
550         pc.setExposeProxy(true);
551         
552         // Now let's try it with the special target
553
AopProxy aop = createAopProxy(pc);
554         INeedsToSeeProxy proxied = (INeedsToSeeProxy) aop.getProxy();
555         // It will complain if it can't get the proxy
556
proxied.incrementViaProxy();
557     }
558     
559     public void testTargetCanGetInvocation() throws Throwable JavaDoc {
560         final InvocationCheckExposedInvocationTestBean expectedTarget = new InvocationCheckExposedInvocationTestBean();
561         
562         AdvisedSupport pc = new AdvisedSupport(new Class JavaDoc[] { ITestBean.class, IOther.class });
563         pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
564         TrapTargetInterceptor tii = new TrapTargetInterceptor() {
565             public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
566                 // Assert that target matches BEFORE invocation returns
567
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         // Not safe to trap invocation
578
//assertTrue(tii.invocation == target.invocation);
579

580         //assertTrue(target.invocation.getProxy() == tb);
581

582     // ((IOther) tb).absquatulate();
583
//MethodInvocation minv = tii.invocation;
584
//assertTrue("invoked on iother, not " + minv.getMethod().getDeclaringClass(), minv.getMethod().getDeclaringClass() == IOther.class);
585
//assertTrue(target.invocation == tii.invocation);
586
}
587
588     /**
589      * Throw an exception if there is an Invocation.
590      */

591     private void assertNoInvocationContext() {
592         try {
593             ExposeInvocationInterceptor.currentInvocation();
594             fail("Expected no invocation context");
595         } catch (AspectException ex) {
596             // ok
597
}
598     }
599
600     /**
601      * Test stateful interceptor
602      */

603     public void testMixinWithIntroductionAdvisor() throws Throwable JavaDoc {
604         TestBean tb = new TestBean();
605         ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { ITestBean.class });
606         pc.addAdvisor(new LockMixinAdvisor());
607         pc.setTarget(tb);
608         
609         testTestBeanIntroduction(pc);
610     }
611     
612     public void testMixinWithIntroductionInfo() throws Throwable JavaDoc {
613         TestBean tb = new TestBean();
614         ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { ITestBean.class });
615         // We don't use an IntroductionAdvisor, we can just add an advice that implements IntroductionInfo
616
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             // ok
639
}
640         assertTrue(itb.getAge() == newAge);
641         
642         // Unlock
643
assertTrue(lockable.locked());
644         lockable.unlock();
645         itb.setAge(1);
646         assertTrue(itb.getAge() == 1);
647     }
648     
649     
650     public void testReplaceArgument() throws Throwable JavaDoc {
651         TestBean tb = new TestBean();
652         ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { 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 JavaDoc newName = "greg";
661         t.setName(newName);
662         assertEquals(newName, t.getName());
663         
664         t.setName(null);
665         // Null replacement magic should work
666
assertTrue(t.getName().equals(""));
667     }
668     
669     public void testCanCastProxyToProxyConfig() throws Throwable JavaDoc {
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         // will remove di
690
advised.removeAdvisor(0);
691         t.getAge();
692         // Unchanged
693
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 JavaDoc {
705         TestBean tb = new TestBean();
706         String JavaDoc 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 JavaDoc {
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         // Check it still works: proxy factory state shouldn't have been corrupted
736
ITestBean proxied = (ITestBean) createProxy(pc);
737         assertEquals(target.getAge(), proxied.getAge());
738     }
739     
740     public void testRejectsBogusDynamicIntroductionAdviceWithNoAdapter() throws Throwable JavaDoc {
741         TestBean target = new TestBean();
742         target.setAge(21);
743         ProxyFactory pc = new ProxyFactory(target);
744         pc.addAdvisor(new DefaultIntroductionAdvisor(new DummyIntroductionAdviceImpl(), Comparable JavaDoc.class));
745         try {
746             // TODO May fail on either call: may want to tighten up definition
747
ITestBean proxied = (ITestBean) createProxy(pc);
748             proxied.getName();
749             fail("Bogus introduction");
750         }
751         catch (Exception JavaDoc ex) {
752             // TODO used to catch UnknownAdviceTypeException, but
753
// with CGLIB some errors are in proxy creation and are wrapped
754
// in aspect exception. Error message is still fine.
755
//assertTrue(ex.getMessage().indexOf("ntroduction") > -1);
756
}
757     }
758     
759     /**
760      * Check that the introduction advice isn't allowed to introduce interfaces
761      * that are unsupported by the IntroductionInterceptor.
762      */

763     public void testCannotAddIntroductionAdviceWithUnimplementedInterface() throws Throwable JavaDoc {
764         TestBean target = new TestBean();
765         target.setAge(21);
766         ProxyFactory pc = new ProxyFactory(target);
767         try {
768             pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), ITestBean.class));
769             fail("Shouldn't be able to add introduction advice introducing an unimplemented interface");
770         }
771         catch (IllegalArgumentException JavaDoc ex) {
772             //assertTrue(ex.getMessage().indexOf("ntroduction") > -1);
773
}
774         // Check it still works: proxy factory state shouldn't have been corrupted
775
ITestBean proxied = (ITestBean) createProxy(pc);
776         assertEquals(target.getAge(), proxied.getAge());
777     }
778     
779     /**
780      * Note that an introduction can't throw an unexpected checked exception,
781      * as it's constained by the interface.
782      */

783     public void testIntroductionThrowsUncheckedException() throws Throwable JavaDoc {
784         TestBean target = new TestBean();
785         target.setAge(21);
786         ProxyFactory pc = new ProxyFactory(target);
787         
788         class MyDi extends DelegatingIntroductionInterceptor implements TimeStamped {
789             /**
790              * @see org.springframework.aop.framework.TimeStamped#getTimeStamp()
791              */

792             public long getTimeStamp() {
793                 throw new UnsupportedOperationException JavaDoc();
794             }
795         }
796         pc.addAdvisor(new DefaultIntroductionAdvisor(new MyDi()));
797         
798         TimeStamped ts = (TimeStamped) createProxy(pc);
799         try {
800             ts.getTimeStamp();
801             fail("Should throw UnsupportedOperationException");
802         }
803         catch (UnsupportedOperationException JavaDoc ex) {
804         }
805     }
806     
807     /**
808      * Should only be able to introduce interfaces, not classes.
809      */

810     public void testCannotAddIntroductionAdviceToIntroduceClass() throws Throwable JavaDoc {
811         TestBean target = new TestBean();
812         target.setAge(21);
813         ProxyFactory pc = new ProxyFactory(target);
814         try {
815             pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), TestBean.class));
816             fail("Shouldn't be able to add introduction advice that introduces a class, rather than an interface");
817         }
818         catch (IllegalArgumentException JavaDoc ex) {
819             assertTrue(ex.getMessage().indexOf("interface") > -1);
820         }
821         // Check it still works: proxy factory state shouldn't have been corrupted
822
ITestBean proxied = (ITestBean) createProxy(pc);
823         assertEquals(target.getAge(), proxied.getAge());
824     }
825     
826     public void testCannotAddInterceptorWhenFrozen() throws Throwable JavaDoc {
827         TestBean target = new TestBean();
828         target.setAge(21);
829         ProxyFactory pc = new ProxyFactory(target);
830         assertFalse(pc.isFrozen());
831         pc.addAdvice(new NopInterceptor());
832         ITestBean proxied = (ITestBean) createProxy(pc);
833         pc.setFrozen(true);
834         try {
835             pc.addAdvice(0, new NopInterceptor());
836             fail("Shouldn't be able to add interceptor when frozen");
837         }
838         catch (AopConfigException ex) {
839             assertTrue(ex.getMessage().indexOf("frozen") > -1);
840         }
841         // Check it still works: proxy factory state shouldn't have been corrupted
842
assertEquals(target.getAge(), proxied.getAge());
843         assertEquals(1, ((Advised) proxied).getAdvisors().length);
844     }
845     
846     /**
847      * Check that casting to Advised can't get around advice freeze.
848      */

849     public void testCannotAddAdvisorWhenFrozenUsingCast() throws Throwable JavaDoc {
850         TestBean target = new TestBean();
851         target.setAge(21);
852         ProxyFactory pc = new ProxyFactory(target);
853         assertFalse(pc.isFrozen());
854         pc.addAdvice(new NopInterceptor());
855         ITestBean proxied = (ITestBean) createProxy(pc);
856         pc.setFrozen(true);
857         Advised advised = (Advised) proxied;
858         
859         assertTrue(pc.isFrozen());
860         try {
861             advised.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
862             fail("Shouldn't be able to add Advisor when frozen");
863         }
864         catch (AopConfigException ex) {
865             assertTrue(ex.getMessage().indexOf("frozen") > -1);
866         }
867         // Check it still works: proxy factory state shouldn't have been corrupted
868
assertEquals(target.getAge(), proxied.getAge());
869         assertEquals(1, advised.getAdvisors().length);
870     }
871     
872     public void testCannotRemoveAdvisorWhenFrozen() throws Throwable JavaDoc {
873         TestBean target = new TestBean();
874         target.setAge(21);
875         ProxyFactory pc = new ProxyFactory(target);
876         assertFalse(pc.isFrozen());
877         pc.addAdvice(new NopInterceptor());
878         ITestBean proxied = (ITestBean) createProxy(pc);
879         pc.setFrozen(true);
880         Advised advised = (Advised) proxied;
881     
882         assertTrue(pc.isFrozen());
883         try {
884             advised.removeAdvisor(0);
885             fail("Shouldn't be able to remove Advisor when frozen");
886         }
887         catch (AopConfigException ex) {
888             assertTrue(ex.getMessage().indexOf("frozen") > -1);
889         }
890         // Didn't get removed
891
assertEquals(1, advised.getAdvisors().length);
892         pc.setFrozen(false);
893         // Can now remove it
894
advised.removeAdvisor(0);
895         // Check it still works: proxy factory state shouldn't have been corrupted
896
assertEquals(target.getAge(), proxied.getAge());
897         assertEquals(0, advised.getAdvisors().length);
898     }
899     
900     public void testUseAsHashKey() {
901         TestBean target1 = new TestBean();
902         ProxyFactory pf1 = new ProxyFactory(target1);
903         pf1.addAdvice(new NopInterceptor());
904         ITestBean proxy1 = (ITestBean) createProxy(pf1);
905         
906         TestBean target2 = new TestBean();
907         ProxyFactory pf2 = new ProxyFactory(target2);
908         pf2.addAdvisor(new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor()));
909         ITestBean proxy2 = (ITestBean) createProxy(pf2);
910         
911         HashMap JavaDoc h = new HashMap JavaDoc();
912         Object JavaDoc value1 = new Object JavaDoc();
913         Object JavaDoc value2 = new Object JavaDoc();
914         assertNull(h.get(proxy1));
915         h.put(proxy1, value1);
916         h.put(proxy2, value2);
917         assertEquals(h.get(proxy1), value1);
918         assertEquals(h.get(proxy2), value2);
919     }
920     
921     /**
922      * Check that the string is informative.
923      */

924     public void testProxyConfigString() {
925         TestBean target = new TestBean();
926         ProxyFactory pc = new ProxyFactory(target);
927         pc.setInterfaces(new Class JavaDoc[] { ITestBean.class } );
928         pc.addAdvice(new NopInterceptor());
929         MethodBeforeAdvice mba = new CountingBeforeAdvice();
930         Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut(), mba);
931         pc.addAdvisor(advisor);
932         ITestBean proxied = (ITestBean) createProxy(pc);
933         
934         String JavaDoc proxyConfigString = ((Advised) proxied).toProxyConfigString();
935         assertTrue(proxyConfigString.indexOf(advisor.toString()) != -1);
936         assertTrue(proxyConfigString.indexOf("1 interface") != -1);
937     }
938     
939     public void testCanPreventCastToAdvisedUsingOpaque() {
940         TestBean target = new TestBean();
941         ProxyFactory pc = new ProxyFactory(target);
942         pc.setInterfaces(new Class JavaDoc[] { ITestBean.class } );
943         pc.addAdvice(new NopInterceptor());
944         CountingBeforeAdvice mba = new CountingBeforeAdvice();
945         Advisor advisor = new DefaultPointcutAdvisor(new NameMatchMethodPointcut().addMethodName("setAge"), mba);
946         pc.addAdvisor(advisor);
947         assertFalse("Opaque defaults to false", pc.isOpaque());
948         pc.setOpaque(true);
949         assertTrue("Opaque now true for this config", pc.isOpaque());
950         ITestBean proxied = (ITestBean) createProxy(pc);
951         proxied.setAge(10);
952         assertEquals(10, proxied.getAge());
953         assertEquals(1, mba.getCalls());
954         
955         assertFalse("Cannot be cast to Advised", proxied instanceof Advised);
956     }
957     
958     public void testAdviceSupportListeners() throws Throwable JavaDoc {
959         TestBean target = new TestBean();
960         target.setAge(21);
961         
962         ProxyFactory pc = new ProxyFactory(target);
963         CountingAdvisorListener l = new CountingAdvisorListener(pc);
964         pc.addListener(l);
965         RefreshCountingAdvisorChainFactory acf = new RefreshCountingAdvisorChainFactory();
966         // Should be automatically added as a listener
967
pc.setAdvisorChainFactory(acf);
968         assertFalse(pc.isActive());
969         assertEquals(0, l.activates);
970         assertEquals(0, acf.refreshes);
971         ITestBean proxied = (ITestBean) createProxy(pc);
972         assertEquals(1, acf.refreshes);
973         assertEquals(1, l.activates);
974         assertTrue(pc.isActive());
975         assertEquals(target.getAge(), proxied.getAge());
976         assertEquals(0, l.adviceChanges);
977         NopInterceptor di = new NopInterceptor();
978         pc.addAdvice(0, di);
979         assertEquals(1, l.adviceChanges);
980         assertEquals(2, acf.refreshes);
981         assertEquals(target.getAge(), proxied.getAge());
982         pc.removeAdvice(di);
983         assertEquals(2, l.adviceChanges);
984         assertEquals(3, acf.refreshes);
985         assertEquals(target.getAge(), proxied.getAge());
986         pc.getProxy();
987         assertEquals(1, l.activates);
988         
989         pc.removeListener(l);
990         assertEquals(2, l.adviceChanges);
991         pc.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
992         // No longer counting
993
assertEquals(2, l.adviceChanges);
994     }
995     
996     public void testExistingProxyChangesTarget() throws Throwable JavaDoc {
997         TestBean tb1 = new TestBean();
998         tb1.setAge(33);
999         
1000        TestBean tb2 = new TestBean();
1001        tb2.setAge(26);
1002        tb2.setName("Juergen");
1003        TestBean tb3 = new TestBean();
1004        tb3.setAge(37);
1005        ProxyFactory pc = new ProxyFactory(tb1);
1006        NopInterceptor nop = new NopInterceptor();
1007        pc.addAdvice(nop);
1008        ITestBean proxy = (ITestBean) createProxy(pc);
1009        assertEquals(nop.getCount(), 0);
1010        assertEquals(tb1.getAge(), proxy.getAge());
1011        assertEquals(nop.getCount(), 1);
1012        // Change to a new static target
1013
pc.setTarget(tb2);
1014        assertEquals(tb2.getAge(), proxy.getAge());
1015        assertEquals(nop.getCount(), 2);
1016        
1017        // Change to a new dynamic target
1018
HotSwappableTargetSource hts = new HotSwappableTargetSource(tb3);
1019        pc.setTargetSource(hts);
1020        assertEquals(tb3.getAge(), proxy.getAge());
1021        assertEquals(nop.getCount(), 3);
1022        hts.swap(tb1);
1023        assertEquals(tb1.getAge(), proxy.getAge());
1024        tb1.setName("Colin");
1025        assertEquals(tb1.getName(), proxy.getName());
1026        assertEquals(nop.getCount(), 5);
1027        
1028        // Change back, relying on casting to Advised
1029
Advised advised = (Advised) proxy;
1030        assertSame(hts, advised.getTargetSource());
1031        SingletonTargetSource sts = new SingletonTargetSource(tb2);
1032        advised.setTargetSource(sts);
1033        assertEquals(tb2.getName(), proxy.getName());
1034        assertSame(sts, advised.getTargetSource());
1035        assertEquals(tb2.getAge(), proxy.getAge());
1036    }
1037    
1038    
1039    public static class CountingAdvisorListener implements AdvisedSupportListener {
1040
1041        public int adviceChanges;
1042        public int activates;
1043        private AdvisedSupport expectedSource;
1044        
1045        public CountingAdvisorListener(AdvisedSupport expectedSource) {
1046            this.expectedSource = expectedSource;
1047        }
1048        
1049        public void adviceChanged(AdvisedSupport as) {
1050            assertEquals(expectedSource, as);
1051            ++adviceChanges;
1052        }
1053
1054        public void activated(AdvisedSupport as) {
1055            assertEquals(expectedSource, as);
1056            ++activates;
1057        }
1058    }
1059
1060
1061    public static class RefreshCountingAdvisorChainFactory implements AdvisorChainFactory {
1062
1063        public int refreshes;
1064        
1065        public void adviceChanged(AdvisedSupport pc) {
1066            ++refreshes;
1067        }
1068
1069        public List JavaDoc getInterceptorsAndDynamicInterceptionAdvice(Advised pc, Object JavaDoc proxy, Method JavaDoc method, Class JavaDoc targetClass) {
1070            return AdvisorChainFactoryUtils.calculateInterceptorsAndDynamicInterceptionAdvice(pc, proxy, method, targetClass);
1071        }
1072        
1073        public void activated(AdvisedSupport as) {
1074            ++refreshes;
1075        }
1076    }
1077
1078
1079    /**
1080     * Fires on setter methods that take a string. Replaces null arg with "".
1081     */

1082    public static class StringSetterNullReplacementAdvice extends DynamicMethodMatcherPointcutAdvisor {
1083        
1084        private static MethodInterceptor cleaner = new MethodInterceptor() {
1085            public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1086                // We know it can only be invoked if there's a single parameter of type string
1087
mi.getArguments()[0] = "";
1088                return mi.proceed();
1089            }
1090        };
1091        
1092        public StringSetterNullReplacementAdvice() {
1093            super(cleaner);
1094        }
1095
1096        public boolean matches(Method JavaDoc m, Class JavaDoc targetClass, Object JavaDoc[] args){//, AttributeRegistry attributeRegistry) {
1097
return args[0] == null;
1098        }
1099
1100        public boolean matches(Method JavaDoc m, Class JavaDoc targetClass){//, AttributeRegistry attributeRegistry) {
1101
return m.getName().startsWith("set") &&
1102                m.getParameterTypes().length == 1 &&
1103                m.getParameterTypes()[0].equals(String JavaDoc.class);
1104        }
1105    }
1106    
1107    
1108    public void testDynamicMethodPointcutThatAlwaysAppliesStatically() throws Throwable JavaDoc {
1109        TestBean tb = new TestBean();
1110        ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { ITestBean.class });
1111        TestDynamicPointcutAdvice dp = new TestDynamicPointcutAdvice(new NopInterceptor(), "getAge");
1112        pc.addAdvisor(dp);
1113        pc.setTarget(tb);
1114        ITestBean it = (ITestBean) createProxy(pc);
1115        assertEquals(dp.count, 0);
1116        int age = it.getAge();
1117        assertEquals(dp.count, 1);
1118        it.setAge(11);
1119        assertEquals(it.getAge(), 11);
1120        assertEquals(dp.count, 2);
1121    }
1122    
1123    public void testDynamicMethodPointcutThatAppliesStaticallyOnlyToSetters() throws Throwable JavaDoc {
1124        TestBean tb = new TestBean();
1125        ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { ITestBean.class });
1126        // Could apply dynamically to getAge/setAge but not to getName
1127
TestDynamicPointcutAdvice dp = new TestDynamicPointcutForSettersOnly(new NopInterceptor(), "Age");
1128        pc.addAdvisor(dp);
1129        this.mockTargetSource.setTarget(tb);
1130        pc.setTargetSource(mockTargetSource);
1131        ITestBean it = (ITestBean) createProxy(pc);
1132        assertEquals(dp.count, 0);
1133        int age = it.getAge();
1134        // Statically vetoed
1135
assertEquals(0, dp.count);
1136        it.setAge(11);
1137        assertEquals(it.getAge(), 11);
1138        assertEquals(dp.count, 1);
1139        // Applies statically but not dynamically
1140
it.setName("joe");
1141        assertEquals(dp.count, 1);
1142    }
1143
1144    public void testStaticMethodPointcut() throws Throwable JavaDoc {
1145        TestBean tb = new TestBean();
1146        ProxyFactory pc = new ProxyFactory(new Class JavaDoc[] { ITestBean.class });
1147        NopInterceptor di = new NopInterceptor();
1148        TestStaticPointcutAdvice sp = new TestStaticPointcutAdvice(di, "getAge");
1149        pc.addAdvisor(sp);
1150        pc.setTarget(tb);
1151        ITestBean it = (ITestBean) createProxy(pc);
1152        assertEquals(di.getCount(), 0);
1153        int age = it.getAge();
1154        assertEquals(di.getCount(), 1);
1155        it.setAge(11);
1156        assertEquals(it.getAge(), 11);
1157        assertEquals(di.getCount(), 2);
1158    }
1159    
1160    /**
1161     * There are times when we want to call proceed() twice.
1162     * We can do this if we clone the invocation.
1163     */

1164    public void testCloneInvocationToProceedThreeTimes() throws Throwable JavaDoc {
1165        TestBean tb = new TestBean();
1166        ProxyFactory pc = new ProxyFactory(tb);
1167        pc.addInterface(ITestBean.class);
1168        
1169        MethodInterceptor twoBirthdayInterceptor = new MethodInterceptor() {
1170            public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1171                // Clone the invocation to proceed three times
1172
// "The Moor's Last Sigh": this technology can cause premature aging
1173
MethodInvocation clone1 = ((ReflectiveMethodInvocation) mi).invocableClone();
1174                MethodInvocation clone2 = ((ReflectiveMethodInvocation) mi).invocableClone();
1175                clone1.proceed();
1176                clone2.proceed();
1177                return mi.proceed();
1178            }
1179        };
1180        StaticMethodMatcherPointcutAdvisor advisor = new StaticMethodMatcherPointcutAdvisor(twoBirthdayInterceptor) {
1181            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1182                return "haveBirthday".equals(m.getName());
1183            }
1184        };
1185        pc.addAdvisor(advisor);
1186        ITestBean it = (ITestBean) createProxy(pc);
1187        
1188        final int age = 20;
1189        it.setAge(age);
1190        assertEquals(age, it.getAge());
1191        // Should return the age before the third, AOP-induced birthday
1192
assertEquals(age + 2, it.haveBirthday());
1193        // Return the final age produced by 3 birthdays
1194
assertEquals(age + 3, it.getAge());
1195    }
1196    
1197    /**
1198     * We want to change the arguments on a clone: it shouldn't affect the original.
1199     */

1200    public void testCanChangeArgumentsIndependentlyOnClonedInvocation() throws Throwable JavaDoc {
1201        TestBean tb = new TestBean();
1202        ProxyFactory pc = new ProxyFactory(tb);
1203        pc.addInterface(ITestBean.class);
1204        
1205        /**
1206         * Changes the name, then changes it back.
1207         */

1208        MethodInterceptor nameReverter = new MethodInterceptor() {
1209            public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1210                MethodInvocation clone = ((ReflectiveMethodInvocation) mi).invocableClone();
1211                String JavaDoc oldName = ((ITestBean) mi.getThis()).getName();
1212                clone.getArguments()[0] = oldName;
1213                // Original method invocation should be unaffected by changes to argument list of clone
1214
mi.proceed();
1215                return clone.proceed();
1216            }
1217        };
1218        
1219        class NameSaver implements MethodInterceptor {
1220            private List JavaDoc names = new LinkedList JavaDoc();
1221            
1222            public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1223                names.add(mi.getArguments()[0]);
1224                return mi.proceed();
1225            }
1226        }
1227
1228        NameSaver saver = new NameSaver();
1229        
1230        pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, nameReverter));
1231        pc.addAdvisor(new DefaultPointcutAdvisor(Pointcuts.SETTERS, saver));
1232        ITestBean it = (ITestBean) createProxy(pc);
1233        
1234        String JavaDoc name1 = "tony";
1235        String JavaDoc name2 = "gordon";
1236        
1237        tb.setName(name1);
1238        assertEquals(name1, tb.getName());
1239        
1240        it.setName(name2);
1241        // NameReverter saved it back
1242
assertEquals(name1, it.getName());
1243        assertEquals(2, saver.names.size());
1244        assertEquals(name2, saver.names.get(0));
1245        assertEquals(name1, saver.names.get(1));
1246    }
1247    
1248    public static interface IOverloads {
1249        void overload();
1250        int overload(int i);
1251        String JavaDoc overload(String JavaDoc foo);
1252        void noAdvice();
1253    }
1254    
1255    public static class Overloads implements IOverloads {
1256        public void overload() {
1257        }
1258        public int overload(int i) {
1259            return i;
1260        }
1261        public String JavaDoc overload(String JavaDoc s) {
1262            return s;
1263        }
1264        public void noAdvice() {
1265        }
1266    }
1267    
1268    public void testOverloadedMethodsWithDifferentAdvice() throws Throwable JavaDoc {
1269        Overloads target = new Overloads();
1270        ProxyFactory pc = new ProxyFactory(target);
1271        NopInterceptor overLoadVoids = new NopInterceptor();
1272        pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadVoids) {
1273            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1274                return m.getName().equals("overload") && m.getParameterTypes().length == 0;
1275            }
1276        });
1277        NopInterceptor overLoadInts = new NopInterceptor();
1278        pc.addAdvisor(new StaticMethodMatcherPointcutAdvisor(overLoadInts) {
1279            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1280                return m.getName().equals("overload") && m.getParameterTypes().length == 1 &&
1281                    m.getParameterTypes()[0].equals(int.class);
1282            }
1283        });
1284
1285        IOverloads proxy = (IOverloads) createProxy(pc);
1286        assertEquals(0, overLoadInts.getCount());
1287        assertEquals(0, overLoadVoids.getCount());
1288        proxy.overload();
1289        assertEquals(0, overLoadInts.getCount());
1290        assertEquals(1, overLoadVoids.getCount());
1291        assertEquals(25, proxy.overload(25));
1292        assertEquals(1, overLoadInts.getCount());
1293        assertEquals(1, overLoadVoids.getCount());
1294        proxy.noAdvice();
1295        assertEquals(1, overLoadInts.getCount());
1296        assertEquals(1, overLoadVoids.getCount());
1297    }
1298
1299    public void testEquals() {
1300        IOther a = new AllInstancesAreEqual();
1301        IOther b = new AllInstancesAreEqual();
1302        NopInterceptor i1 = new NopInterceptor();
1303        NopInterceptor i2 = new NopInterceptor();
1304        ProxyFactory pfa = new ProxyFactory(a);
1305        pfa.addAdvice(i1);
1306        ProxyFactory pfb = new ProxyFactory(b);
1307        pfb.addAdvice(i2);
1308        IOther proxyA = (IOther) createProxy(pfa);
1309        IOther proxyB = (IOther) createProxy(pfb);
1310    
1311        assertEquals(pfa.getAdvisors().length, pfb.getAdvisors().length);
1312    
1313        assertTrue(a.equals(b));
1314        assertTrue(i1.equals(i2));
1315        assertTrue(proxyA.equals(proxyB));
1316        //assertTrue(a.equals(proxyA));
1317
assertFalse(proxyA.equals(a));
1318    
1319        // Equality checks were handled by the proxy
1320
assertEquals(0, i1.getCount());
1321    
1322        // When we invoke A, it's NopInterceptor will have count == 1
1323
// and won't think it's equal to B's NopInterceptor
1324
proxyA.absquatulate();
1325        assertEquals(1, i1.getCount());
1326        assertFalse(proxyA.equals(proxyB));
1327    }
1328    
1329    public void testBeforeAdvisorIsInvoked() {
1330        CountingBeforeAdvice cba = new CountingBeforeAdvice();
1331        Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cba) {
1332            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1333                return m.getParameterTypes().length == 0;
1334            }
1335        };
1336        TestBean target = new TestBean();
1337        target.setAge(80);
1338        ProxyFactory pf = new ProxyFactory(target);
1339        pf.addAdvice(new NopInterceptor());
1340        pf.addAdvisor(matchesNoArgs);
1341        assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]);
1342        ITestBean proxied = (ITestBean) createProxy(pf);
1343        assertEquals(0, cba.getCalls());
1344        assertEquals(0, cba.getCalls("getAge"));
1345        assertEquals(target.getAge(), proxied.getAge());
1346        assertEquals(1, cba.getCalls());
1347        assertEquals(1, cba.getCalls("getAge"));
1348        assertEquals(0, cba.getCalls("setAge"));
1349        // Won't be advised
1350
proxied.setAge(26);
1351        assertEquals(1, cba.getCalls());
1352        assertEquals(26, proxied.getAge());
1353    }
1354    
1355    public void testMultiAdvice() throws Throwable JavaDoc {
1356        CountingMultiAdvice cca = new CountingMultiAdvice();
1357        Advisor matchesNoArgs = new StaticMethodMatcherPointcutAdvisor(cca) {
1358            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1359                return m.getParameterTypes().length == 0 || "exceptional".equals(m.getName());
1360            }
1361        };
1362        TestBean target = new TestBean();
1363        target.setAge(80);
1364        ProxyFactory pf = new ProxyFactory(target);
1365        pf.addAdvice(new NopInterceptor());
1366        pf.addAdvisor(matchesNoArgs);
1367        assertEquals("Advisor was added", matchesNoArgs, pf.getAdvisors()[1]);
1368        ITestBean proxied = (ITestBean) createProxy(pf);
1369
1370        /* TODO: support multiple Advice interfaces for same object
1371        assertEquals(0, cca.getCalls());
1372        assertEquals(0, cca.getCalls("getAge"));
1373        assertEquals(target.getAge(), proxied.getAge());
1374        assertEquals(2, cca.getCalls());
1375        assertEquals(2, cca.getCalls("getAge"));
1376        assertEquals(0, cca.getCalls("setAge"));
1377        // Won't be advised
1378        proxied.setAge(26);
1379        assertEquals(2, cca.getCalls());
1380        assertEquals(26, proxied.getAge());
1381        assertEquals(4, cca.getCalls());
1382        try {
1383            proxied.exceptional(new IllegalStateException());
1384            fail("Should have thrown IllegalStateException");
1385        }
1386        catch (IllegalStateException ex) {
1387            // expected
1388        }
1389        assertEquals(6, cca.getCalls());
1390        */

1391    }
1392
1393    public void testBeforeAdviceThrowsException() {
1394        final RuntimeException JavaDoc rex = new RuntimeException JavaDoc();
1395        CountingBeforeAdvice ba = new CountingBeforeAdvice() {
1396            public void before(Method JavaDoc m, Object JavaDoc[] args, Object JavaDoc target) throws Throwable JavaDoc {
1397                super.before(m, args, target);
1398                if (m.getName().startsWith("set"))
1399                    throw rex;
1400            }
1401        };
1402
1403        TestBean target = new TestBean();
1404        target.setAge(80);
1405        NopInterceptor nop1 = new NopInterceptor();
1406        NopInterceptor nop2 = new NopInterceptor();
1407        ProxyFactory pf = new ProxyFactory(target);
1408        pf.addAdvice(nop1);
1409        pf.addAdvice(ba);
1410        pf.addAdvice(nop2);
1411        ITestBean proxied = (ITestBean) createProxy(pf);
1412        // Won't throw an exception
1413
assertEquals(target.getAge(), proxied.getAge());
1414        assertEquals(1, ba.getCalls());
1415        assertEquals(1, ba.getCalls("getAge"));
1416        assertEquals(1, nop1.getCount());
1417        assertEquals(1, nop2.getCount());
1418        // Will fail, after invoking Nop1
1419
try {
1420            proxied.setAge(26);
1421            fail("before advice should have ended chain");
1422        }
1423        catch (RuntimeException JavaDoc ex) {
1424            assertEquals(rex, ex);
1425        }
1426        assertEquals(2, ba.getCalls());
1427        assertEquals(2, nop1.getCount());
1428        // Nop2 didn't get invoked when the exception was thrown
1429
assertEquals(1, nop2.getCount());
1430        // Shouldn't have changed value in joinpoint
1431
assertEquals(target.getAge(), proxied.getAge());
1432    }
1433
1434
1435    public void testAfterReturningAdvisorIsInvoked() {
1436        class SummingAfterAdvice implements AfterReturningAdvice {
1437            public int sum;
1438            public void afterReturning(Object JavaDoc returnValue, Method JavaDoc m, Object JavaDoc[] args, Object JavaDoc target) throws Throwable JavaDoc {
1439                sum += ((Integer JavaDoc) returnValue).intValue();
1440            }
1441        }
1442        SummingAfterAdvice aa = new SummingAfterAdvice();
1443        Advisor matchesInt = new StaticMethodMatcherPointcutAdvisor(aa) {
1444            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1445                return m.getReturnType() == int.class;
1446            }
1447        };
1448        TestBean target = new TestBean();
1449        ProxyFactory pf = new ProxyFactory(target);
1450        pf.addAdvice(new NopInterceptor());
1451        pf.addAdvisor(matchesInt);
1452        assertEquals("Advisor was added", matchesInt, pf.getAdvisors()[1]);
1453        ITestBean proxied = (ITestBean) createProxy(pf);
1454        assertEquals(0, aa.sum);
1455        int i1 = 12;
1456        int i2 = 13;
1457
1458        // Won't be advised
1459
proxied.setAge(i1);
1460        assertEquals(i1, proxied.getAge());
1461        assertEquals(i1, aa.sum);
1462        proxied.setAge(i2);
1463        assertEquals(i2, proxied.getAge());
1464        assertEquals(i1 + i2, aa.sum);
1465        assertEquals(i2, proxied.getAge());
1466    }
1467
1468    public void testAfterReturningAdvisorIsNotInvokedOnException() {
1469        CountingAfterReturningAdvice car = new CountingAfterReturningAdvice();
1470        TestBean target = new TestBean();
1471        ProxyFactory pf = new ProxyFactory(target);
1472        pf.addAdvice(new NopInterceptor());
1473        pf.addAdvice(car);
1474        assertEquals("Advice was wrapped in Advisor and added", car, pf.getAdvisors()[1].getAdvice());
1475        ITestBean proxied = (ITestBean) createProxy(pf);
1476        assertEquals(0, car.getCalls());
1477        int age = 10;
1478        proxied.setAge(age);
1479        assertEquals(age, proxied.getAge());
1480        assertEquals(2, car.getCalls());
1481        Exception JavaDoc exc = new Exception JavaDoc();
1482        // On exception it won't be invoked
1483
try {
1484            proxied.exceptional(exc);
1485            fail();
1486        }
1487        catch (Throwable JavaDoc t) {
1488            assertSame(exc, t);
1489        }
1490        assertEquals(2, car.getCalls());
1491    }
1492
1493
1494    public void testThrowsAdvisorIsInvoked() throws Throwable JavaDoc {
1495        // Reacts to ServletException and RemoteException
1496
ThrowsAdviceInterceptorTests.MyThrowsHandler th = new ThrowsAdviceInterceptorTests.MyThrowsHandler();
1497        Advisor matchesEchoInvocations = new StaticMethodMatcherPointcutAdvisor(th) {
1498            public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1499                return m.getName().startsWith("echo");
1500            }
1501        };
1502
1503        ThrowsAdviceInterceptorTests.Echo target = new ThrowsAdviceInterceptorTests.Echo();
1504        target.setA(16);
1505        ProxyFactory pf = new ProxyFactory(target);
1506        pf.addAdvice(new NopInterceptor());
1507        pf.addAdvisor(matchesEchoInvocations);
1508        assertEquals("Advisor was added", matchesEchoInvocations, pf.getAdvisors()[1]);
1509        ThrowsAdviceInterceptorTests.IEcho proxied = (ThrowsAdviceInterceptorTests.IEcho) createProxy(pf);
1510        assertEquals(0, th.getCalls());
1511        assertEquals(target.getA(), proxied.getA());
1512        assertEquals(0, th.getCalls());
1513        Exception JavaDoc ex = new Exception JavaDoc();
1514        // Will be advised but doesn't match
1515
try {
1516            proxied.echoException(1, ex);
1517            fail();
1518        }
1519        catch (Exception JavaDoc caught) {
1520            assertEquals(ex, caught);
1521        }
1522
1523        ex = new ServletException JavaDoc();
1524        try {
1525            proxied.echoException(1, ex);
1526            fail();
1527        }
1528        catch (ServletException JavaDoc caught) {
1529            assertEquals(ex, caught);
1530        }
1531        assertEquals(1, th.getCalls("servletException"));
1532    }
1533
1534    public void testAddThrowsAdviceWithoutAdvisor() throws Throwable JavaDoc {
1535        // Reacts to ServletException and RemoteException
1536
ThrowsAdviceInterceptorTests.MyThrowsHandler th = new ThrowsAdviceInterceptorTests.MyThrowsHandler();
1537
1538        ThrowsAdviceInterceptorTests.Echo target = new ThrowsAdviceInterceptorTests.Echo();
1539        target.setA(16);
1540        ProxyFactory pf = new ProxyFactory(target);
1541        pf.addAdvice(new NopInterceptor());
1542        pf.addAdvice(th);
1543        ThrowsAdviceInterceptorTests.IEcho proxied = (ThrowsAdviceInterceptorTests.IEcho) createProxy(pf);
1544        assertEquals(0, th.getCalls());
1545        assertEquals(target.getA(), proxied.getA());
1546        assertEquals(0, th.getCalls());
1547        Exception JavaDoc ex = new Exception JavaDoc();
1548        // Will be advised but doesn't match
1549
try {
1550            proxied.echoException(1, ex);
1551            fail();
1552        }
1553        catch (Exception JavaDoc caught) {
1554            assertEquals(ex, caught);
1555        }
1556
1557        // Subclass of RemoteException
1558
ex = new TransactionRequiredException JavaDoc();
1559        try {
1560            proxied.echoException(1, ex);
1561            fail();
1562        }
1563        catch (TransactionRequiredException JavaDoc caught) {
1564            assertEquals(ex, caught);
1565        }
1566        assertEquals(1, th.getCalls("remoteException"));
1567    }
1568
1569
1570    private static class CheckMethodInvocationIsSameInAndOutInterceptor implements MethodInterceptor {
1571
1572        public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1573            Method JavaDoc m = mi.getMethod();
1574            Object JavaDoc retval = mi.proceed();
1575            assertEquals("Method invocation has same method on way back", m, mi.getMethod());
1576            return retval;
1577        }
1578    }
1579
1580
1581    /**
1582     * ExposeInvocation must be set to true.
1583     */

1584    private static class CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor implements MethodInterceptor {
1585
1586        public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1587            String JavaDoc task = "get invocation on way IN";
1588            try {
1589                MethodInvocation current = ExposeInvocationInterceptor.currentInvocation();
1590                assertEquals(mi, current);
1591                Object JavaDoc retval = mi.proceed();
1592                task = "get invocation on way OUT";
1593                assertEquals(current, ExposeInvocationInterceptor.currentInvocation());
1594                return retval;
1595            }
1596            catch (AspectException ex) {
1597                System.err.println(task + " for " + mi.getMethod());
1598                ex.printStackTrace();
1599                //fail("Can't find invocation: " + ex);
1600
throw ex;
1601            }
1602        }
1603    }
1604
1605
1606    /**
1607     * Same thing for a proxy.
1608     * Only works when exposeProxy is set to true.
1609     * Checks that the proxy is the same on the way in and out.
1610     */

1611    private static class ProxyMatcherInterceptor implements MethodInterceptor {
1612
1613        public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
1614            Object JavaDoc proxy = AopContext.currentProxy();
1615            Object JavaDoc ret = mi.proceed();
1616            // TODO why does this cause stack overflow?
1617
//assertEquals(proxy, AopContext.currentProxy());
1618
assertTrue(proxy == AopContext.currentProxy());
1619            return ret;
1620        }
1621    }
1622
1623
1624    protected static class TestDynamicPointcutAdvice extends DynamicMethodMatcherPointcutAdvisor {
1625
1626        private String JavaDoc pattern;
1627        public int count;
1628
1629        public TestDynamicPointcutAdvice(MethodInterceptor mi, String JavaDoc pattern) {
1630            super(mi);
1631            this.pattern = pattern;
1632        }
1633
1634        public boolean matches(Method JavaDoc m, Class JavaDoc targetClass, Object JavaDoc[] args) {
1635            boolean run = m.getName().indexOf(pattern) != -1;
1636            if (run) ++count;
1637            return run;
1638        }
1639    }
1640
1641
1642    protected static class TestDynamicPointcutForSettersOnly extends TestDynamicPointcutAdvice {
1643
1644        public TestDynamicPointcutForSettersOnly(MethodInterceptor mi, String JavaDoc pattern) {
1645            super(mi, pattern);
1646        }
1647
1648        public boolean matches(Method JavaDoc m, Class JavaDoc clazz) {
1649            return m.getName().startsWith("set");
1650        }
1651    }
1652
1653
1654    protected static class TestStaticPointcutAdvice extends StaticMethodMatcherPointcutAdvisor {
1655
1656        private String JavaDoc pattern;
1657        private int count;
1658
1659        public TestStaticPointcutAdvice(MethodInterceptor mi, String JavaDoc pattern) {
1660            super(mi);
1661            this.pattern = pattern;
1662        }
1663        public boolean matches(Method JavaDoc m, Class JavaDoc targetClass) {
1664            boolean run = m.getName().indexOf(pattern) != -1;
1665            if (run) ++count;
1666            return run;
1667        }
1668    }
1669
1670
1671    /**
1672     * Note that trapping the Invocation as in previous version of this test
1673     * isn't safe, as invocations may be reused
1674     * and hence cleared at the end of each invocation.
1675     * So we trap only the targe.
1676     */

1677    protected static class TrapTargetInterceptor implements MethodInterceptor {
1678
1679        public Object JavaDoc target;
1680
1681        public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
1682            this.target = invocation.getThis();
1683            return invocation.proceed();
1684        }
1685    }
1686
1687
1688    private static class DummyIntroductionAdviceImpl implements DynamicIntroductionAdvice {
1689
1690        public boolean implementsInterface(Class JavaDoc intf) {
1691            return true;
1692        }
1693    }
1694
1695
1696    public static class OwnSpouse extends TestBean {
1697
1698        public ITestBean getSpouse() {
1699            return this;
1700        }
1701    }
1702
1703
1704    private static class EqualsTestBean extends TestBean {
1705
1706        public ITestBean getSpouse() {
1707            return this;
1708        }
1709    }
1710
1711
1712    public static class AllInstancesAreEqual implements IOther {
1713
1714        public boolean equals(Object JavaDoc o) {
1715            return o instanceof AllInstancesAreEqual;
1716        }
1717
1718        public void absquatulate() {
1719        }
1720    }
1721
1722
1723    public interface INeedsToSeeProxy {
1724
1725        int getCount();
1726
1727        void incrementViaThis();
1728
1729        void incrementViaProxy();
1730
1731        void increment();
1732    }
1733
1734
1735    public static class NeedsToSeeProxy implements INeedsToSeeProxy {
1736
1737        private int count;
1738
1739        public int getCount() {
1740            return count;
1741        }
1742
1743        public void incrementViaThis() {
1744            this.increment();
1745        }
1746
1747        public void incrementViaProxy() {
1748            INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.currentProxy();
1749            thisViaProxy.increment();
1750            Advised advised = (Advised) thisViaProxy;
1751            checkAdvised(advised);
1752        }
1753
1754        protected void checkAdvised(Advised advised) {
1755        }
1756
1757        public void increment() {
1758            ++count;
1759        }
1760    }
1761
1762
1763    public static class TargetChecker extends NeedsToSeeProxy {
1764
1765        protected void checkAdvised(Advised advised) {
1766            // TODO replace this check: no longer possible
1767
//assertEquals(advised.getTarget(), this);
1768
}
1769    }
1770
1771}
1772
Popular Tags