001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.proxy2; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertNotSame; 024import static org.junit.Assert.assertSame; 025import static org.junit.Assert.assertTrue; 026 027import java.io.IOException; 028import java.io.Serializable; 029import java.lang.reflect.Method; 030import java.util.Arrays; 031import java.util.Date; 032import java.util.Iterator; 033import java.util.LinkedList; 034import java.util.List; 035import java.util.ServiceLoader; 036import java.util.SortedSet; 037import java.util.TreeSet; 038 039import org.apache.commons.proxy2.provider.BeanProvider; 040import org.apache.commons.proxy2.provider.ConstantProvider; 041import org.apache.commons.proxy2.provider.SingletonProvider; 042import org.apache.commons.proxy2.util.AbstractTestCase; 043import org.apache.commons.proxy2.util.DuplicateEcho; 044import org.apache.commons.proxy2.util.Echo; 045import org.apache.commons.proxy2.util.EchoImpl; 046import org.apache.commons.proxy2.util.SuffixInterceptor; 047import org.junit.Test; 048 049@SuppressWarnings("serial") 050public abstract class AbstractProxyFactoryTestCase extends AbstractTestCase 051{ 052 //********************************************************************************************************************** 053 // Fields 054 //********************************************************************************************************************** 055 056 private static final Class<?>[] ECHO_ONLY = new Class[] { Echo.class }; 057 protected final ProxyFactory factory; 058 private static final Class<?>[] COMPARABLE_ONLY = new Class[] { Comparable.class }; 059 060 //********************************************************************************************************************** 061 // Constructors 062 //********************************************************************************************************************** 063 064 protected AbstractProxyFactoryTestCase() 065 { 066 final ServiceLoader<ProxyFactory> serviceLoader = ServiceLoader.load(ProxyFactory.class); 067 Iterator<ProxyFactory> iter = serviceLoader.iterator(); 068 if (iter.hasNext()) 069 { 070 this.factory = iter.next(); 071 } 072 else 073 { 074 throw new RuntimeException("Unable to find proxy factory implementation."); 075 } 076 077 } 078 079 //********************************************************************************************************************** 080 // Other Methods 081 //********************************************************************************************************************** 082 083 private ObjectProvider<Echo> createSingletonEcho() 084 { 085 return new SingletonProvider<Echo>(new BeanProvider<Echo>(EchoImpl.class)); 086 } 087 088 @Test 089 public void testInterceptorHashCode() 090 { 091 final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); 092 assertEquals(proxy.hashCode(), System.identityHashCode(proxy)); 093 } 094 095 @Test 096 public void testInvokerHashCode() throws Exception 097 { 098 final Echo proxy = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY); 099 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}