- /*
- * Copyright 2002-2010 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.bootstrap.config;
- import java.lang.reflect.Field;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.DisposableBean;
- import org.springframework.beans.factory.NoSuchBeanDefinitionException;
- import org.springframework.beans.factory.config.BeanDefinition;
- import org.springframework.beans.factory.parsing.ComponentRegistrarAdapter;
- import org.springframework.beans.factory.parsing.ProblemReporter;
- import org.springframework.beans.factory.parsing.ReaderContext;
- import org.springframework.beans.factory.support.BeanDefinitionBuilder;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.xml.BeanDefinitionParser;
- import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
- import org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader;
- import org.springframework.beans.factory.xml.ParserContext;
- import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
- import org.springframework.beans.factory.xml.XmlReaderContext;
- import org.springframework.context.ConfigurableApplicationContext;
- import org.springframework.context.Lifecycle;
- import org.springframework.context.config.FeatureSpecification;
- import org.springframework.context.config.SpecificationContext;
- import org.springframework.context.support.GenericApplicationContext;
- import org.springframework.core.env.ConfigurableEnvironment;
- import org.springframework.core.env.DefaultEnvironment;
- import org.springframework.core.env.Environment;
- import org.springframework.core.io.Resource;
- import org.springframework.util.StringUtils;
- import org.springframework.util.xml.DomUtils;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- /**
- * @author Dave Syer
- *
- */
- public class GenericFeatureSpecificationParser implements BeanDefinitionParser {
- /** Constant for the id attribute */
- public static final String ID_ATTRIBUTE = "id";
- /** Constant for the expose-features attribute */
- private static final String EXPOSE_FEATURES_ATTRIBUTE = "expose-features";
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- final GenericApplicationContext bootstrapApplicationContext = new GenericApplicationContext();
- Environment environment = parserContext.getDelegate().getEnvironment();
- if (environment instanceof ConfigurableEnvironment) {
- bootstrapApplicationContext.setEnvironment((ConfigurableEnvironment) environment);
- }
- registerBootstrapApplicationContext(bootstrapApplicationContext, element, parserContext);
- registerBeanDefinitionsInBootstrapApplicationContext(bootstrapApplicationContext, element, parserContext);
- bootstrapApplicationContext.refresh();
- if ("true".equals(element.getAttribute(EXPOSE_FEATURES_ATTRIBUTE))) {
- exposeFeatures(bootstrapApplicationContext, parserContext);
- }
- return null;
- }
- /**
- * Copied from AbstractSpecificationBeanDefinitionParser. Adapt the given ParserContext into a SpecificationContext.
- */
- private static SpecificationContext specificationContextFrom(ParserContext parserContext) {
- SpecificationContext specContext = new SpecificationContext();
- specContext.setRegistry(parserContext.getRegistry());
- specContext.setRegistrar(new ComponentRegistrarAdapter(parserContext));
- specContext.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
- try {
- // again, STS constraints around the addition of the new getEnvironment()
- // method in 3.1.0 (it's not present in STS current spring version, 3.0.5)
- // TODO 3.1 GA: remove this block prior to 3.1 GA
- specContext.setEnvironment(parserContext.getDelegate().getEnvironment());
- } catch (NoSuchMethodError ex) {
- specContext.setEnvironment(new DefaultEnvironment());
- }
- try {
- // access the reader context's problem reporter reflectively in order to
- // compensate for tooling (STS) constraints around introduction of changes
- // to parser context / reader context classes.
- // TODO 3.1 GA: remove this block prior to 3.1 GA
- Field field = ReaderContext.class.getDeclaredField("problemReporter");
- field.setAccessible(true);
- ProblemReporter problemReporter = (ProblemReporter) field.get(parserContext.getReaderContext());
- specContext.setProblemReporter(problemReporter);
- } catch (Exception ex) {
- throw new IllegalStateException("Could not access field 'ReaderContext#problemReporter' on object "
- + parserContext.getReaderContext(), ex);
- }
- return specContext;
- }
- public void registerBootstrapApplicationContext(final GenericApplicationContext context, Element element,
- ParserContext parserContext) {
- BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(ContextHolder.class)
- .addConstructorArgValue(context).getBeanDefinition();
- String id = element.getAttribute(ID_ATTRIBUTE);
- String beanName = parserContext.getReaderContext().generateBeanName(beanDefinition);
- if (StringUtils.hasText(id)) {
- context.setId(id);
- beanName = id;
- }
- parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);
- }
- public void exposeFeatures(final GenericApplicationContext context, ParserContext parserContext) {
- SpecificationContext specificationContext = specificationContextFrom(parserContext);
- for (FeatureSpecification specification : context.getBeansOfType(FeatureSpecification.class).values()) {
- specification.execute(specificationContext);
- }
- }
- private void registerBeanDefinitionsInBootstrapApplicationContext(BeanDefinitionRegistry registry, Element element,
- ParserContext parserContext) {
- LocalXmlBeanDefinitionReader beanDefinitionReader = new LocalXmlBeanDefinitionReader( //
- registry, //
- parserContext.getDelegate().getEnvironment(), //
- parserContext.getReaderContext().getResource()//
- );
- beanDefinitionReader.register(element);
- }
- private static class LocalXmlBeanDefinitionReader extends XmlBeanDefinitionReader {
- private Resource resource;
- public LocalXmlBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment, Resource resource) {
- super(registry);
- this.resource = resource;
- setEnvironment(environment);
- }
- public void register(Element element) {
- XmlReaderContext readerContext = createReaderContext(resource);
- LocalBeanDefinitionDocumentReader documentReader = new LocalBeanDefinitionDocumentReader(
- this.getEnvironment());
- documentReader.registerBeanDefinitions(element, readerContext);
- }
- }
- private static class LocalBeanDefinitionDocumentReader extends DefaultBeanDefinitionDocumentReader {
- public LocalBeanDefinitionDocumentReader(Environment environment) {
- super.setEnvironment(environment);
- }
- public void registerBeanDefinitions(Element element, XmlReaderContext readerContext) {
- try {
- registerBeanDefinitions((Document) null, readerContext);
- } catch (NullPointerException e) {
- // Hack: ignore
- }
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, element, null);
- for (Element child : DomUtils.getChildElements(element)) {
- if ("bean".equals(child.getNodeName())) {
- processBeanDefinition(child, delegate);
- } else {
- doRegisterBeanDefinitions(child);
- }
- }
- }
- }
- private static class ContextHolder implements BeanFactory, Lifecycle, DisposableBean {
- final ConfigurableApplicationContext context;
- @SuppressWarnings("unused")
- public ContextHolder(ConfigurableApplicationContext context) {
- super();
- this.context = context;
- }
- public void destroy() throws Exception {
- context.close();
- }
- public void start() {
- context.start();
- }
- public void stop() {
- context.stop();
- }
- public boolean isRunning() {
- return context.isRunning();
- }
- public Object getBean(String name) throws BeansException {
- return context.getBean(name);
- }
- public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
- return context.getBean(name, requiredType);
- }
- public <T> T getBean(Class<T> requiredType) throws BeansException {
- return context.getBean(requiredType);
- }
- public Object getBean(String name, Object... args) throws BeansException {
- return context.getBean(name, args);
- }
- public boolean containsBean(String name) {
- return context.containsBean(name);
- }
- public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
- return context.isSingleton(name);
- }
- public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException {
- return context.isTypeMatch(name, targetType);
- }
- public String[] getAliases(String name) {
- return context.getAliases(name);
- }
- public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
- return context.isPrototype(name);
- }
- public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
- return context.getType(name);
- }
- }
- }