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.proxy.factory;
19  
20  import org.apache.commons.proxy.Interceptor;
21  import org.apache.commons.proxy.Invocation;
22  import org.apache.commons.proxy.Invoker;
23  import org.apache.commons.proxy.ObjectProvider;
24  import org.apache.commons.proxy.ProxyFactory;
25  import org.apache.commons.proxy.provider.BeanProvider;
26  import org.apache.commons.proxy.provider.ConstantProvider;
27  import org.apache.commons.proxy.provider.SingletonProvider;
28  import org.apache.commons.proxy.util.AbstractTestCase;
29  import org.apache.commons.proxy.util.DuplicateEcho;
30  import org.apache.commons.proxy.util.Echo;
31  import org.apache.commons.proxy.util.EchoImpl;
32  import org.apache.commons.proxy.util.SuffixInterceptor;
33  
34  import java.io.IOException;
35  import java.io.Serializable;
36  import java.lang.reflect.Method;
37  import java.util.Arrays;
38  import java.util.LinkedList;
39  import java.util.List;
40  import java.util.SortedSet;
41  import java.util.TreeSet;
42  import java.util.Date;
43  
44  /**
45   * @author James Carman
46   * @since 1.0
47   */
48  public abstract class AbstractProxyFactoryTestCase extends AbstractTestCase
49  {
50  //**********************************************************************************************************************
51  // Fields
52  //**********************************************************************************************************************
53  
54      private static final Class[] ECHO_ONLY = new Class[]{Echo.class};
55      protected final ProxyFactory factory;
56      private static final Class[] COMPARABLE_ONLY = new Class[] { Comparable.class };
57  
58  //**********************************************************************************************************************
59  // Constructors
60  //**********************************************************************************************************************
61  
62      protected AbstractProxyFactoryTestCase(ProxyFactory factory)
63      {
64          this.factory = factory;
65      }
66  
67  //**********************************************************************************************************************
68  // Other Methods
69  //**********************************************************************************************************************
70  
71      private ObjectProvider createSingletonEcho()
72      {
73          return new SingletonProvider(new BeanProvider(EchoImpl.class));
74      }
75  
76      public void testInterceptorHashCode()
77      {
78          final Echo proxy = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
79          assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
80      }
81  
82      public void testInvokerHashCode() throws Exception
83      {
84          final Echo proxy = (Echo) factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
85          assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
86      }
87  
88      public void testDelegatorHashCode() throws Exception
89      {
90          final Echo proxy = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
91          assertEquals(proxy.hashCode(), System.identityHashCode(proxy));
92      }
93  
94  
95      public void testInterceptorEquals()
96      {
97          final Date date = new Date();
98          final Comparable proxy1 = (Comparable) factory.createInterceptorProxy(date,
99                  new NoOpMethodInterceptor(), COMPARABLE_ONLY);
100         final Comparable proxy2 = (Comparable) factory.createInterceptorProxy(date,
101                 new NoOpMethodInterceptor(), COMPARABLE_ONLY);
102         assertEquals(proxy1, proxy1);
103         assertFalse(proxy1.equals(proxy2));
104         assertFalse(proxy2.equals(proxy1));
105     }
106 
107     public void testInvokerEquals() throws Exception
108     {
109         final Comparable proxy1 = (Comparable) factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY);
110         final Comparable proxy2 = (Comparable) factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY);
111         assertEquals(proxy1, proxy1);
112         assertFalse(proxy1.equals(proxy2));
113         assertFalse(proxy2.equals(proxy1));
114     }
115 
116     public void testDelegatorEquals() throws Exception
117     {
118         final Date date = new Date();
119         final Comparable proxy1 = (Comparable) factory.createDelegatorProxy(new ConstantProvider(date),
120                 COMPARABLE_ONLY);
121         final Comparable proxy2 = (Comparable) factory.createDelegatorProxy(new ConstantProvider(date),
122                 COMPARABLE_ONLY);
123         assertEquals(proxy1, proxy1);
124         assertFalse(proxy1.equals(proxy2));
125         assertFalse(proxy2.equals(proxy1));
126     }
127 
128     public void testBooleanInterceptorParameter()
129     {
130         final Echo echo = (Echo) factory.createInterceptorProxy(new EchoImpl(), new InterceptorTester(), ECHO_ONLY);
131         assertFalse(echo.echoBack(false));
132         assertTrue(echo.echoBack(true));
133     }
134 
135     public void testCanProxy()
136     {
137         assertTrue(factory.canProxy(ECHO_ONLY));
138         assertFalse(factory.canProxy(new Class[]{EchoImpl.class}));
139     }
140 
141     public void testChangingArguments()
142     {
143         final Echo proxy = (Echo) factory.createInterceptorProxy(new EchoImpl(), new ChangeArgumentInterceptor(), ECHO_ONLY);
144         assertEquals("something different", proxy.echoBack("whatever"));
145     }
146 
147     public void testCreateDelegatingProxy()
148     {
149         final Echo echo = (Echo) factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
150         echo.echo();
151         assertEquals("message", echo.echoBack("message"));
152         assertEquals("ab", echo.echoBack("a", "b"));
153     }
154 
155     public void testCreateInterceptorProxy()
156     {
157         final Echo target = (Echo) factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
158         final Echo proxy = (Echo) factory.createInterceptorProxy(target, new SuffixInterceptor(" suffix"), ECHO_ONLY);
159         proxy.echo();
160         assertEquals("message suffix", proxy.echoBack("message"));
161     }
162 
163     public void testDelegatingProxyClassCaching() throws Exception
164     {
165         final Echo proxy1 = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
166         final Echo proxy2 = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
167         assertNotSame(proxy1, proxy2);
168         assertSame(proxy1.getClass(), proxy2.getClass());
169     }
170 
171     public void testDelegatingProxyInterfaceOrder()
172     {
173         final Echo echo = (Echo) factory.createDelegatorProxy(createSingletonEcho(), new Class[]{Echo.class, DuplicateEcho.class});
174         final List expected = new LinkedList(Arrays.asList(new Class[]{Echo.class, DuplicateEcho.class}));
175         final List actual = new LinkedList(Arrays.asList(echo.getClass().getInterfaces()));
176         actual.retainAll(expected);  // Doesn't alter order!
177         assertEquals(expected, actual);
178     }
179 
180     public void testDelegatingProxySerializable() throws Exception
181     {
182         final Echo proxy = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
183         assertSerializable(proxy);
184     }
185 
186     public void testInterceptingProxyClassCaching() throws Exception
187     {
188         final Echo proxy1 = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
189         final Echo proxy2 = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
190         assertNotSame(proxy1, proxy2);
191         assertSame(proxy1.getClass(), proxy2.getClass());
192     }
193 
194     public void testInterceptingProxySerializable() throws Exception
195     {
196         final Echo proxy = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
197         assertSerializable(proxy);
198     }
199 
200     public void testInterceptorProxyWithCheckedException() throws Exception
201     {
202         final Echo proxy = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
203         try
204         {
205             proxy.ioException();
206             fail();
207         }
208         catch (IOException e)
209         {
210         }
211     }
212 
213     public void testInterceptorProxyWithUncheckedException() throws Exception
214     {
215         final Echo proxy = (Echo) factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY);
216         try
217         {
218             proxy.illegalArgument();
219             fail();
220         }
221         catch (IllegalArgumentException e)
222         {
223         }
224     }
225 
226     public void testInterfaceHierarchies()
227     {
228         final SortedSet set = (SortedSet) factory.createDelegatorProxy(new ConstantProvider(new TreeSet()), new Class[]{SortedSet.class});
229         set.add("Hello");
230     }
231 
232     public void testInvokerProxy() throws Exception
233     {
234         final InvokerTester tester = new InvokerTester();
235         final Echo echo = (Echo) factory.createInvokerProxy(tester, ECHO_ONLY);
236         echo.echoBack("hello");
237         assertEquals(Echo.class.getMethod("echoBack", new Class[]{String.class}), tester.method);
238         assertSame(echo, tester.proxy);
239         assertNotNull(tester.args);
240         assertEquals(1, tester.args.length);
241         assertEquals("hello", tester.args[0]);
242     }
243 
244     public void testInvokerProxyClassCaching() throws Exception
245     {
246         final Echo proxy1 = (Echo) factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
247         final Echo proxy2 = (Echo) factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
248         assertNotSame(proxy1, proxy2);
249         assertSame(proxy1.getClass(), proxy2.getClass());
250     }
251 
252     public void testInvokerProxySerializable() throws Exception
253     {
254         final Echo proxy = (Echo) factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY);
255         assertSerializable(proxy);
256     }
257 
258     public void testMethodInvocationClassCaching() throws Exception
259     {
260         final InterceptorTester tester = new InterceptorTester();
261         final EchoImpl target = new EchoImpl();
262         final Echo proxy1 = (Echo) factory.createInterceptorProxy(target, tester, ECHO_ONLY);
263         final Echo proxy2 = (Echo) factory.createInterceptorProxy(target, tester, new Class[]{Echo.class, DuplicateEcho.class});
264         proxy1.echoBack("hello1");
265         final Class invocationClass1 = tester.invocationClass;
266         proxy2.echoBack("hello2");
267         assertSame(invocationClass1, tester.invocationClass);
268     }
269 
270     public void testMethodInvocationDuplicateMethods() throws Exception
271     {
272         final InterceptorTester tester = new InterceptorTester();
273         final EchoImpl target = new EchoImpl();
274         final Echo proxy = (Echo) factory.createInterceptorProxy(target, tester, new Class[]{Echo.class, DuplicateEcho.class});
275         proxy.echoBack("hello");
276         assertEquals(Echo.class.getMethod("echoBack", new Class[]{String.class}), tester.method);
277     }
278 
279     public void testMethodInvocationImplementation() throws Exception
280     {
281         final InterceptorTester tester = new InterceptorTester();
282         final EchoImpl target = new EchoImpl();
283         final Echo proxy = (Echo) factory.createInterceptorProxy(target, tester, ECHO_ONLY);
284         proxy.echo();
285         assertNotNull(tester.arguments);
286         assertEquals(0, tester.arguments.length);
287         assertEquals(Echo.class.getMethod("echo", new Class[]{}), tester.method);
288         assertEquals(target, tester.proxy);
289         proxy.echoBack("Hello");
290         assertNotNull(tester.arguments);
291         assertEquals(1, tester.arguments.length);
292         assertEquals("Hello", tester.arguments[0]);
293         assertEquals(Echo.class.getMethod("echoBack", new Class[]{String.class}), tester.method);
294         proxy.echoBack("Hello", "World");
295         assertNotNull(tester.arguments);
296         assertEquals(2, tester.arguments.length);
297         assertEquals("Hello", tester.arguments[0]);
298         assertEquals("World", tester.arguments[1]);
299         assertEquals(Echo.class.getMethod("echoBack", new Class[]{String.class, String.class}), tester.method);
300     }
301 
302     public void testPrimitiveParameter()
303     {
304         final Echo echo = (Echo) factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY);
305         assertEquals(1, echo.echoBack(1));
306     }
307 
308     public void testProxyWithCheckedException() throws Exception
309     {
310         final Echo proxy = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
311         try
312         {
313             proxy.ioException();
314             fail();
315         }
316         catch (IOException e)
317         {
318         }
319     }
320 
321     public void testProxyWithUncheckedException() throws Exception
322     {
323         final Echo proxy = (Echo) factory.createDelegatorProxy(new ConstantProvider(new EchoImpl()), ECHO_ONLY);
324         try
325         {
326             proxy.illegalArgument();
327             fail();
328         }
329         catch (IllegalArgumentException e)
330         {
331         }
332     }
333 
334     public void testWithNonAccessibleTargetType()
335     {
336         final Echo proxy = (Echo) factory.createInterceptorProxy(new PrivateEcho(), new NoOpMethodInterceptor(), ECHO_ONLY);
337         proxy.echo();
338     }
339 
340 //**********************************************************************************************************************
341 // Inner Classes
342 //**********************************************************************************************************************
343 
344     private static class ChangeArgumentInterceptor implements Interceptor
345     {
346         public Object intercept(Invocation methodInvocation) throws Throwable
347         {
348             methodInvocation.getArguments()[0] = "something different";
349             return methodInvocation.proceed();
350         }
351     }
352 
353     protected static class InterceptorTester implements Interceptor
354     {
355         private Object[] arguments;
356         private Method method;
357         private Object proxy;
358         private Class invocationClass;
359 
360         public Object intercept(Invocation methodInvocation) throws Throwable
361         {
362             arguments = methodInvocation.getArguments();
363             method = methodInvocation.getMethod();
364             proxy = methodInvocation.getProxy();
365             invocationClass = methodInvocation.getClass();
366             return methodInvocation.proceed();
367         }
368     }
369 
370     protected static class InvokerTester implements Invoker
371     {
372         private Object method;
373         private Object[] args;
374         private Object proxy;
375 
376         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
377         {
378             this.proxy = proxy;
379             this.method = method;
380             this.args = args;
381             return null;
382         }
383     }
384 
385     protected static class NoOpMethodInterceptor implements Interceptor, Serializable
386     {
387         public Object intercept(Invocation methodInvocation) throws Throwable
388         {
389             return methodInvocation.proceed();
390         }
391     }
392 
393     private static class PrivateEcho extends EchoImpl
394     {
395     }
396 }