/*
* 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.config.java.plugin.context;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScopeMetadataResolver;
/**
* TODO: JAVADOC
* Parser for the <context:component-scan/> element.
*
* @author Mark Fisher
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @since 2.5
*/
class GeneralizedComponentScanBeanDefinitionParser {
/*
private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";
private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";
private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";
private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";
private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";
private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";
private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";
private static final String INCLUDE_FILTER_ELEMENT = "include-filter";
private static final String FILTER_TYPE_ATTRIBUTE = "type";
private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";
*/
public void parse(ComponentScanDeclaration scanDec, BeanDefinitionRegistry registry) {
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(registry, scanDec);
if(scanDec.isAnnotationConfig())
AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
// TODO: the code below is a workaround. Should be able to call
/* scanner.doScan(scanDec.getBasePackages()) */
// directly, but it is currently package-private.
try {
Method doScan = ClassPathBeanDefinitionScanner.class.getDeclaredMethod("doScan", String[].class);
doScan.setAccessible(true);
// explicitly cast to Object to coerce varargs invocation
doScan.invoke(scanner, (Object) scanDec.getBasePackages());
} catch (Exception ex) {
throw new RuntimeException("Error when trying to reflectively invoke scanner.doScan()", ex);
}
}
protected ClassPathBeanDefinitionScanner configureScanner(BeanDefinitionRegistry registry, ComponentScanDeclaration scanDec) {
// Delegate bean definition registration to scanner class.
ClassPathBeanDefinitionScanner scanner = createScanner(registry, scanDec.isUseDefaultFilters());
if (scanDec.getResourcePattern() != null) {
scanner.setResourcePattern(scanDec.getResourcePattern());
}
try {
parseBeanNameGenerator(scanner, scanDec);
}
catch (Exception ex) {
throw new RuntimeException(ex);
//registry.getReaderContext().error(ex.getMessage(), element, ex.getCause());
}
try {
parseScope(scanner, scanDec);
}
catch (Exception ex) {
throw new RuntimeException(ex);
//registry.getReaderContext().error(ex.getMessage(), element, ex.getCause());
}
/*
try {
parseTypeFilters(scanner, scanDec);
}
catch (Exception ex) {
throw new RuntimeException(ex);
//registry.getReaderContext().error(ex.getMessage(), element, ex.getCause());
}
*/
return scanner;
}
protected ClassPathBeanDefinitionScanner createScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
return new ClassPathBeanDefinitionScanner(registry, useDefaultFilters);
}
protected void parseBeanNameGenerator(ClassPathBeanDefinitionScanner scanner, ComponentScanDeclaration scanDec) {
if (scanDec.getNameGenerator() != null) {
BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
scanDec.getNameGenerator(), BeanNameGenerator.class,
scanner.getResourceLoader().getClassLoader());
scanner.setBeanNameGenerator(beanNameGenerator);
}
}
/*
protected void registerComponents(
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
Object source = readerContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
for (Iterator it = beanDefinitions.iterator(); it.hasNext();) {
BeanDefinitionHolder beanDefHolder = (BeanDefinitionHolder) it.next();
AbstractBeanDefinition beanDef = (AbstractBeanDefinition) beanDefHolder.getBeanDefinition();
beanDef.setSource(readerContext.extractSource(beanDef.getSource()));
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
}
// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
}
if (annotationConfig) {
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
}
readerContext.fireComponentRegistered(compositeDef);
}
@SuppressWarnings("unchecked")
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
try {
if ("annotation".equals(filterType)) {
return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
}
else if ("assignable".equals(filterType)) {
return new AssignableTypeFilter(classLoader.loadClass(expression));
}
else if ("regex".equals(filterType)) {
return new RegexPatternTypeFilter(Pattern.compile(expression));
}
else if ("aspectj".equals(filterType)) {
return new AspectJTypeFilter(expression, classLoader);
}
else {
throw new IllegalArgumentException("Unsupported filter type: " + filterType);
}
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Type filter class not found: " + expression, ex);
}
}
protected void parseTypeFilters(ClassPathBeanDefinitionScanner scanner, ComponentScanDeclaration scanDec) {
// Parse exclude and include filter elements.
ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
NodeList nodeList = scanDec.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
String localName = node.getLocalName();
if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
scanner.addIncludeFilter(typeFilter);
}
else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
scanner.addExcludeFilter(typeFilter);
}
}
}
}
*/
protected void parseScope(ClassPathBeanDefinitionScanner scanner, ComponentScanDeclaration scanDec) {
// Register ScopeMetadataResolver if class name provided.
if (scanDec.getScopeResolver() != null) {
if (scanDec.getScopedProxy() != null) {
throw new IllegalArgumentException(
"Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
}
ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
scanDec.getScopeResolver(), ScopeMetadataResolver.class,
scanner.getResourceLoader().getClassLoader());
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
scanner.setScopedProxyMode(scanDec.getScopedProxy());
}
private Object instantiateUserDefinedStrategy(Class<?> userStrategy, Class<?> strategyType, ClassLoader classLoader) {
String strategyTypeName = userStrategy.getClass().getTypeParameters()[0].toString();
String className = userStrategy.getName();
Object result = null;
try {
result = userStrategy.newInstance();
}
catch (Exception ex) {
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
strategyTypeName + "]. A zero-argument constructor is required", ex);
}
return result;
}
}
|