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 junit.framework.TestCase;
21  import org.apache.commons.proxy.Interceptor;
22  import org.apache.commons.proxy.Invocation;
23  import org.apache.commons.proxy.Invoker;
24  import org.apache.commons.proxy.ObjectProvider;
25  import org.apache.commons.proxy.ProxyFactory;
26  import org.apache.commons.proxy.provider.BeanProvider;
27  import org.apache.commons.proxy.provider.ConstantProvider;
28  import org.apache.commons.proxy.provider.SingletonProvider;
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.lang.reflect.Method;
36  import java.util.Arrays;
37  import java.util.LinkedList;
38  import java.util.List;
39  import java.util.SortedSet;
40  import java.util.TreeSet;
41  
42  /**
43   * @author James Carman
44   * @since 1.0
45   */
46  public abstract class AbstractProxyFactoryTestCase extends TestCase
47  {
48      protected final ProxyFactory factory;
49      private static final Class[] ECHO_ONLY = new Class[] { Echo.class };
50  
51      protected AbstractProxyFactoryTestCase( ProxyFactory factory )
52      {
53          this.factory = factory;
54      }
55  
56      public void testCanProxy()
57      {
58          assertTrue( factory.canProxy( ECHO_ONLY ) );
59          assertFalse( factory.canProxy( new Class[] { EchoImpl.class } ) );
60      }
61  
62      public void testInterfaceHierarchies()
63      {
64          final SortedSet set = ( SortedSet ) factory.createDelegatorProxy( new ConstantProvider( new TreeSet() ), new Class[] { SortedSet.class } );
65          set.add( "Hello" );
66      }
67  
68      public void testInvokerProxy() throws Exception
69      {
70          final InvokerTester tester = new InvokerTester();
71          final Echo echo = ( Echo )factory.createInvokerProxy( tester, ECHO_ONLY );
72          echo.echoBack( "hello" );
73          assertEquals( Echo.class.getMethod( "echoBack", new Class[] { String.class } ), tester.method );
74          assertSame( echo, tester.proxy );
75          assertNotNull( tester.args );
76          assertEquals( 1, tester.args.length );
77          assertEquals( "hello", tester.args[0] );
78      }
79  
80      public void testDelegatingProxyInterfaceOrder()
81      {
82          final Echo echo = ( Echo ) factory.createDelegatorProxy( createSingletonEcho(), new Class[] { Echo.class, DuplicateEcho.class } );
83          final List expected = new LinkedList( Arrays.asList( new Class[] { Echo.class, DuplicateEcho.class } ) );
84          final List actual = new LinkedList( Arrays.asList( echo.getClass().getInterfaces() ) );
85          actual.retainAll( expected );  // Doesn't alter order!
86          assertEquals( expected, actual );
87      }
88  
89      public void testCreateDelegatingProxy()
90      {
91          final Echo echo = ( Echo ) factory.createDelegatorProxy( createSingletonEcho(), ECHO_ONLY );
92          echo.echo();
93          assertEquals( "message", echo.echoBack( "message" ) );
94          assertEquals( "ab", echo.echoBack( "a", "b" ) );
95      }
96  
97      public void testBooleanInterceptorParameter()
98      {
99          final Echo echo = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new  InterceptorTester(), ECHO_ONLY );
100         assertFalse( echo.echoBack( false ) );
101         assertTrue( echo.echoBack( true ) );
102 
103     }
104     public void testPrimitiveParameter()
105     {
106         final Echo echo = ( Echo ) factory.createDelegatorProxy( createSingletonEcho(), ECHO_ONLY );
107         assertEquals( 1, echo.echoBack( 1 ) );
108     }
109 
110     public void testCreateInterceptorProxy()
111     {
112         final Echo target = ( Echo ) factory.createDelegatorProxy( createSingletonEcho(), ECHO_ONLY );
113         final Echo proxy = ( Echo ) factory.createInterceptorProxy( target, new SuffixInterceptor( " suffix" ), ECHO_ONLY );
114         proxy.echo();
115         assertEquals( "message suffix", proxy.echoBack( "message" ) );
116     }
117 
118     private ObjectProvider createSingletonEcho()
119     {
120         return new SingletonProvider( new BeanProvider( EchoImpl.class ) );
121     }
122 
123     public void testMethodInvocationImplementation() throws Exception
124     {
125         final InterceptorTester tester = new InterceptorTester();
126         final EchoImpl target = new EchoImpl();
127         final Echo proxy = ( Echo ) factory.createInterceptorProxy( target, tester, ECHO_ONLY );
128         proxy.echo();
129         assertNotNull( tester.arguments );
130         assertEquals( 0, tester.arguments.length );
131         assertEquals( Echo.class.getMethod( "echo", new Class[] {} ), tester.method );
132         assertEquals( target, tester.proxy );
133         proxy.echoBack( "Hello" );
134         assertNotNull( tester.arguments );
135         assertEquals( 1, tester.arguments.length );
136         assertEquals( "Hello", tester.arguments[0] );
137         assertEquals( Echo.class.getMethod( "echoBack", new Class[] { String.class } ), tester.method );
138         proxy.echoBack( "Hello", "World" );
139         assertNotNull( tester.arguments );
140         assertEquals( 2, tester.arguments.length );
141         assertEquals( "Hello", tester.arguments[0] );
142         assertEquals( "World", tester.arguments[1] );
143         assertEquals( Echo.class.getMethod( "echoBack", new Class[] { String.class, String.class } ), tester.method );
144     }
145 
146     public void testMethodInvocationDuplicateMethods() throws Exception
147     {
148         final InterceptorTester tester = new InterceptorTester();
149         final EchoImpl target = new EchoImpl();
150         final Echo proxy = ( Echo ) factory.createInterceptorProxy( target, tester, new Class[] { Echo.class, DuplicateEcho.class } );
151         proxy.echoBack( "hello" );
152         assertEquals( Echo.class.getMethod( "echoBack", new Class[] { String.class } ), tester.method );
153     }
154 
155 
156     public void testMethodInvocationClassCaching() throws Exception
157     {
158         final InterceptorTester tester = new InterceptorTester();
159         final EchoImpl target = new EchoImpl();
160         final Echo proxy1 = ( Echo ) factory.createInterceptorProxy( target, tester, ECHO_ONLY );
161         final Echo proxy2 = ( Echo ) factory.createInterceptorProxy( target, tester, new Class[] { Echo.class, DuplicateEcho.class } );
162         proxy1.echoBack( "hello1" );
163         final Class invocationClass1 = tester.invocationClass;
164         proxy2.echoBack( "hello2" );
165         assertEquals( invocationClass1, tester.invocationClass );
166     }
167 
168     public void testDelegatingProxyClassCaching() throws Exception
169     {
170         final Echo proxy1 = ( Echo ) factory.createDelegatorProxy( new ConstantProvider( new EchoImpl() ), ECHO_ONLY );
171         final Echo proxy2 = ( Echo ) factory.createDelegatorProxy( new ConstantProvider( new EchoImpl() ), ECHO_ONLY );
172         assertEquals( proxy1.getClass(), proxy2.getClass() );
173     }
174 
175     public void testInterceptingProxyClassCaching() throws Exception
176     {
177         final Echo proxy1 = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY );
178         final Echo proxy2 = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY );
179         assertEquals( proxy1.getClass(), proxy2.getClass() );
180     }
181 
182     public void testProxyWithCheckedException() throws Exception
183     {
184         final Echo proxy = ( Echo ) factory.createDelegatorProxy( new ConstantProvider( new EchoImpl() ), ECHO_ONLY );
185         try
186         {
187             proxy.ioException();
188             fail();
189         }
190         catch( IOException e )
191         {
192         }
193     }
194 
195     public void testProxyWithUncheckedException() throws Exception
196     {
197         final Echo proxy = ( Echo ) factory.createDelegatorProxy( new ConstantProvider( new EchoImpl() ), ECHO_ONLY );
198         try
199         {
200             proxy.illegalArgument();
201             fail();
202         }
203         catch( IllegalArgumentException e )
204         {
205         }
206     }
207 
208     public void testInterceptorProxyWithUncheckedException() throws Exception
209     {
210         final Echo proxy = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new NoOpMethodInterceptor(),  ECHO_ONLY );
211         try
212         {
213             proxy.illegalArgument();
214             fail();
215         }
216         catch( IllegalArgumentException e )
217         {
218         }
219     }
220 
221     public void testInterceptorProxyWithCheckedException() throws Exception
222     {
223         final Echo proxy = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY );
224         try
225         {
226             proxy.ioException();
227             fail();
228         }
229         catch( IOException e )
230         {
231         }
232     }
233 
234     public void testWithNonAccessibleTargetType()
235     {
236         final Echo proxy = ( Echo ) factory.createInterceptorProxy( new PrivateEcho(), new NoOpMethodInterceptor(), ECHO_ONLY );
237         proxy.echo();
238 
239     }
240 
241     public void testChangingArguments()
242     {
243         final Echo proxy = ( Echo ) factory.createInterceptorProxy( new EchoImpl(), new ChangeArgumentInterceptor(), ECHO_ONLY );
244         assertEquals( "something different", proxy.echoBack( "whatever" ) );
245     }
246 
247     private static class PrivateEcho extends EchoImpl
248     {
249     }
250 
251     private static class ChangeArgumentInterceptor implements Interceptor
252     {
253         public Object intercept( Invocation methodInvocation ) throws Throwable
254         {
255             methodInvocation.getArguments()[0] = "something different";
256             return methodInvocation.proceed();
257         }
258     }
259 
260     protected static class NoOpMethodInterceptor implements Interceptor
261     {
262         public Object intercept( Invocation methodInvocation ) throws Throwable
263         {
264             return methodInvocation.proceed();
265         }
266     }
267 
268     private static class InvokerTester implements Invoker
269     {
270         private Object method;
271         private Object[] args;
272         private Object proxy;
273 
274         public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
275         {
276             this.proxy = proxy;
277             this.method = method;
278             this.args = args;
279             return null;
280         }
281     }
282 
283     private static class InterceptorTester implements Interceptor
284     {
285         private Object[] arguments;
286         private Method method;
287         private Object proxy;
288         private Class invocationClass;
289 
290         public Object intercept( Invocation methodInvocation ) throws Throwable
291         {
292             arguments = methodInvocation.getArguments();
293             method = methodInvocation.getMethod();
294             proxy = methodInvocation.getProxy();
295             invocationClass = methodInvocation.getClass();
296             return methodInvocation.proceed();
297         }
298     }
299 }