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    
015    package org.apache.tapestry5.spring;
016    
017    import org.apache.tapestry5.internal.spring.SymbolBeanFactoryPostProcessor;
018    import org.apache.tapestry5.ioc.MappedConfiguration;
019    import org.apache.tapestry5.ioc.OrderedConfiguration;
020    import org.apache.tapestry5.ioc.annotations.Contribute;
021    import org.apache.tapestry5.ioc.annotations.Marker;
022    import org.apache.tapestry5.ioc.annotations.Primary;
023    import org.apache.tapestry5.ioc.services.ChainBuilder;
024    import org.apache.tapestry5.ioc.services.FactoryDefaults;
025    import org.apache.tapestry5.ioc.services.SymbolProvider;
026    import org.apache.tapestry5.ioc.services.SymbolSource;
027    import org.apache.tapestry5.services.ApplicationInitializer;
028    import org.apache.tapestry5.services.ApplicationInitializerFilter;
029    import org.apache.tapestry5.services.Context;
030    import org.slf4j.Logger;
031    import org.springframework.context.ApplicationContext;
032    import org.springframework.core.SpringVersion;
033    import org.springframework.web.context.ConfigurableWebApplicationContext;
034    
035    import javax.servlet.ServletContext;
036    import 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     */
044    public 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    }