001// Copyright 2008, 2009, 2011 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.spring;
016
017import org.apache.tapestry5.internal.spring.SymbolBeanFactoryPostProcessor;
018import org.apache.tapestry5.ioc.MappedConfiguration;
019import org.apache.tapestry5.ioc.OrderedConfiguration;
020import org.apache.tapestry5.ioc.annotations.Contribute;
021import org.apache.tapestry5.ioc.annotations.Marker;
022import org.apache.tapestry5.ioc.annotations.Primary;
023import org.apache.tapestry5.ioc.services.ChainBuilder;
024import org.apache.tapestry5.ioc.services.FactoryDefaults;
025import org.apache.tapestry5.ioc.services.SymbolProvider;
026import org.apache.tapestry5.ioc.services.SymbolSource;
027import org.apache.tapestry5.services.ApplicationInitializer;
028import org.apache.tapestry5.services.ApplicationInitializerFilter;
029import org.apache.tapestry5.services.Context;
030import org.slf4j.Logger;
031import org.springframework.context.ApplicationContext;
032import org.springframework.core.SpringVersion;
033import org.springframework.web.context.ConfigurableWebApplicationContext;
034
035import javax.servlet.ServletContext;
036import java.util.List;
037
038/**
039 * Module for Tapestry/Spring Integration. This module exists to force the load of the Spring ApplicationContext as part
040 * of Tapestry application initialization.
041 *
042 * @since 5.1.0.0
043 */
044public class SpringModule
045{
046    private final Logger logger;
047
048    public SpringModule(Logger logger)
049    {
050        this.logger = logger;
051    }
052
053    @Contribute(ApplicationInitializer.class)
054    public void reportSpringContextDetailsAtStartup(
055            OrderedConfiguration<ApplicationInitializerFilter> configuration, final ApplicationContext springContext)
056    {
057        ApplicationInitializerFilter filter = new ApplicationInitializerFilter()
058        {
059            public void initializeApplication(Context context, ApplicationInitializer initializer)
060            {
061                logger.info(String.format("Spring version %s with %,d defined beans.",
062                        SpringVersion.getVersion(),
063                        springContext.getBeanDefinitionCount()));
064
065                initializer.initializeApplication(context);
066            }
067        };
068
069        configuration.add("SpringContextInitialization", filter);
070    }
071
072    @Contribute(SymbolProvider.class)
073    @FactoryDefaults
074    public static void defaultExternalSpringContextOff(MappedConfiguration<String, Object> configuration)
075    {
076        configuration.add(SpringConstants.USE_EXTERNAL_SPRING_CONTEXT, false);
077    }
078
079    /**
080     * Defines a chain-of-command for handling application context customization. This allows the Spring context to be
081     * configured before it is initially {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh()
082     * refreshed}.
083     */
084    @Marker(Primary.class)
085    public static ApplicationContextCustomizer buildApplicationContextCustomizer(
086            List<ApplicationContextCustomizer> configuration,
087            ChainBuilder builder)
088    {
089        return builder.build(ApplicationContextCustomizer.class, configuration);
090    }
091
092    @Contribute(ApplicationContextCustomizer.class)
093    public static void addSymbolSourceAsPropertyCustomizerForSpringBeans(
094            OrderedConfiguration<ApplicationContextCustomizer> configuration,
095            final SymbolSource symbolSource)
096    {
097        ApplicationContextCustomizer beanFactoryPostProcessorCustomizer = new ApplicationContextCustomizer()
098        {
099
100            public void customizeApplicationContext(ServletContext servletContext,
101                                                    ConfigurableWebApplicationContext applicationContext)
102            {
103                applicationContext.addBeanFactoryPostProcessor(new SymbolBeanFactoryPostProcessor(symbolSource));
104
105            }
106        };
107
108        configuration.add("BeanFactoryPostProcessorCustomizer", beanFactoryPostProcessorCustomizer);
109    }
110}