moving unit tests from .testsuite -> .aop

This commit is contained in:
Chris Beams
2008-12-13 01:46:56 +00:00
parent 84a4fe6d39
commit 7f5e60e76a
18 changed files with 134 additions and 37 deletions

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 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.interceptor;
/**
* Bean that changes state on a business invocation, so that
* we can check whether it's been invoked
* @author Rod Johnson
*/
public class SideEffectBean {
private int count;
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return this.count;
}
public void doWork() {
++count;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2002-2006 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.target;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
/**
* @author Rob Harrop
* @author Chris Beams
* @since 2.0
*/
public class CommonsPoolTargetSourceProxyTests {
@Test
public void testProxy() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("commonsPoolProxyTests.xml", getClass()));
beanFactory.preInstantiateSingletons();
ITestBean bean = (ITestBean)beanFactory.getBean("testBean");
assertTrue(AopUtils.isAopProxy(bean));
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright 2002-2005 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.target;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.SerializableNopInterceptor;
import org.springframework.aop.interceptor.SideEffectBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.Person;
import org.springframework.beans.SerializablePerson;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public class HotSwappableTargetSourceTests {
/** Initial count value set in bean factory XML */
private static final int INITIAL_COUNT = 10;
private XmlBeanFactory beanFactory;
@Before
public void setUp() throws Exception {
this.beanFactory = new XmlBeanFactory(new ClassPathResource("hotSwapTests.xml", getClass()));
}
/**
* We must simulate container shutdown, which should clear threads.
*/
@After
public void tearDown() {
// Will call pool.close()
this.beanFactory.destroySingletons();
}
/**
* Check it works like a normal invoker
*
*/
@Test
public void testBasicFunctionality() {
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(INITIAL_COUNT, proxied.getCount() );
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
proxied = (SideEffectBean) beanFactory.getBean("swappable");
proxied.doWork();
assertEquals(INITIAL_COUNT + 2, proxied.getCount() );
}
@Test
public void testValidSwaps() {
SideEffectBean target1 = (SideEffectBean) beanFactory.getBean("target1");
SideEffectBean target2 = (SideEffectBean) beanFactory.getBean("target2");
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(target1.getCount(), proxied.getCount() );
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object old = swapper.swap(target2);
assertEquals("Correct old target was returned", target1, old);
// TODO should be able to make this assertion: need to fix target handling
// in AdvisedSupport
//assertEquals(target2, ((Advised) proxied).getTarget());
assertEquals(20, proxied.getCount());
proxied.doWork();
assertEquals(21, target2.getCount());
// Swap it back
swapper.swap(target1);
assertEquals(target1.getCount(), proxied.getCount());
}
/**
*
* @param invalid
* @return the message
*/
private IllegalArgumentException testRejectsSwapToInvalidValue(Object invalid) {
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
IllegalArgumentException aopex = null;
try {
swapper.swap(invalid);
fail("Shouldn't be able to swap to invalid value [" + invalid + "]");
}
catch (IllegalArgumentException ex) {
// Ok
aopex = ex;
}
// It shouldn't be corrupted, it should still work
testBasicFunctionality();
return aopex;
}
@Test
public void testRejectsSwapToNull() {
IllegalArgumentException ex = testRejectsSwapToInvalidValue(null);
assertTrue(ex.getMessage().indexOf("null") != -1);
}
// TODO test reject swap to wrong interface or class?
// how to decide what's valid?
@Test
public void testSerialization() throws Exception {
SerializablePerson sp1 = new SerializablePerson();
sp1.setName("Tony");
SerializablePerson sp2 = new SerializablePerson();
sp1.setName("Gordon");
HotSwappableTargetSource hts = new HotSwappableTargetSource(sp1);
ProxyFactory pf = new ProxyFactory();
pf.addInterface(Person.class);
pf.setTargetSource(hts);
pf.addAdvisor(new DefaultPointcutAdvisor(new SerializableNopInterceptor()));
Person p = (Person) pf.getProxy();
assertEquals(sp1.getName(), p.getName());
hts.swap(sp2);
assertEquals(sp2.getName(), p.getName());
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
// We need to get a reference to the client-side targetsource
hts = (HotSwappableTargetSource) ((Advised) p).getTargetSource();
assertEquals(sp2.getName(), p.getName());
hts.swap(sp1);
assertEquals(sp1.getName(), p.getName());
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2002-2006 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.target;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactory;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Chris Beams
*/
public class LazyCreationTargetSourceTests {
@Test
public void testCreateLazy() {
TargetSource targetSource = new AbstractLazyCreationTargetSource() {
protected Object createObject() {
return new InitCountingBean();
}
public Class<?> getTargetClass() {
return InitCountingBean.class;
}
};
InitCountingBean proxy = (InitCountingBean) ProxyFactory.getProxy(targetSource);
assertEquals("Init count should be 0", 0, InitCountingBean.initCount);
assertEquals("Target class incorrect", InitCountingBean.class, targetSource.getTargetClass());
assertEquals("Init count should still be 0 after getTargetClass()", 0, InitCountingBean.initCount);
proxy.doSomething();
assertEquals("Init count should now be 1", 1, InitCountingBean.initCount);
proxy.doSomething();
assertEquals("Init count should still be 1", 1, InitCountingBean.initCount);
}
private static class InitCountingBean {
public static int initCount;
public InitCountingBean() {
if (InitCountingBean.class.equals(getClass())) {
// only increment when creating the actual target - not the proxy
initCount++;
}
}
public void doSomething() {
//no-op
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2002-2007 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.target;
import static org.junit.Assert.*;
import java.util.Set;
import org.junit.Test;
import org.springframework.beans.ITestBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/**
* @author Juergen Hoeller
* @author Rob Harrop
* @author Chris Beams
* @since 07.01.2005
*/
public class LazyInitTargetSourceTests {
@Test
public void testLazyInitSingletonTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitSingletonTests.xml", getClass()));
bf.preInstantiateSingletons();
ITestBean tb = (ITestBean) bf.getBean("proxy");
assertFalse(bf.containsSingleton("target"));
assertEquals(10, tb.getAge());
assertTrue(bf.containsSingleton("target"));
}
@Test
public void testCustomLazyInitSingletonTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("customLazyInitTarget.xml", getClass()));
bf.preInstantiateSingletons();
ITestBean tb = (ITestBean) bf.getBean("proxy");
assertFalse(bf.containsSingleton("target"));
assertEquals("Rob Harrop", tb.getName());
assertTrue(bf.containsSingleton("target"));
}
@Test
public void testLazyInitFactoryBeanTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitFactoryBean.xml", getClass()));
bf.preInstantiateSingletons();
Set<?> set1 = (Set<?>) bf.getBean("proxy1");
assertFalse(bf.containsSingleton("target1"));
assertTrue(set1.contains("10"));
assertTrue(bf.containsSingleton("target1"));
Set<?> set2 = (Set<?>) bf.getBean("proxy2");
assertFalse(bf.containsSingleton("target2"));
assertTrue(set2.contains("20"));
assertTrue(bf.containsSingleton("target2"));
}
public static class CustomLazyInitTargetSource extends LazyInitTargetSource {
protected void postProcessTargetObject(Object targetObject) {
((ITestBean) targetObject).setName("Rob Harrop");
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2002-2008 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.target;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.TargetSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.SerializablePerson;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.SerializationTestUtils;
/**
* Unit tests relating to the abstract AbstractPrototypeBasedTargetSource
* and not subclasses.
*
* @author Rod Johnson
* @author Chris Beams
*/
public class PrototypeBasedTargetSourceTests {
@Test
public void testSerializability() throws Exception {
MutablePropertyValues tsPvs = new MutablePropertyValues();
tsPvs.addPropertyValue("targetBeanName", "person");
RootBeanDefinition tsBd = new RootBeanDefinition(TestTargetSource.class, tsPvs);
MutablePropertyValues pvs = new MutablePropertyValues();
RootBeanDefinition bd = new RootBeanDefinition(SerializablePerson.class, pvs);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("ts", tsBd);
bf.registerBeanDefinition("person", bd);
TestTargetSource cpts = (TestTargetSource) bf.getBean("ts");
TargetSource serialized = (TargetSource) SerializationTestUtils.serializeAndDeserialize(cpts);
assertTrue("Changed to SingletonTargetSource on deserialization",
serialized instanceof SingletonTargetSource);
SingletonTargetSource sts = (SingletonTargetSource) serialized;
assertNotNull(sts.getTarget());
}
private static class TestTargetSource extends AbstractPrototypeBasedTargetSource {
/**
* Nonserializable test field to check that subclass
* state can't prevent serialization from working
*/
private TestBean thisFieldIsNotSerializable = new TestBean();
public Object getTarget() throws Exception {
return newPrototypeInstance();
}
public void releaseTarget(Object target) throws Exception {
// Do nothing
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2005 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.target;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.interceptor.SideEffectBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public class PrototypeTargetSourceTests {
/** Initial count value set in bean factory XML */
private static final int INITIAL_COUNT = 10;
private BeanFactory beanFactory;
@Before
public void setUp() throws Exception {
this.beanFactory = new XmlBeanFactory(new ClassPathResource("prototypeTests.xml", getClass()));
}
/**
* Test that multiple invocations of the prototype bean will result
* in no change to visible state, as a new instance is used.
* With the singleton, there will be change.
*/
@Test
public void testPrototypeAndSingletonBehaveDifferently() {
SideEffectBean singleton = (SideEffectBean) beanFactory.getBean("singleton");
assertEquals(INITIAL_COUNT, singleton.getCount() );
singleton.doWork();
assertEquals(INITIAL_COUNT + 1, singleton.getCount() );
SideEffectBean prototype = (SideEffectBean) beanFactory.getBean("prototype");
assertEquals(INITIAL_COUNT, prototype.getCount() );
prototype.doWork();
assertEquals(INITIAL_COUNT, prototype.getCount() );
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright 2002-2005 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.target;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.interceptor.SideEffectBean;
import org.springframework.beans.ITestBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public class ThreadLocalTargetSourceTests {
/** Initial count value set in bean factory XML */
private static final int INITIAL_COUNT = 10;
private XmlBeanFactory beanFactory;
@Before
public void setUp() throws Exception {
this.beanFactory = new XmlBeanFactory(new ClassPathResource("threadLocalTests.xml", getClass()));
}
/**
* We must simulate container shutdown, which should clear threads.
*/
protected void tearDown() {
this.beanFactory.destroySingletons();
}
/**
* Check we can use two different ThreadLocalTargetSources
* managing objects of different types without them interfering
* with one another.
*/
@Test
public void testUseDifferentManagedInstancesInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
ITestBean test = (ITestBean) beanFactory.getBean("threadLocal2");
assertEquals("Rod", test.getName());
assertEquals("Kerry", test.getSpouse().getName());
}
@Test
public void testReuseInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
}
/**
* Relies on introduction.
*/
@Test
public void testCanGetStatsViaMixin() {
ThreadLocalTargetSourceStats stats = (ThreadLocalTargetSourceStats) beanFactory.getBean("apartment");
// +1 because creating target for stats call counts
assertEquals(1, stats.getInvocationCount());
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
apartment.doWork();
// +1 again
assertEquals(3, stats.getInvocationCount());
// + 1 for states call!
assertEquals(3, stats.getHitCount());
apartment.doWork();
assertEquals(6, stats.getInvocationCount());
assertEquals(6, stats.getHitCount());
// Only one thread so only one object can have been bound
assertEquals(1, stats.getObjectCount());
}
@Test
public void testNewThreadHasOwnInstance() throws InterruptedException {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
apartment.doWork();
apartment.doWork();
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
class Runner implements Runnable {
public SideEffectBean mine;
public void run() {
this.mine = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, mine.getCount() );
mine.doWork();
assertEquals(INITIAL_COUNT + 1, mine.getCount() );
}
}
Runner r = new Runner();
Thread t = new Thread(r);
t.start();
t.join();
assertNotNull(r);
// Check it didn't affect the other thread's copy
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
// When we use other thread's copy in this thread
// it should behave like ours
assertEquals(INITIAL_COUNT + 3, r.mine.getCount() );
// Bound to two threads
assertEquals(2, ((ThreadLocalTargetSourceStats) apartment).getObjectCount());
}
/**
* Test for SPR-1442. Destroyed target should re-associated with thread and not throw NPE
*/
@Test
public void testReuseDestroyedTarget() {
ThreadLocalTargetSource source = (ThreadLocalTargetSource)this.beanFactory.getBean("threadLocalTs");
// try first time
source.getTarget();
source.destroy();
// try second time
try {
source.getTarget();
} catch(NullPointerException ex) {
fail("Should not throw NPE");
}
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="testBeanTarget" class="org.springframework.beans.TestBean" scope="prototype"/>
<bean id="targetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="testBeanTarget"/>
</bean>
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="targetSource"/>
</bean>
</beans>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
<property name="maxSize"><value>25</value></property>
</bean>
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="poolTargetSource" /></property>
<property name="targetMethod"><value>getPoolingConfigMixin</value></property>
</bean>
<bean id="nop" class="org.springframework.aop.interceptor.NopInterceptor"/>
<!--
This will create a bean for each thread ("apartment")
-->
<bean id="pooled" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
<property name="interceptorNames"><value>nop</value></property>
</bean>
<bean id="pooledNoInterceptors" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
</bean>
<bean id="pooledWithMixin" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
<property name="interceptorNames"><value>poolConfigAdvisor</value></property>
<!-- Necessary as have a mixin and want to avoid losing the class,
because there's no target interface -->
<property name="proxyTargetClass"><value>true</value></property>
</bean>
<!-- Serialization tests using serializable target and advice -->
<bean id="serializableNop" class="org.springframework.aop.interceptor.SerializableNopInterceptor" />
<bean id="prototypePerson" class="org.springframework.beans.SerializablePerson" scope="prototype"/>
<bean id="personPoolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName"><value>prototypePerson</value></property>
<property name="maxSize"><value>10</value></property>
</bean>
<bean id="pooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="personPoolTargetSource"/></property>
<property name="interceptorNames"><value>serializableNop</value></property>
</bean>
<bean id="maxSizePooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="prototypePerson"/>
<property name="maxSize" value="10"/>
<property name="maxWait" value="1"/>
</bean>
</property>
<property name="interceptorNames"><value>serializableNop</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target" class="org.springframework.beans.TestBean" lazy-init="true">
<property name="age"><value>10</value></property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSourceTests$CustomLazyInitTargetSource">
<property name="targetBeanName"><idref local="target"/></property>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2002-2007 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.target.dynamic;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public class RefreshableTargetSourceTests {
/**
* Test what happens when checking for refresh but not refreshing object.
*/
@Test
public void testRefreshCheckWithNonRefresh() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource();
ts.setRefreshCheckDelay(0);
Object a = ts.getTarget();
Thread.sleep(1);
Object b = ts.getTarget();
assertEquals("Should be one call to freshTarget to get initial target", 1, ts.getCallCount());
assertSame("Returned objects should be the same - no refresh should occur", a, b);
}
/**
* Test what happens when checking for refresh and refresh occurs.
*/
@Test
public void testRefreshCheckWithRefresh() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(0);
Object a = ts.getTarget();
Thread.sleep(100);
Object b = ts.getTarget();
assertEquals("Should have called freshTarget twice", 2, ts.getCallCount());
assertNotSame("Should be different objects", a, b);
}
/**
* Test what happens when no refresh occurs.
*/
@Test
public void testWithNoRefreshCheck() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(-1);
Object a = ts.getTarget();
Object b = ts.getTarget();
assertEquals("Refresh target should only be called once", 1, ts.getCallCount());
assertSame("Objects should be the same - refresh check delay not elapsed", a, b);
}
@Test
public void testRefreshOverTime() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(100);
Object a = ts.getTarget();
Object b = ts.getTarget();
assertEquals("Objects should be same", a, b);
Thread.sleep(50);
Object c = ts.getTarget();
assertEquals("A and C should be same", a, c);
Thread.sleep(60);
Object d = ts.getTarget();
assertNotNull("D should not be null", d);
assertFalse("A and D should not be equal", a.equals(d));
Object e = ts.getTarget();
assertEquals("D and E should be equal", d, e);
Thread.sleep(110);
Object f = ts.getTarget();
assertFalse("E and F should be different", e.equals(f));
}
private static class CountingRefreshableTargetSource extends AbstractRefreshableTargetSource {
private int callCount;
private boolean requiresRefresh;
public CountingRefreshableTargetSource() {
}
public CountingRefreshableTargetSource(boolean requiresRefresh) {
this.requiresRefresh = requiresRefresh;
}
protected Object freshTarget() {
this.callCount++;
return new Object();
}
public int getCallCount() {
return this.callCount;
}
protected boolean requiresRefresh() {
return this.requiresRefresh;
}
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="target1" class="org.springframework.aop.interceptor.SideEffectBean">
<property name="count"><value>10</value></property>
</bean>
<bean id="target2" class="org.springframework.aop.interceptor.SideEffectBean" scope="singleton">
<property name="count"><value>20</value></property>
</bean>
<!--
Hot swappable target source. Note the use of Type 3 IoC.
-->
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg><ref local="target1"/></constructor-arg>
</bean>
<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="swapper"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target1" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
<property name="sourceSet">
<set>
<value>10</value>
</set>
</property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="java.util.Set"/>
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName" value="target1"/>
</bean>
</property>
</bean>
<bean id="target2" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
<property name="sourceSet">
<set>
<value>20</value>
</set>
</property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces" value="true"/>
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName" value="target2"/>
<property name="targetClass" value="java.util.Set"/>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target" class="org.springframework.beans.TestBean" lazy-init="true">
<property name="age"><value>10</value></property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName"><idref local="target"/></property>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="test" class="org.springframework.aop.interceptor.SideEffectBean">
<property name="count"><value>10</value></property>
</bean>
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.NopInterceptor" />
<bean id="singleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,test</value></property>
</bean>
<!--
This will create a bean that creates a new target on each invocation.
-->
<bean id="prototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="prototypeTargetSource"/></property>
<property name="interceptorNames"><value>debugInterceptor</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="threadLocalTs" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.NopInterceptor" />
<!--
We want to invoke the getStatsMixin method on our ThreadLocal invoker
-->
<bean id="statsAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="threadLocalTs" /></property>
<property name="targetMethod"><value>getStatsMixin</value></property>
</bean>
<!--
This will create a bean for each thread ("apartment")
-->
<bean id="apartment" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,statsAdvisor</value></property>
<property name="targetSource"><ref local="threadLocalTs"/></property>
<!-- Necessary as have a mixin and want to avoid losing the class,
because there's no target interface -->
<property name="proxyTargetClass"><value>true</value></property>
</bean>
<!-- ================ Definitions for second ThreadLocalTargetSource ====== -->
<bean id="test" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="wife" class="org.springframework.beans.TestBean">
<property name="name"><value>Kerry</value></property>
</bean>
<bean id="threadLocalTs2" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName"><value>test</value></property>
</bean>
<bean id="threadLocal2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="threadLocalTs2"/></property>
</bean>
</beans>