⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractaopproxytests.java

📁 spring的源代码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 2002-2004 the original author or authors.
 * 
 * Licensed 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.springframework.aop.framework;

import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletException;
import javax.transaction.TransactionRequiredException;

import junit.framework.TestCase;

import org.aopalliance.aop.AspectException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests;
import org.springframework.aop.interceptor.NopInterceptor;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.DynamicMethodMatcherPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.beans.IOther;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;

/**
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 13-Mar-2003
 * @version $Id: AbstractAopProxyTests.java,v 1.27 2004/04/14 18:55:17 johnsonr Exp $
 */
public abstract class AbstractAopProxyTests extends TestCase {
	
	protected MockTargetSource mockTargetSource = new MockTargetSource();

	public AbstractAopProxyTests(String arg0) {
		super(arg0);
	}
	
	/**
	 * Make a clean target source available if code wants to use it.
	 * The target must be set. Verification will be automatic in tearDown
	 * to ensure that it was used appropriately by code.
	 * @see junit.framework.TestCase#setUp()
	 */
	protected void setUp() {
		mockTargetSource.reset();
	}

	protected void tearDown() {
		mockTargetSource.verify();
	}
	
	/**
	 * Set in CGLIB or JDK mode
	 * @param as
	 */
	protected abstract Object createProxy(AdvisedSupport as);
	
	protected abstract AopProxy createAopProxy(AdvisedSupport as);
	
	/**
	 * Is a target always required?
	 * @return
	 */
	protected boolean requiresTarget() {
		return false;
	}
	
	
	public void testNoInterceptorsAndNoTarget() {
		AdvisedSupport pc =
			new AdvisedSupport(new Class[] { ITestBean.class });
		// Add no interceptors
		try {
			AopProxy aop = createAopProxy(pc);
			aop.getProxy();
			fail("Shouldn't allow no interceptors");
		} catch (AopConfigException ex) {
			// Ok
		}
	}
	
	private static class CheckMethodInvocationIsSameInAndOutInterceptor implements MethodInterceptor {
		public Object invoke(MethodInvocation mi) throws Throwable {
			Method m = mi.getMethod();
			Object retval = mi.proceed();
			assertEquals("Method invocation has same method on way back", m, mi.getMethod());
			return retval;
		}
	}
	
	/**
	 * ExposeInvocation must be set to true
	 */
	private static class CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor implements MethodInterceptor {
		public Object invoke(MethodInvocation mi) throws Throwable {
			String task = "get invocation on way IN";
			try {
				MethodInvocation current = ExposeInvocationInterceptor.currentInvocation();
				assertEquals(mi, current);
				Object retval = mi.proceed();
				task = "get invocation on way OUT";
				assertEquals(current, ExposeInvocationInterceptor.currentInvocation());
				return retval;
			}
			catch (AspectException ex) {
				System.err.println(task + " for " + mi.getMethod());
				ex.printStackTrace();
				//fail("Can't find invocation: " + ex);
				throw ex;
			}
		}
	}
	
	/**
	 * Same thing for a proxy.
	* Only works when exposeProxy is set to true.
	* Checks that the proxy is the same on the way in and out.
	*/
	public static class ProxyMatcherInterceptor implements MethodInterceptor {
		public Object invoke(MethodInvocation mi) throws Throwable {
			Object proxy = AopContext.currentProxy();
			Object ret = mi.proceed();
			// TODO why does this cause stack overflow?
			//assertEquals(proxy, AopContext.currentProxy());
			assertTrue(proxy == AopContext.currentProxy());
			return ret;
		}
	}
	
