/*
* 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.impl;
import static com.alibaba.citrus.springext.ContributionType.*;
import static com.alibaba.citrus.test.TestUtil.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import com.alibaba.citrus.springext.ConfigurationPoint;
import com.alibaba.citrus.springext.Contribution;
import com.alibaba.citrus.springext.ContributionType;
import com.alibaba.citrus.springext.Schema;
import com.alibaba.citrus.springext.SourceInfo;
import com.alibaba.citrus.springext.support.ConfigurationPointSchemaSourceInfo;
import com.alibaba.citrus.springext.support.ConfigurationPointSourceInfo;
import com.alibaba.citrus.springext.support.ContributionSchemaSourceInfo;
import com.alibaba.citrus.springext.support.ContributionSourceInfo;
import com.alibaba.citrus.springext.support.SchemaSet;
import com.alibaba.citrus.test.TestEnvStatic;
import com.alibaba.citrus.test.runner.TestNameAware;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.FatalBeanException;
import org.springframework.core.io.Resource;
@RunWith(TestNameAware.class)
public class ConfigurationPointTests {
private static final Method instantiateContributionImplementationMethod;
private ConfigurationPointsImpl cps;
static {
TestEnvStatic.init();
instantiateContributionImplementationMethod
= getAccessibleMethod(ConfigurationPointImpl.class,
"instantiateContributionImplementation", new Class<?>[] { Contribution.class });
}
private Object instantiateContributionImplementation(ConfigurationPoint cp, Contribution contrib) throws Exception {
try {
return instantiateContributionImplementationMethod.invoke(cp, contrib);
} catch (InvocationTargetException e) {
throw (Exception) e.getTargetException();
}
}
@Test
public void test1_getContributions_noContributions() {
createConfigurationPoints("TEST-INF/test1/cps");
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
assertTrue(cp.getContributions().isEmpty());
}
@Test
public void test2_NoClass() throws Exception {
createConfigurationPoints("TEST-INF/test2/cps");
// quietly failed
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContribution("no-class", BEAN_DEFINITION_PARSER);
try {
instantiateContributionImplementation(cp, contrib);
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception("not defined", "contributionType=BEAN_DEFINITION_PARSER", "contributionName=no-class",
"configurationPoint=cp1", "namespaceUri=http://www.alibaba.com/test2/cp1"));
}
}
@Test
public void test2_ClassNotFound() throws Exception {
createConfigurationPoints("TEST-INF/test2/cps");
// quietly failed
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContribution("not-exist-class", BEAN_DEFINITION_PARSER);
try {
instantiateContributionImplementation(cp, contrib);
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception(ClassNotFoundException.class, "not found", "contributionType=BEAN_DEFINITION_PARSER",
"contribuitionClass=com.alibaba.NotExistClass", "contributionName=not-exist-class",
"configurationPoint=cp1", "namespaceUri=http://www.alibaba.com/test2/cp1"));
}
}
@Test
public void test2_WrongClass_beanDefinitionParsers() throws Exception {
createConfigurationPoints("TEST-INF/test2/cps");
// quietly failed
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContribution("wrong-class", BEAN_DEFINITION_PARSER);
try {
instantiateContributionImplementation(cp, contrib);
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception("Contribution class does not implement the BeanDefinitionParser interface",
"contributionType=BEAN_DEFINITION_PARSER", "contribuitionClass=java.lang.String",
"contributionName=wrong-class", "configurationPoint=cp1",
"namespaceUri=http://www.alibaba.com/test2/cp1"));
}
}
@Test
public void test2_WrongClass_beanDefinitionDecorators() throws Exception {
createConfigurationPoints("TEST-INF/test2/cps");
// quietly failed
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContribution("wrong-class", BEAN_DEFINITION_DECORATOR);
try {
instantiateContributionImplementation(cp, contrib);
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception("Contribution class does not implement the BeanDefinitionDecorator interface",
"contributionType=BEAN_DEFINITION_DECORATOR", "contribuitionClass=java.lang.String",
"contributionName=wrong-class", "configurationPoint=cp1",
"namespaceUri=http://www.alibaba.com/test2/cp1"));
}
}
@Test
public void test2_WrongClass_beanDefinitionDecoratorsForAttribute() throws Exception {
createConfigurationPoints("TEST-INF/test2/cps");
// quietly failed
ConfigurationPoint cp = cps.getConfigurationPointByName("cp1");
Contribution contrib = cp.getContribution("wrong-class", BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE);
try {
instantiateContributionImplementation(cp, contrib);
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception("Contribution class does not implement the BeanDefinitionDecorator interface",
"contributionType=BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE",
"contribuitionClass=java.lang.String", "contributionName=wrong-class",
"configurationPoint=cp1", "namespaceUri=http://www.alibaba.com/test2/cp1"));
}
}
@Test
public void test6_toString_and_getContribution() {
createConfigurationPoints("TEST-INF/test6/cps");
ConfigurationPointImpl cp = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp1");
assertEquals(6, cp.getContributions().size());
String str = cp.toString();
System.out.println("--");
System.out.println(str);
assertThat(str, containsString("ConfigurationPoint[cp1=http://www.alibaba.com/test6/cp1"));
assertThat(str, containsString("loaded contributions from TEST-INF/test6/cp1."));
int i = 0;
String[] strs = {
"Contribution[toConfigurationPoint=cp1, name=my1, type=BEAN_DEFINITION_PARSER, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionParser]",
"Contribution[toConfigurationPoint=cp1, name=my1, type=BEAN_DEFINITION_DECORATOR, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]",
"Contribution[toConfigurationPoint=cp1, name=my1, type=BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]",
"Contribution[toConfigurationPoint=cp1, name=my2, type=BEAN_DEFINITION_PARSER, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionParser2]",
"Contribution[toConfigurationPoint=cp1, name=my2, type=BEAN_DEFINITION_DECORATOR, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator2]",
"Contribution[toConfigurationPoint=cp1, name=my2, type=BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator2]" };
for (Contribution contrib : cp.getContributions()) {
assertThat(contrib.toString(), containsString(strs[i++]));
}
i = 0;
assertThat(cp.getContribution("my1", BEAN_DEFINITION_PARSER).toString(), containsString(strs[i++]));
assertThat(cp.getContribution("my1", BEAN_DEFINITION_DECORATOR).toString(), containsString(strs[i++]));
assertThat(cp.getContribution("my1", BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE).toString(),
containsString(strs[i++]));
assertThat(cp.getContribution("my2", BEAN_DEFINITION_PARSER).toString(), containsString(strs[i++]));
assertThat(cp.getContribution("my2", BEAN_DEFINITION_DECORATOR).toString(), containsString(strs[i++]));
assertThat(cp.getContribution("my2", BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE).toString(),
containsString(strs[i++]));
assertEquals(null, cp.getContribution("my3", BEAN_DEFINITION_PARSER));
try {
cp.getContribution(null, null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("name"));
}
try {
cp.getContribution("name", null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("type"));
}
}
@Test
public void test7_toString_nestedName() {
createConfigurationPoints("TEST-INF/test7/cps");
ConfigurationPointImpl cp = (ConfigurationPointImpl) cps.getConfigurationPointByName("dir/cp1");
assertEquals(6, cp.getContributions().size());
String str = cp.toString();
System.out.println("--");
System.out.println(str);
assertThat(str, containsString("ConfigurationPoint[dir/cp1=http://www.alibaba.com/test7/dir/cp1"));
assertThat(str, containsString("loaded contributions from TEST-INF/test7/dir-cp1."));
int i = 0;
String[] strs = {
"Contribution[toConfigurationPoint=dir/cp1, name=my1, type=BEAN_DEFINITION_PARSER, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionParser]",
"Contribution[toConfigurationPoint=dir/cp1, name=my1, type=BEAN_DEFINITION_DECORATOR, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]",
"Contribution[toConfigurationPoint=dir/cp1, name=my1, type=BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]",
"Contribution[toConfigurationPoint=dir/cp1, name=my2, type=BEAN_DEFINITION_PARSER, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionParser]",
"Contribution[toConfigurationPoint=dir/cp1, name=my2, type=BEAN_DEFINITION_DECORATOR, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]",
"Contribution[toConfigurationPoint=dir/cp1, name=my2, type=BEAN_DEFINITION_DECORATOR_FOR_ATTRIBUTE, class=com.alibaba.citrus.springext.contrib.MyBeanDefinitionDecorator]" };
for (Contribution contrib : cp.getContributions()) {
assertThat(contrib.toString(), containsString(strs[i++]));
}
}
@Test
public void test10_defaultElement() {
createConfigurationPoints("TEST-INF/test10/cps");
ConfigurationPointImpl cp1 = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp1");
ConfigurationPointImpl cp2 = (ConfigurationPointImpl) cps.getConfigurationPointByName("cp2");
assertEquals(null, cp1.getDefaultElementName()); // no default element
assertEquals("mybean", cp2.getDefaultElementName());
}
@Test
public void test10_contribNameSameAsDefaultElementName() {
createConfigurationPoints("TEST-INF/test10/cps2");
try {
cps.getConfigurationPointByName("cp1");
fail();
} catch (FatalBeanException e) {
assertThat(
e,
exception("Contribution has a same name as the default element name for configuration point",
"contributionType=BEAN_DEFINITION_PARSER",
"contribuitionClass=com.alibaba.citrus.springext.contrib.MyBeanDefinitionParser",
"contributionName=mybean", "configurationPoint=cp1",
"namespaceUri=http://www.alibaba.com/test10/cp1"));
}
}
@Test
public void test11_illegal_ns_format() {
createConfigurationPoints("TEST-INF/test11/cps1");
try {
cps.getConfigurationPointByName("cp1");
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("Illegal namespace URI", "http://www.alibaba.com/test11/cp1, illegal"));
}
createConfigurationPoints("TEST-INF/test11/cps2");
try {
cps.getConfigurationPointByName("cp2");
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("Illegal namespace URI", "http://www.alibaba.com/test11/cp2, =mybean"));
}
createConfigurationPoints("TEST-INF/test11/cps3");
try {
cps.getConfigurationPointByName("cp3");
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("Illegal namespace URI", ";defaultElement=mybean"));
}
}
@Test
public void test13_getDependingContributions() {
createConfigurationPoints("TEST-INF/test13/cps");
ConfigurationPointImpl cp1 = (ConfigurationPointImpl) cps.getConfigurationPointByName("my/services");
ConfigurationPointImpl cp2 = (ConfigurationPointImpl) cps.getConfigurationPointByName("my/services/service1/plugins");
Contribution contrib1 = cp1.getContribution("service1", ContributionType.BEAN_DEFINITION_PARSER);
Collection<Contribution> dependingContributions = cp2.getDependingContributions();
// Schema解析前,并不知道依赖关系。
assertEquals(0, dependingContributions.size());
new SchemaSet(cps);
// Schema解析后,就知道依赖关系。
assertEquals(1, dependingContributions.size());
assertSame(contrib1, dependingContributions.iterator().next());
assertEquals("service1", contrib1.getName());
assertSame(cp1, contrib1.getConfigurationPoint());
}
@Test
public void test12_sourceInfo_configurationPoints() throws Exception {
createConfigurationPoints("TEST-INF/test12/cps");
Resource resource;
// configuration point
ConfigurationPoint cp1 = cps.getConfigurationPointByName("my/services");
resource = assertSourceInfoAndGetResource(cp1, ConfigurationPointSourceInfo.class, null);
assertResource("TEST-INF/test12/cps", resource);
// configuration point schema
Schema cp1Schema = cp1.getSchemas().getMainSchema();
resource = assertSourceInfoAndGetResource(cp1Schema, ConfigurationPointSchemaSourceInfo.class, cp1);
assertResource(null, resource);
Schema cp1Schema2 = cp1.getSchemas().getVersionedSchema("2.0");
resource = assertSourceInfoAndGetResource(cp1Schema2, ConfigurationPointSchemaSourceInfo.class, cp1);
assertResource(null, resource);
// contribution
Contribution contrib1 = cp1.getContribution("myservice", ContributionType.BEAN_DEFINITION_PARSER);
resource = assertSourceInfoAndGetResource(contrib1, ContributionSourceInfo.class, cp1);
assertResource("TEST-INF/test12/my-services.bean-definition-parsers", resource);
Contribution contrib2 = cp1.getContribution("myservice-abc-xyz", ContributionType.BEAN_DEFINITION_DECORATOR);
resource = assertSourceInfoAndGetResource(contrib2, ContributionSourceInfo.class, cp1);
assertResource("TEST-INF/test12/my-services.bean-definition-decorators", resource);
// contribution schema
Schema contrib1Schema = contrib1.getSchemas().getMainSchema();
resource = assertSourceInfoAndGetResource(contrib1Schema, ContributionSchemaSourceInfo.class, contrib1);
assertResource("TEST-INF/test12/my/services/myservice.xsd", resource);
Schema contrib1Schema2 = contrib2.getSchemas().getVersionedSchema("2.0");
resource = assertSourceInfoAndGetResource(contrib1Schema2, ContributionSchemaSourceInfo.class, contrib2);
assertResource("TEST-INF/test12/my/services/myservice-abc-xyz-2.0.xsd", resource);
}
private void assertResource(String resourceName, Resource resource) throws Exception {
if (resourceName == null) {
assertNull(resource);
} else {
assertEquals(getClass().getClassLoader().getResource(resourceName), resource.getURL());
}
}
private Resource assertSourceInfoAndGetResource(Object obj, Class<? extends SourceInfo<?>> expectedInterface, Object parent) {
SourceInfo<?> sourceInfo = expectedInterface.cast(obj);
assertEquals(-1, sourceInfo.getLineNumber());
assertSame(parent, sourceInfo.getParent());
return sourceInfo.getSource() == null ? null
: getFieldValue(sourceInfo.getSource(), "springResource", Resource.class);
}
private void createConfigurationPoints(String location) {
cps = new ConfigurationPointsImpl((ClassLoader) null, location);
}
}