/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.springext.util;
import static com.alibaba.citrus.test.TestEnvStatic.*;
import static com.alibaba.citrus.test.TestUtil.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static org.easymock.EasyMock.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.config.BeanDefinition.*;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.citrus.springext.ConfigurationPoint;
import com.alibaba.citrus.springext.Contribution;
import com.alibaba.citrus.springext.impl.ConfigurationPointImpl;
import com.alibaba.citrus.springext.impl.ConfigurationPointsImpl;
import com.alibaba.citrus.springext.support.context.XmlApplicationContext;
import com.alibaba.citrus.springext.support.context.XmlBeanFactory;
import com.alibaba.citrus.springext.util.SpringExtUtil.ConstructorArg;
import org.hamcrest.Matcher;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.FileSystemResource;
public class SpringExtUtilTests {
private static BeanFactory factory;
private ConfigurationPointsImpl cps;
private HttpServletRequest request;
@BeforeClass
public static void initFactory() {
factory = new XmlBeanFactory(new FileSystemResource(new File(srcdir, "beans.xml")));
}
@Test
public void autowireAndInitialize() throws Exception {
ApplicationContext context = new XmlApplicationContext(new FileSystemResource(new File(srcdir, "beans.xml")));
class Bean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Autowired
private com.alibaba.citrus.springext.support.context.MyClass myClass;
private String beanName;
private ApplicationContext context;
private boolean inited;
public void setBeanName(String name) {
this.beanName = name;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public void afterPropertiesSet() throws Exception {
this.inited = true;
}
}
Bean bean = new Bean();
assertSame(bean,
SpringExtUtil.autowireAndInitialize(bean, context, AutowireCapableBeanFactory.AUTOWIRE_NO, "myname"));
assertNotNull(bean.myClass);
assertEquals("myname", bean.beanName);
assertSame(context, bean.context);
assertTrue(bean.inited);
}
@Test
public void getBeanByType() {
Map<?, ?> container = SpringExtUtil.getBeanOfType(factory, Map.class);
assertNotNull(container);
assertEquals(4, container.size());
String str = SpringExtUtil.getBeanOfType(factory, String.class);
assertNull(str);
List<Object> list = createArrayList(container.values());
// 包含一个str, 一个dateformat,两个date
for (Iterator<Object> i = list.iterator(); i.hasNext(); ) {
Object o = i.next();
if (o instanceof String) {
i.remove();
} else if (o instanceof DateFormat) {
i.remove();
} else if (o instanceof Date) {
long t = ((Date) o).getTime();
assertTrue(t == 1 || t == 0);
i.remove();
} else {
fail();
}
}
assertTrue(list.isEmpty());
}
@Test(expected = IllegalArgumentException.class)
public void getCp_Contrib_Null() throws Exception {
SpringExtUtil.getSiblingConfigurationPoint("cp1", (Contribution) null);
}
@Test(expected = IllegalArgumentException.class)
public void getCp_Cp_Null() throws Exception {
SpringExtUtil.getSiblingConfigurationPoint("cp1", (ConfigurationPoint) null);
}
@Test(expected = IllegalArgumentException.class)
public void getCp_Name_Null() throws Exception {
createConfigurationPoints("TEST-INF/test6/cps");
ConfigurationPointImpl cp = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp1");
SpringExtUtil.getSiblingConfigurationPoint(null, cp);
}
@Test(expected = IllegalArgumentException.class)
public void getCp_Name_notFound() throws Exception {
createConfigurationPoints("TEST-INF/test6/cps");
ConfigurationPointImpl cp = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContributions().iterator().next();
SpringExtUtil.getSiblingConfigurationPoint("not-found", contrib);
}
@Test
public void test6_getCp() throws Exception {
createConfigurationPoints("TEST-INF/test6/cps");
ConfigurationPointImpl cp = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContributions().iterator().next();
assertSame(cp, SpringExtUtil.getSiblingConfigurationPoint("cp1", contrib));
}
@Test(expected = IllegalArgumentException.class)
public void generateBeanName_null() throws Exception {
SpringExtUtil.generateBeanName(null, (BeanDefinitionRegistry) factory);
}
@Test
public void generateBeanName() throws Exception {
// newName在container中尚不存在,直接返回。
assertEquals("newName", SpringExtUtil.generateBeanName("newName", (BeanDefinitionRegistry) factory));
assertEquals("newName",
SpringExtUtil.generateBeanName("newName", (BeanDefinitionRegistry) factory, null, false));
// testName和testName#0已经在container中存在,故返回testName#1。
assertEquals("testName#1", SpringExtUtil.generateBeanName("testName", (BeanDefinitionRegistry) factory));
assertEquals("testName#1",
SpringExtUtil.generateBeanName("testName", (BeanDefinitionRegistry) factory, null, false));
}
@Test
public void generateInnerBeanName() throws Exception {
assertTrue(SpringExtUtil.generateBeanName("newName", (BeanDefinitionRegistry) factory,
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(), true).matches("newName#[a-z0-9]+"));
assertTrue(SpringExtUtil.generateBeanName("testName", (BeanDefinitionRegistry) factory,
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(), true).matches("testName#[a-z0-9]+"));
}
private void createConfigurationPoints(String location) {
cps = new ConfigurationPointsImpl((ClassLoader) null, location);
}
@Test
public void createConstructorArg_args() {
// no beanType
try {
SpringExtUtil.createConstructorArg(null, true, 0);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("beanType"));
}
// argTypes not specified, but has more than 1 constructors
try {
SpringExtUtil.createConstructorArg(MyClass.class, true, 0);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("2 constructors found, please specify argTypes"));
}
// argTypes not specified
SpringExtUtil.createConstructorArg(MyClass2.class, true, 0);
SpringExtUtil.createConstructorArg(MyClass2.class, true, 1);
// argIndex out of bound
try {
SpringExtUtil.createConstructorArg(MyClass.class, true, -1, HttpServletRequest.class, MyObject.class);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("argIndex is out of bound: -1"));
}
try {
SpringExtUtil.createConstructorArg(MyClass.class, true, 2, HttpServletRequest.class, MyObject.class);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("argIndex is out of bound: 2"));
}
// constructor not found
try {
SpringExtUtil.createConstructorArg(MyClass.class, true, String.class);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception(NoSuchMethodException.class, "Could not find constructor"));
}
}
@Test
public void createConstructorArg_BeanFactory() throws Exception {
BeanFactory context = createMock(BeanFactory.class);
// not ApplicationContext or ConfigurableBeanFactory, required
ConstructorArg arg = new ConstructorArg(MyClass.class.getConstructors()[0], HttpServletRequest.class, 0, true);
arg.setBeanFactory(context);
try {
arg.getObject();
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("could not get object of " + HttpServletRequest.class.getName()
+ ": no Application Context"));
}
// not ApplicationContext or ConfigurableBeanFactory, optional
arg = new ConstructorArg(MyClass.class.getConstructors()[0], HttpServletRequest.class, 0, false);
arg.setBeanFactory(context);
assertNull(arg.getObject());
}
@Test
public void createConstructorArg_ConfigurableBeanFactory() {
createConstructorArg("configbf");
}
@Test
public void createConstructorArg_ApplicationContext() {
createConstructorArg("appcontext");
}
private void createConstructorArg(String contextType) {
BeanFactory context;
MyClass myClass;
// optional arg, no value injected
context = createApplicationContext_forConstructorArg(contextType, false, false, true);
myClass = (MyClass) context.getBean("myClass");
assertNull(myClass.getRequest());
assertNull(myClass.getObject());
// optional arg, with value injected
context = createApplicationContext_forConstructorArg(contextType, false, true, true);
myClass = (MyClass) context.getBean("myClass");
assertSame(request, myClass.getRequest());
assertNotNull(myClass.getObject());
// required arg, no value injected
try {
context = createApplicationContext_forConstructorArg(contextType, true, false, true); // appcontext.refresh时报错
context.getBean("myClass"); // beanfactory.getBean时报错
fail();
} catch (BeanCreationException e) {
assertThat(e, exception(NoSuchBeanDefinitionException.class, "myClass"));
@SuppressWarnings("unchecked")
Matcher<Throwable> m = anyOf(exception(NoSuchBeanDefinitionException.class, "HttpServletRequest"),
exception(NoSuchBeanDefinitionException.class, "MyObject"));
assertThat(e, m);
}
// required arg, with value injected
context = createApplicationContext_forConstructorArg(contextType, true, true, true);
myClass = (MyClass) context.getBean("myClass");
assertSame(request, myClass.getRequest());
assertNotNull(myClass.getObject());
// required arg, with value injected
context = createApplicationContext_forConstructorArg(contextType, true, true, true);
myClass = (MyClass) context.getBean("myClass");
assertSame(request, myClass.getRequest());
assertNotNull(myClass.getObject());
// required arg, with value injected, prototype
context = createApplicationContext_forConstructorArg(contextType, true, true, false);
MyClass myClass1 = (MyClass) context.getBean("myClass");
MyClass myClass2 = (MyClass) context.getBean("myClass");
assertSame(request, myClass1.getRequest());
assertSame(request, myClass2.getRequest());
assertNotNull(myClass1.getObject());
assertNotNull(myClass2.getObject());
assertNotSame(myClass1.getObject(), myClass2.getObject());
}
private BeanFactory createApplicationContext_forConstructorArg(String contextType, boolean required,
boolean withValue, boolean singleton) {
BeanDefinitionRegistry context = null;
if ("appcontext".equals(contextType)) {
context = new GenericApplicationContext();
} else {
context = new DefaultListableBeanFactory();
}
// create MyClass bean
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyClass.class);
builder.setScope(singleton ? SCOPE_SINGLETON : SCOPE_PROTOTYPE);
// construct with an optional values of type HttpServletRequest and MyObject
SpringExtUtil.addConstructorArg(builder, required, 0, HttpServletRequest.class, MyObject.class);
builder.addConstructorArgValue(SpringExtUtil.createConstructorArg(MyClass.class, required, 1,
HttpServletRequest.class, MyObject.class));
// register bean
context.registerBeanDefinition("myClass", builder.getBeanDefinition());
if (withValue) {
// register value as a resolvableDependency
request = createMock(HttpServletRequest.class);
try {
ConfigurableListableBeanFactory clbf;
try {
clbf = (ConfigurableListableBeanFactory) context;
} catch (ClassCastException e) {
clbf = (ConfigurableListableBeanFactory) ((ApplicationContext) context)
.getAutowireCapableBeanFactory();
}
clbf.registerResolvableDependency(HttpServletRequest.class, request);
} catch (ClassCastException e) {
}
// register value as a bean
BeanDefinitionBuilder bean = BeanDefinitionBuilder.genericBeanDefinition(MyObject.class);
bean.setScope(SCOPE_PROTOTYPE);
context.registerBeanDefinition("myObject", bean.getBeanDefinition());
}
// start context
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).refresh();
}
return (BeanFactory) context;
}
@Test
public void createPropertyRef_args() {
// no beanName
try {
SpringExtUtil.createOptionalPropertyRef(null, null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("beanName"));
}
try {
SpringExtUtil.createOptionalPropertyRef(" ", null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("beanName"));
}
// no beanType
try {
SpringExtUtil.createOptionalPropertyRef("myBean", null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("beanType"));
}
}
@Test
public void createPropertyRef() {
ApplicationContext context;
MyClass myClass;
// required, no Value
try {
createApplicationContext_forPropertyRef(true, false, true);
fail();
} catch (BeanCreationException e) {
assertThat(e, exception(NoSuchBeanDefinitionException.class, "myClass", "myObject"));
}
// optional, no Value
context = createApplicationContext_forPropertyRef(false, false, true);
myClass = (MyClass) context.getBean("myClass");
assertNull(myClass.getObject());
// required, with Value
context = createApplicationContext_forPropertyRef(true, true, true);
myClass = (MyClass) context.getBean("myClass");
assertNotNull(myClass.getObject());
// optional, with Value
context = createApplicationContext_forPropertyRef(false, true, true);
myClass = (MyClass) context.getBean("myClass");
assertNotNull(myClass.getObject());
// prototype
context = createApplicationContext_forPropertyRef(false, true, false);
MyClass myClass1 = (MyClass) context.getBean("myClass");
MyClass myClass2 = (MyClass) context.getBean("myClass");
assertNotNull(myClass1.getObject());
assertNotNull(myClass2.getObject());
assertNotSame(myClass1.getObject(), myClass2.getObject());
}
private ApplicationContext createApplicationContext_forPropertyRef(boolean required, boolean withValue,
boolean singleton) {
GenericApplicationContext context = new GenericApplicationContext();
// create MyClass bean
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyClass.class);
builder.setScope(singleton ? SCOPE_SINGLETON : SCOPE_PROTOTYPE);
SpringExtUtil.addPropertyRef(builder, "object", "myObject", MyObject.class, required);
context.registerBeanDefinition("myClass", builder.getBeanDefinition());
if (withValue) {
// register value as a bean
BeanDefinitionBuilder bean = BeanDefinitionBuilder.genericBeanDefinition(MyObject.class);
bean.setScope(SCOPE_PROTOTYPE);
context.registerBeanDefinition("myObject", bean.getBeanDefinition());
}
// start context
context.refresh();
return context;
}
public static class MyClass {
private HttpServletRequest request;
private MyObject object;
public MyClass() {
}
public MyClass(HttpServletRequest request, MyObject object) {
this.request = request;
this.object = object;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public MyObject getObject() {
return object;
}
public void setObject(MyObject object) {
this.object = object;
}
}
public static class MyClass2 extends MyClass {
public MyClass2(HttpServletRequest request, MyObject object) {
super(request, object);
}
}
public static class MyObject {
}
}