	/**
	 * Simple test that if we set values we can get them out again
	 *
	 */
	public void testValuesStick() {
		int age1 = 33;
		int age2 = 37;
		String name = "tony";
	
		TestBean target1 = new TestBean();
		target1.setAge(age1);
		ProxyFactory pf1 = new ProxyFactory(target1);
		pf1.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
		pf1.addAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor()));
		ITestBean tb = (ITestBean) target1;
		
		assertEquals(age1, tb.getAge());
		tb.setAge(age2);
		assertEquals(age2, tb.getAge());
		assertNull(tb.getName());
		tb.setName(name);
		assertEquals(name, tb.getName());
	}
	
	/**
	 * Check that the two MethodInvocations necessary are independent and
	 * don't conflict.
	 * Check also proxy exposure.
	 */
	public void testOneAdvisedObjectCallsAnother() {
		int age1 = 33;
		int age2 = 37;
		
		TestBean target1 = new TestBean();
		ProxyFactory pf1 = new ProxyFactory(target1);
		// Permit proxy and invocation checkers to get context from AopContext
		pf1.setExposeProxy(true);
		NopInterceptor di1 = new NopInterceptor();
		pf1.addInterceptor(0, di1);
		pf1.addInterceptor(1, new ProxyMatcherInterceptor());
		pf1.addInterceptor(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
		pf1.addInterceptor(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
		// Must be first
		pf1.addInterceptor(0, ExposeInvocationInterceptor.INSTANCE);
		ITestBean advised1 = (ITestBean) pf1.getProxy();
		advised1.setAge(age1); // = 1 invocation
		
		TestBean target2 = new TestBean();
		ProxyFactory pf2 = new ProxyFactory(target2);		
		pf2.setExposeProxy(true);
		NopInterceptor di2 = new NopInterceptor();
		pf2.addInterceptor(0, di2);
		pf2.addInterceptor(1, new ProxyMatcherInterceptor());
		pf2.addInterceptor(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
		pf2.addInterceptor(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
		pf2.addInterceptor(0, ExposeInvocationInterceptor.INSTANCE);
		//System.err.println(pf2.toProxyConfigString());
		ITestBean advised2 = (ITestBean) createProxy(pf2);
		advised2.setAge(age2);
		advised1.setSpouse(advised2); // = 2 invocations
		
		assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
		assertEquals("Advised two has correct age", age2, advised2.getAge());
		// Means extra call on advised 2
		assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge()); // = 4 invocations on 1 and another one on 2
		
		assertEquals("one was invoked correct number of times", 4, di1.getCount());
		// Got hit by call to advised1.getSpouse().getAge()
		assertEquals("one was invoked correct number of times", 3, di2.getCount());
	}
	
	
	public void testReentrance() {
		int age1 = 33;
	
		TestBean target1 = new TestBean();
		ProxyFactory pf1 = new ProxyFactory(target1);
		NopInterceptor di1 = new NopInterceptor();
		pf1.addInterceptor(0, di1);
		ITestBean advised1 = (ITestBean) createProxy(pf1);
		advised1.setAge(age1); // = 1 invocation
		advised1.setSpouse(advised1); // = 2 invocations
	
		assertEquals("one was invoked correct number of times", 2, di1.getCount());
		
		assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
		assertEquals("one was invoked correct number of times", 3, di1.getCount());
		
		// = 5 invocations, as reentrant call to spouse is advised also
		assertEquals("Advised spouse has correct age", age1, advised1.getSpouse().getAge()); 
		
		assertEquals("one was invoked correct number of times", 5, di1.getCount());
	}

	
	public interface INeedsToSeeProxy {
		int getCount();
		void incrementViaThis();
		void incrementViaProxy();
		void increment();
	}
	
	public static class NeedsToSeeProxy implements INeedsToSeeProxy {
		private int count;
		public int getCount() {
			return count;
		}
		public void incrementViaThis() {
			this.increment();
		}
		public void incrementViaProxy() {
			INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.currentProxy();
			thisViaProxy.increment();
			Advised advised = (Advised) thisViaProxy;
			checkAdvised(advised);
		}
		
		protected void checkAdvised(Advised advised) {
		}
	
		public void increment() {
			++count;
		}
	}
	
	public static class TargetChecker extends NeedsToSeeProxy {
		protected void checkAdvised(Advised advised) {
			// TODO replace this check: no longer possible
			//assertEquals(advised.getTarget(), this);
		}
	}
	
	public void testTargetCanGetProxy() {
		NopInterceptor di = new NopInterceptor();
		INeedsToSeeProxy target = new TargetChecker();
		ProxyFactory proxyFactory = new ProxyFactory(target);
		proxyFactory.setExposeProxy(true);
		assertTrue(proxyFactory.getExposeProxy());
	
		proxyFactory.addInterceptor(0, di);
		INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(proxyFactory);
		assertEquals(0, di.getCount());
		assertEquals(0, target.getCount());
		proxied.incrementViaThis();
		assertEquals("Increment happened", 1, target.getCount());
		
		assertEquals("Only one invocation via AOP as use of this wasn't proxied", 1, di.getCount());
		// 1 invocation
		assertEquals("Increment happened", 1, proxied.getCount());
		proxied.incrementViaProxy(); // 2 invoocations
		assertEquals("Increment happened", 2, target.getCount());
		assertEquals("3 more invocations via AOP as the first call was reentrant through the proxy", 4, di.getCount());
	}

			
	public void testTargetCantGetProxyByDefault() {
		NeedsToSeeProxy et = new NeedsToSeeProxy();
		ProxyFactory pf1 = new ProxyFactory(et);
		assertFalse(pf1.getExposeProxy());
		INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(pf1);
		try {
			proxied.incrementViaProxy();
			fail("Should have failed to get proxy as exposeProxy wasn't set to true");
		}
		catch (AspectException ex) {
			// Ok
		}
	}
	

	public void testContext() throws Throwable {
		testContext(true);
	}

	public void testNoContext() throws Throwable {
		testContext(false);
	}

	/**
	 * @param context if true, want context
	 * @throws Throwable
	 */
	private void testContext(final boolean context) throws Throwable {
		final String s = "foo";
		// Test return value
		MethodInterceptor mi = new MethodInterceptor() {
			public Object invoke(MethodInvocation invocation) throws Throwable {
				if (!context) {
					assertNoInvocationContext();
				} else {
					assertTrue("have context", ExposeInvocationInterceptor.currentInvocation() != null);
				}
				return s;
			}
		};
		AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class });
		if (context) {
			pc.addInterceptor(ExposeInvocationInterceptor.INSTANCE);
		}
		pc.addInterceptor(mi);
		// Keep CGLIB happy
		if (requiresTarget()) {
			pc.setTarget(new TestBean());
		}
		AopProxy aop = createAopProxy(pc);

		assertNoInvocationContext();
		ITestBean tb = (ITestBean) aop.getProxy();
		assertNoInvocationContext();
		assertTrue("correct return value", tb.getName() == s);
	}
	
	public static class OwnSpouse extends TestBean {
		public ITestBean getSpouse() {
			return this;
		}
	}

	/**
	 * Test that the proxy returns itself when the
	 * target returns <code>this</code>
	 * @throws Throwable
	 */
	public void testTargetReturnsThis() throws Throwable {
		// Test return value
		TestBean raw = new OwnSpouse();
	
		AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class });
		pc.setTarget(raw);

		ITestBean tb = (ITestBean) createProxy(pc);
		assertTrue("this return is wrapped in proxy", tb.getSpouse() == tb);
	}

	

