blob: 574b1ec761b2c2fb4003dd4a1fb47b7ac1458030 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.aries.blueprint.proxy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import org.apache.aries.blueprint.proxy.ProxyTestClassInnerClasses.ProxyTestClassInner;
import org.apache.aries.blueprint.proxy.ProxyTestClassInnerClasses.ProxyTestClassStaticInner;
import org.apache.aries.proxy.InvocationListener;
import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
import org.junit.Test;
public abstract class AbstractProxyTest {
protected static class TestListener implements InvocationListener {
boolean preInvoke = false;
boolean postInvoke = false;
boolean postInvokeExceptionalReturn = false;
private Method m;
private Object token;
private Throwable e;
public Object preInvoke(Object proxy, Method m, Object[] args)
throws Throwable {
preInvoke = true;
token = new Object();
this.m = m;
return token;
}
public void postInvoke(Object token, Object proxy, Method m,
Object returnValue) throws Throwable {
postInvoke = this.token == token && this.m == m;
}
public void postInvokeExceptionalReturn(Object token, Object proxy,
Method m, Throwable exception) throws Throwable {
postInvokeExceptionalReturn = this.token == token && this.m == m;
e = exception;
}
public void clear() {
preInvoke = false;
postInvoke = false;
postInvokeExceptionalReturn = false;
token = null;
m = null;
e = null;
}
public Method getLastMethod() {
return m;
}
public Throwable getLastThrowable() {
return e;
}
}
protected abstract Object getProxyInstance(Class<?> proxyClass);
protected abstract Object getProxyInstance(Class<?> proxyClass, InvocationListener listener);
protected abstract Class<?> getProxyClass(Class<?> clazz);
protected abstract Object setDelegate(Object proxy, Callable<Object> dispatcher);
protected Class<?> getTestClass() {
return ProxyTestClassGeneral.class;
}
protected Method getDeclaredMethod(Class<?> testClass, String name,
Class<?>... classes) throws Exception {
return getProxyClass(testClass).getDeclaredMethod(name, classes);
}
/**
* This test uses the ProxySubclassGenerator to generate and load a subclass
* of the specified getTestClass().
*
* Once the subclass is generated we check that it wasn't null. We check
* that the InvocationHandler constructor doesn't return a null object
* either
*
* Test method for
* {@link org.apache.aries.proxy.impl.ProxySubclassGenerator#generateAndLoadSubclass()}
* .
*/
@Test
public void testGenerateAndLoadProxy() throws Exception
{
assertNotNull("Generated proxy subclass was null", getProxyClass(getTestClass()));
assertNotNull("Generated proxy subclass instance was null", getProxyInstance(getProxyClass(getTestClass())));
}
/**
* Test a basic method invocation on the proxy subclass
*/
@Test
public void testMethodInvocation() throws Exception {
Method m = getDeclaredMethod(getTestClass(), "testMethod", String.class,
int.class, Object.class);
String x = "x";
String returned = (String) m.invoke(getProxyInstance(getProxyClass(getTestClass())), x, 1, new Object());
assertEquals("Object returned from invocation was not correct.", x, returned);
}
/**
* Test different argument types on a method invocation
*/
@Test
public void testMethodArgs() throws Exception
{
Method m = getDeclaredMethod(getTestClass(), "testArgs", double.class,
short.class, long.class, char.class, byte.class, boolean.class);
Character xc = Character.valueOf('x');
String x = xc.toString();
String returned = (String) m.invoke(getProxyInstance(getProxyClass(getTestClass())), Double.MAX_VALUE, Short.MIN_VALUE, Long.MAX_VALUE, xc
.charValue(), Byte.MIN_VALUE, false);
assertEquals("Object returned from invocation was not correct.", x, returned);
}
/**
* Test a method that returns void
*/
@Test
public void testReturnVoid() throws Exception
{
Method m = getDeclaredMethod(getTestClass(), "testReturnVoid");
//for these weaving tests we are loading the woven test classes on a different classloader
//to this class so we need to set the method accessible
m.setAccessible(true);
m.invoke(getProxyInstance(getProxyClass(getTestClass())));
}
/**
* Test a method that returns an int
*/
@Test
public void testReturnInt() throws Exception
{
Method m = getDeclaredMethod(getTestClass(), "testReturnInt");
//for these weaving tests we are loading the woven test classes on a different classloader
//to this class so we need to set the method accessible
m.setAccessible(true);
Integer returned = (Integer) m.invoke(getProxyInstance(getProxyClass(getTestClass())));
assertEquals("Expected object was not returned from invocation", Integer.valueOf(17), returned);
}
/**
* Test a method that returns an Integer
*/
@Test
public void testReturnInteger() throws Exception
{
Method m = getDeclaredMethod(getTestClass(), "testReturnInteger");
Integer returned = (Integer) m.invoke(getProxyInstance(getProxyClass(getTestClass())));
assertEquals("Expected object was not returned from invocation", Integer.valueOf(1), returned);
}
/**
* Test a public method declared higher up the superclass hierarchy
*/
@Test
public void testPublicHierarchyMethod() throws Exception
{
Method m = null;
try {
m = getDeclaredMethod(getTestClass(), "bMethod");
} catch (NoSuchMethodException nsme) {
m = getProxyClass(getTestClass()).getSuperclass().getDeclaredMethod("bMethod");
}
m.invoke(getProxyInstance(getProxyClass(getTestClass())));
}
/**
* Test a protected method declared higher up the superclass hierarchy
*/
@Test
public void testProtectedHierarchyMethod() throws Exception
{
Method m = null;
try {
m = getDeclaredMethod(getTestClass(), "bProMethod");
} catch (NoSuchMethodException nsme) {
m = getProxyClass(getTestClass()).getSuperclass().getDeclaredMethod("bProMethod");
}
//for these weaving tests we are loading the woven test classes on a different classloader
//to this class so we need to set the method accessible
m.setAccessible(true);
m.invoke(getProxyInstance(getProxyClass(getTestClass())));
}
/**
* Test a default method declared higher up the superclass hierarchy
*/
@Test
public void testDefaultHierarchyMethod() throws Exception
{
Method m = null;
try {
m = getDeclaredMethod(getTestClass(), "bDefMethod");
} catch (NoSuchMethodException nsme) {
m = getProxyClass(getTestClass()).getSuperclass().getDeclaredMethod("bDefMethod", new Class[] {});
}
//for these weaving tests we are loading the woven test classes on a different classloader
//to this class so we need to set the method accessible
m.setAccessible(true);
m.invoke(getProxyInstance(getProxyClass(getTestClass())));
}
/**
* Test a covariant override method
*/
@Test
public void testCovariant() throws Exception
{
Class<?> proxy = getProxyClass(ProxyTestClassCovariantOverride.class);
Method m = getDeclaredMethod(ProxyTestClassCovariantOverride.class, "getCovariant");
Object returned = m.invoke(getProxyInstance(proxy));
assertTrue("Object was of wrong type: " + returned.getClass().getSimpleName(),
proxy.isInstance(returned));
}
/**
* Test a method with generics
*/
@Test
public void testGenerics() throws Exception
{
Class<?> proxy = getProxyClass(ProxyTestClassGeneric.class);
Object o = getProxyInstance(proxy);
Method m = getDeclaredMethod(ProxyTestClassGeneric.class, "setSomething", String.class);
m.invoke(o, "aString");
if(getClass() == WovenProxyGeneratorTest.class)
m = getDeclaredMethod(ProxyTestClassGeneric.class.getSuperclass(), "getSomething");
else
m = getDeclaredMethod(ProxyTestClassGeneric.class, "getSomething");
Object returned = m.invoke(o);
assertTrue("Object was of wrong type", String.class.isInstance(returned));
assertEquals("String had wrong value", "aString", returned);
}
/**
* Test that we don't generate classes twice
*/
@Test
public void testRetrieveClass() throws Exception
{
Class<?> retrieved = getProxyClass(getTestClass());
assertNotNull("The new class was null", retrieved);
assertEquals("The same class was not returned", retrieved, getProxyClass(getTestClass()));
}
@Test
public void testEquals() throws Exception {
Object p1 = getProxyInstance(getProxyClass(getTestClass()));
Object p2 = getProxyInstance(getProxyClass(getTestClass()));
assertFalse("Should not be equal", p1.equals(p2));
Object p3 = getP3();
p1 = setDelegate(p1, new SingleInstanceDispatcher(p3));
p2 = setDelegate(p2, new SingleInstanceDispatcher(p3));
assertTrue("Should be equal", p1.equals(p2));
Object p4 = getProxyInstance(getProxyClass(getTestClass()));
Object p5 = getProxyInstance(getProxyClass(getTestClass()));
p4 = setDelegate(p4, new SingleInstanceDispatcher(p1));
p5 = setDelegate(p5, new SingleInstanceDispatcher(p2));
assertTrue("Should be equal", p4.equals(p5));
}
protected abstract Object getP3() throws Exception;
@Test
public void testInterception() throws Throwable {
TestListener tl = new TestListener();
Object obj = getProxyInstance(getProxyClass(getTestClass()), tl);
assertCalled(tl, false, false, false);
Method m = getDeclaredMethod(getTestClass(), "testReturnInteger", new Class[] {});
m.invoke(obj);
assertCalled(tl, true, true, false);
tl.clear();
assertCalled(tl, false, false, false);
m = getDeclaredMethod(getTestClass(), "testException", new Class[] {});
try {
m.invoke(obj);
fail("Should throw an exception");
} catch (InvocationTargetException re) {
if(!!!re.getTargetException().getClass().equals(RuntimeException.class))
throw re.getTargetException();
assertCalled(tl, true, false, true);
}
tl.clear();
assertCalled(tl, false, false, false);
m = getDeclaredMethod(getTestClass(), "testInternallyCaughtException", new Class[] {});
try {
m.invoke(obj);
} finally {
assertCalled(tl, true, true, false);
}
}
protected void assertCalled(TestListener listener, boolean pre, boolean post, boolean ex) {
assertEquals(pre, listener.preInvoke);
assertEquals(post, listener.postInvoke);
assertEquals(ex, listener.postInvokeExceptionalReturn);
}
@Test
public void testStaticInner() throws Exception {
assertNotNull(getProxyInstance(getProxyClass(ProxyTestClassStaticInner.class)));
}
@Test
public void testInner() throws Exception {
//An inner class has no no-args (the parent gets added as an arg) so we can't
//get an instance
assertNotNull(getProxyClass(ProxyTestClassInner.class));
}
/**
* Test an abstract class
*/
@Test
public void testAbstractClass() throws Exception
{
Object ptca = getProxyInstance(getProxyClass(ProxyTestClassAbstract.class));
ptca = setDelegate(ptca, new Callable<Object>() {
public Object call() throws Exception {
//We have to use a proxy instance here because we need it to be a subclass
//of the one from the weaving loader in the weaving test...
return getProxyInstance(ProxyTestClassChildOfAbstract.class);
}
});
Method m = ptca.getClass().getDeclaredMethod("getMessage");
assertEquals("Working", m.invoke(ptca));
}
}