View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.proxy2;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNotNull;
23  import static org.junit.Assert.assertNotSame;
24  import static org.junit.Assert.assertSame;
25  import static org.junit.Assert.assertTrue;
26  
27  import java.io.IOException;
28  import java.io.Serializable;
29  import java.lang.reflect.Method;
30  import java.util.Arrays;
31  import java.util.Date;
32  import java.util.Iterator;
33  import java.util.LinkedList;
34  import java.util.List;
35  import java.util.ServiceLoader;
36  import java.util.SortedSet;
37  import java.util.TreeSet;
38  
39  import org.apache.commons.proxy2.provider.BeanProvider;
40  import org.apache.commons.proxy2.provider.ConstantProvider;
41  import org.apache.commons.proxy2.provider.SingletonProvider;
42  import org.apache.commons.proxy2.util.AbstractTestCase;
43  import org.apache.commons.proxy2.util.DuplicateEcho;
44  import org.apache.commons.proxy2.util.Echo;
45  import org.apache.commons.proxy2.util.EchoImpl;
46  import org.apache.commons.proxy2.util.SuffixInterceptor;
47  import org.junit.Test;
48  
49  @SuppressWarnings("serial")
50  public abstract class AbstractProxyFactoryTestCase extends AbstractTestCase
51  {
52      //**********************************************************************************************************************
53      // Fields
54      //**********************************************************************************************************************
55  
56      private static final Class<?>[] ECHO_ONLY = new Class[] { Echo.class };
57      protected final ProxyFactory factory;
58      private static final Class<?>[] COMPARABLE_ONLY = new Class[] { Comparable.class };
59  
60      //**********************************************************************************************************************
61      // Constructors
62      //**********************************************************************************************************************
63  
64      protected AbstractProxyFactoryTestCase()
65      {
66          final ServiceLoader<ProxyFactory> serviceLoader = ServiceLoader.load(ProxyFactory.class);
67          Iterator<ProxyFactory> iter = serviceLoader.iterator();
68          if (iter.hasNext())
69          {
70              this.factory = iter.next();
71          }
72          else
73          {
74              throw new RuntimeException("Unable to find proxy factory implementation.");
75          }
76  
77      }
78  
79      //**********************************************************************************************************************
80      // Other Methods
81      //**********************************************************************************************************************
82  
83      private ObjectProvider<Echo> createSingletonEcho()
84      {
85          return new SingletonProvider<Echo>(new BeanProvider<Echo>(EchoImpl.class));
86      }
87  
88      @Test
89      public void testInterceptorHashCode()
90      {
91          final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
92          assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
93      }
94  
95      @Test
96      public void testInvokerHashCode() throws Exception
97      {
98          final Echo proxy = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
99          assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
100     }
101 
102     @Test
103     public void testDelegatorHashCode() throws Exception
104     {
105         final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
106         assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
107     }
108 
109     @Test
110     public void testInterceptorEquals()
111     {
112         final Date date = new Date();
113         final Comparable<?> proxy1 = factory.createInterceptorProxy(date, new NoOpMethodInterceptor(), COMPARABLE_ONLY);
114         final Comparable<?> proxy2 = factory.createInterceptorProxy(date, new NoOpMethodInterceptor(), COMPARABLE_ONLY);
115         assertEquals(proxy1, proxy1);
116         assertFalse(proxy1.equals(proxy2));
117         assertFalse(proxy2.equals(proxy1));
118     }
119 
120     @Test
121     public void testInvokerEquals() throws Exception
122     {
123         final Comparable<?> proxy1 = factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY);
124         final Comparable<?> proxy2 = factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY);
125         assertEquals(proxy1, proxy1);
126         assertFalse(proxy1.equals(proxy2));
127         assertFalse(proxy2.equals(proxy1));
128     }
129 
130     @Test
131     public void testDelegatorEquals() throws Exception
132     {
133         final Date date = new Date();
134         final Comparable<?> proxy1 = factory.createDelegatorProxy(new ConstantProvider<Date>(date), COMPARABLE_ONLY);
135         final Comparable<?> proxy2 = factory.createDelegatorProxy(new ConstantProvider<Date>(date), COMPARABLE_ONLY);
136         assertEquals(proxy1, proxy1);
137         assertFalse(proxy1.equals(proxy2));
138         assertFalse(proxy2.equals(proxy1));
139     }
140 
141     @Test
142     public void testBooleanInterceptorParameter()
143     {
144         final Echo echo = factory.createInterceptorProxy(new EchoImpl(), new InterceptorTester(), ECHO_ONLY);
145         assertFalse(echo.echoBack(false));
146         assertTrue(echo.echoBack(true));
147     }
148 
149     @Test
150     public void testCanProxy()
151     {
152         assertTrue(factory.canProxy(Echo.class));
153         assertFalse(factory.canProxy(EchoImpl.class));
154     }
155 
156     @Test
157     public void testChangingArguments()
158     {
159         final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new ChangeArgumentInterceptor(), ECHO_ONLY);
160         assertEquals("something different", proxy.echoBack("whatever"));
161     }
162 
163     @Test
164     public void testCreateDelegatingProxy()
165     {
166         final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
167         echo.echo();
168         assertEquals("message", echo.echoBack("message"));
169         assertEquals("ab", echo.echoBack("a", "b"));
170     }
171 
172     @Test
173     public void testCreateInterceptorProxy()
174     {
175         final Echo target = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
176         final Echo proxy = factory.createInterceptorProxy(target, new SuffixInterceptor(" suffix"), ECHO_ONLY);
177         proxy.echo();
178         assertEquals("message suffix", proxy.echoBack("message"));
179     }
180 
181     @Test
182     public void testDelegatingProxyClassCaching() throws Exception
183     {
184         final Echo proxy1 = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
185         final Echo proxy2 = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
186         assertNotSame(proxy1, proxy2);
187         assertSame(proxy1.getClass(), proxy2.getClass());
188     }
189 
190     @Test
191     public void testDelegatingProxyInterfaceOrder()
192     {
193         final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), Echo.class, DuplicateEcho.class);
194         final List<Class<?>> expected = new LinkedList<Class<?>>(Arrays.<Class<?>> asList(Echo.class,
195                 DuplicateEcho.class));
196         final List<Class<?>> actual = new LinkedList<Class<?>>(Arrays.asList(echo.getClass().getInterfaces()));
197         actual.retainAll(expected); // Doesn't alter order!
198         assertEquals(expected, actual);
199     }
200 
201     @Test
202     public void testDelegatingProxySerializable() throws Exception
203     {
204         final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
205         assertSerializable(proxy);
206     }
207 
208     @Test
209     public void testInterceptingProxyClassCaching() throws Exception
210     {
211         final Echo proxy1 = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
212         final Echo proxy2 = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
213         assertNotSame(proxy1, proxy2);
214         assertSame(proxy1.getClass(), proxy2.getClass());
215     }
216 
217     @Test
218     public void testInterceptingProxySerializable() throws Exception
219     {
220         final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
221         assertSerializable(proxy);
222     }
223 
224     @Test(expected = IOException.class)
225     public void testInterceptorProxyWithCheckedException() throws Exception
226     {
227         final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
228         proxy.ioException();
229     }
230 
231     @Test(expected = IllegalArgumentException.class)
232     public void testInterceptorProxyWithUncheckedException() throws Exception
233     {
234         final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
235         proxy.illegalArgument();
236     }
237 
238     @Test
239     public void testInterfaceHierarchies()
240     {
241         final SortedSet<String> set = factory.createDelegatorProxy(new ConstantProvider<SortedSet<String>>(
242                 new TreeSet<String>()), SortedSet.class);
243         set.add("Hello");
244     }
245 
246     @Test
247     public void testInvokerProxy() throws Exception
248     {
249         final InvokerTester tester = new InvokerTester();
250         final Echo echo = factory.createInvokerProxy(tester, ECHO_ONLY);
251         echo.echoBack("hello");
252         assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method);
253         assertSame(echo, tester.proxy);
254         assertNotNull(tester.args);
255         assertEquals(1, tester.args.length);
256         assertEquals("hello", tester.args[0]);
257     }
258 
259     @Test
260     public void testInvokerProxyClassCaching() throws Exception
261     {
262         final Echo proxy1 = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
263         final Echo proxy2 = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
264         assertNotSame(proxy1, proxy2);
265         assertSame(proxy1.getClass(), proxy2.getClass());
266     }
267 
268     @Test
269     public void testInvokerProxySerializable() throws Exception
270     {
271         final Echo proxy = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
272         assertSerializable(proxy);
273     }
274 
275     @Test
276     public void testMethodInvocationClassCaching() throws Exception
277     {
278         final InterceptorTester tester = new InterceptorTester();
279         final EchoImpl target = new EchoImpl();
280         final Echo proxy1 = factory.createInterceptorProxy(target, tester, ECHO_ONLY);
281         final Echo proxy2 = factory.createInterceptorProxy(target, tester, Echo.class, DuplicateEcho.class);
282         proxy1.echoBack("hello1");
283         final Class<?> invocationClass1 = tester.invocationClass;
284         proxy2.echoBack("hello2");
285         assertSame(invocationClass1, tester.invocationClass);
286     }
287 
288     @Test
289     public void testMethodInvocationDuplicateMethods() throws Exception
290     {
291         final InterceptorTester tester = new InterceptorTester();
292         final EchoImpl target = new EchoImpl();
293         final Echo proxy = factory.createInterceptorProxy(target, tester, Echo.class, DuplicateEcho.class);
294         proxy.echoBack("hello");
295         assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method);
296     }
297 
298     @Test
299     public void testMethodInvocationImplementation() throws Exception
300     {
301         final InterceptorTester tester = new InterceptorTester();
302         final EchoImpl target = new EchoImpl();
303         final Echo proxy = factory.createInterceptorProxy(target, tester, ECHO_ONLY);
304         proxy.echo();
305         assertNotNull(tester.arguments);
306         assertEquals(0, tester.arguments.length);
307         assertEquals(Echo.class.getMethod("echo"), tester.method);
308         assertSame(proxy, tester.proxy);
309         proxy.echoBack("Hello");
310         assertNotNull(tester.arguments);
311         assertEquals(1, tester.arguments.length);
312         assertEquals("Hello", tester.arguments[0]);
313         assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method);
314         proxy.echoBack("Hello", "World");
315         assertNotNull(tester.arguments);
316         assertEquals(2, tester.arguments.length);
317         assertEquals("Hello", tester.arguments[0]);
318         assertEquals("World", tester.arguments[1]);
319         assertEquals(Echo.class.getMethod("echoBack", String.class, String.class), tester.method);
320     }
321 
322     @Test
323     public void testPrimitiveParameter()
324     {
325         final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
326         assertEquals(1, echo.echoBack(1));
327     }
328 
329     @Test(expected = IOException.class)
330     public void testProxyWithCheckedException() throws Exception
331     {
332         final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
333         proxy.ioException();
334     }
335 
336     @Test(expected = IllegalArgumentException.class)
337     public void testProxyWithUncheckedException() throws Exception
338     {
339         final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class);
340         proxy.illegalArgument();
341     }
342 
343     @Test
344     public void testWithNonAccessibleTargetType()
345     {
346         final Echo proxy = factory.createInterceptorProxy(new PrivateEcho(), new NoOpMethodInterceptor(), ECHO_ONLY);
347         proxy.echo();
348     }
349 
350     //**********************************************************************************************************************
351     // Inner Classes
352     //**********************************************************************************************************************
353 
354     private static class ChangeArgumentInterceptor implements Interceptor
355     {
356         @Override
357         public Object intercept(Invocation methodInvocation) throws Throwable
358         {
359             methodInvocation.getArguments()[0] = "something different";
360             return methodInvocation.proceed();
361         }
362     }
363 
364     protected static class InterceptorTester implements Interceptor
365     {
366         private Object[] arguments;
367         private Method method;
368         private Object proxy;
369         private Class<?> invocationClass;
370 
371         @Override
372         public Object intercept(Invocation methodInvocation) throws Throwable
373         {
374             arguments = methodInvocation.getArguments();
375             method = methodInvocation.getMethod();
376             proxy = methodInvocation.getProxy();
377             invocationClass = methodInvocation.getClass();
378             return methodInvocation.proceed();
379         }
380     }
381 
382     protected static class InvokerTester implements Invoker
383     {
384         private Object method;
385         private Object[] args;
386         private Object proxy;
387 
388         @Override
389         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
390         {
391             this.proxy = proxy;
392             this.method = method;
393             this.args = args;
394             return null;
395         }
396     }
397 
398     protected static class NoOpMethodInterceptor implements Interceptor, Serializable
399     {
400         @Override
401         public Object intercept(Invocation methodInvocation) throws Throwable
402         {
403             return methodInvocation.proceed();
404         }
405     }
406 
407     private static class PrivateEcho extends EchoImpl
408     {
409     }
410 }