/*
	public void testCanAttach() throws Throwable {
		final TrapInterceptor tii = new TrapInvocationInterceptor();

		ProxyConfig pc = new ProxyConfigSupport(new Class[] { ITestBean.class }, false);
		pc.addInterceptor(tii);
		pc.addInterceptor(new MethodInterceptor() {
			public Object invoke(MethodInvocation invocation) throws Throwable {
				assertTrue("Saw same interceptor", invocation == tii.invocation);
				return null;
			}
		});
		AopProxy aop = new AopProxy(pc, new MethodInvocationFactorySupport());

		ITestBean tb = (ITestBean) aop.getProxy();
		tb.getSpouse();
		assertTrue(tii.invocation != null);
		
		// TODO strengthen this
	//	assertTrue(tii.invocation.getProxy() == tb);
		assertTrue(tii.invocation.getThis() == null);
	}
*/


	public void testDeclaredException() throws Throwable {
		final Exception expectedException = new Exception();
		// Test return value
		MethodInterceptor mi = new MethodInterceptor() {
			public Object invoke(MethodInvocation invocation) throws Throwable {
				throw expectedException;
			}
		};
		AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class });
		pc.addInterceptor(ExposeInvocationInterceptor.INSTANCE);
		pc.addInterceptor(mi);
		
		// We don't care about the object
		mockTargetSource.setTarget(new Object());
		pc.setTargetSource(mockTargetSource);
		AopProxy aop = createAopProxy(pc);

		try {
			ITestBean tb = (ITestBean) aop.getProxy();
			// Note: exception param below isn't used
			tb.exceptional(expectedException);
			fail("Should have thrown exception raised by interceptor");
		} 
		catch (Exception thrown) {
			assertEquals("exception matches", expectedException, thrown);
		}
	}
	
	/**
	 * An interceptor throws a checked exception not on the method signature.
	 * For efficiency, we don't bother unifying java.lang.reflect and
	 * net.sf.cglib UndeclaredThrowableException
	 * @throws Throwable
	 */
	public void testUndeclaredCheckedException() throws Throwable {
		final Exception unexpectedException = new Exception();
		// Test return value
		MethodInterceptor mi = new MethodInterceptor() {
			public Object invoke(MethodInvocation invocation) throws Throwable {
				throw unexpectedException;
			}
		};
		AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class });
		pc.addInterceptor(ExposeInvocationInterceptor.INSTANCE);
		pc.addInterceptor(mi);
	
		// We don't care about the object
		pc.setTarget(new TestBean());
		AopProxy aop = createAopProxy(pc);
		ITestBean tb = (ITestBean) aop.getProxy();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -