001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.modules;
014
015import java.util.List;
016
017import org.apache.tapestry5.SymbolConstants;
018import org.apache.tapestry5.commons.MappedConfiguration;
019import org.apache.tapestry5.commons.OrderedConfiguration;
020import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
021import org.apache.tapestry5.internal.pageload.DefaultComponentRequestSelectorAnalyzer;
022import org.apache.tapestry5.internal.pageload.DefaultComponentResourceLocator;
023import org.apache.tapestry5.internal.pageload.PagePreloaderImpl;
024import org.apache.tapestry5.internal.services.ComponentDependencyRegistry;
025import org.apache.tapestry5.internal.services.ComponentDependencyRegistryImpl;
026import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
027import org.apache.tapestry5.internal.services.ComponentTemplateSource;
028import org.apache.tapestry5.internal.services.ComponentTemplateSourceImpl;
029import org.apache.tapestry5.internal.services.InternalComponentInvalidationEventHub;
030import org.apache.tapestry5.internal.services.TemplateParser;
031import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
032import org.apache.tapestry5.ioc.ServiceBinder;
033import org.apache.tapestry5.ioc.annotations.Marker;
034import org.apache.tapestry5.ioc.annotations.Order;
035import org.apache.tapestry5.ioc.annotations.Startup;
036import org.apache.tapestry5.ioc.annotations.Symbol;
037import org.apache.tapestry5.ioc.services.ChainBuilder;
038import org.apache.tapestry5.ioc.services.PerthreadManager;
039import org.apache.tapestry5.services.ComponentClassResolver;
040import org.apache.tapestry5.services.Core;
041import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer;
042import org.apache.tapestry5.services.pageload.ComponentResourceLocator;
043import org.apache.tapestry5.services.pageload.PageCachingReferenceTypeService;
044import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager;
045import org.apache.tapestry5.services.pageload.PageClassLoaderContextManagerImpl;
046import org.apache.tapestry5.services.pageload.PagePreloader;
047import org.apache.tapestry5.services.pageload.PreloaderMode;
048import org.apache.tapestry5.services.pageload.ReferenceType;
049import org.apache.tapestry5.services.templates.ComponentTemplateLocator;
050import org.slf4j.LoggerFactory;
051
052/**
053 * @since 5.3
054 */
055@SuppressWarnings("deprecation")
056@Marker(Core.class)
057public class PageLoadModule
058{
059    
060    /**
061     * Contributes factory defaults that may be overridden.
062     */
063    public static void contributeFactoryDefaults(MappedConfiguration<String, Object> configuration)
064    {
065        configuration.add(SymbolConstants.MULTIPLE_CLASSLOADERS, false);
066        configuration.add(SymbolConstants.COMPONENT_DEPENDENCY_FILE, ComponentDependencyRegistry.FILENAME);
067    }
068    
069    public static void bind(ServiceBinder binder)
070    {
071        binder.bind(ComponentRequestSelectorAnalyzer.class, DefaultComponentRequestSelectorAnalyzer.class);
072        binder.bind(ComponentResourceLocator.class, DefaultComponentResourceLocator.class);
073        binder.bind(ComponentTemplateSource.class, ComponentTemplateSourceImpl.class);
074        binder.bind(PagePreloader.class, PagePreloaderImpl.class);
075        binder.bind(PageClassLoaderContextManager.class, PageClassLoaderContextManagerImpl.class);
076    }
077
078    @Startup
079    public static void preloadPages(PagePreloader preloader,
080                                    @Symbol(SymbolConstants.PRELOADER_MODE)
081                                    PreloaderMode mode,
082                                    @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
083                                    boolean productionMode)
084    {
085        if (mode.isEnabledFor(productionMode))
086        {
087            preloader.preloadPages();
088        }
089    }
090    
091    @Startup
092    @Order("before:*")
093    public void preloadPageClassLoaderContexts(
094            PageClassLoaderContextManager pageClassLoaderContextManager,
095            ComponentDependencyRegistry componentDependencyRegistry,
096            @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode,
097            @Symbol(SymbolConstants.MULTIPLE_CLASSLOADERS) boolean multipleClassLoaders)
098    {
099        if (!productionMode && multipleClassLoaders)
100        {
101            // If we have component dependency information previously stored in 
102            // a file, then we just preload the page classloader contexts.
103            // Otherwise, we gather component dependency information then
104            // preload the page classloader contexts.
105            if (componentDependencyRegistry.isStoredDependencyInformationPresent())
106            {
107                pageClassLoaderContextManager.preloadContexts();
108            }
109            else 
110            {
111                LoggerFactory.getLogger(PageClassLoaderContextManager.class)
112                    .warn("If the component dependency process is taking too long, "
113                            + "consider writing its results to a file using the "
114                            + " 'Store dependency information' button "
115                            + "in the /t5dashboard/pages page.");
116                pageClassLoaderContextManager.preload();
117            }
118        }
119    }
120    
121    public static PageCachingReferenceTypeService buildPageCachingReferenceTypeService(
122            List<PageCachingReferenceTypeService> configuration,
123            ChainBuilder chainBuilder) 
124    {
125        return chainBuilder.build(PageCachingReferenceTypeService.class, configuration);
126    }
127    
128    public static void contributePageCachingReferenceTypeService(
129            OrderedConfiguration<PageCachingReferenceTypeService> configuration)
130    {
131        configuration.add("Fallback", p -> ReferenceType.SOFT, "after:*");
132    }
133    
134    public static ComponentDependencyRegistry buildComponentDependencyRegistry(
135            InternalComponentInvalidationEventHub internalComponentInvalidationEventHub,
136            ResourceChangeTracker resourceChangeTracker,
137            ComponentTemplateSource componentTemplateSource,
138            PageClassLoaderContextManager pageClassLoaderContextManager,
139            ComponentInstantiatorSource componentInstantiatorSource,
140            ComponentClassResolver componentClassResolver,
141            TemplateParser templateParser,
142            ComponentTemplateLocator componentTemplateLocator,
143            PerthreadManager perthreadManager,
144            @Symbol(SymbolConstants.COMPONENT_DEPENDENCY_FILE) String componentDependencyFile,
145            @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode)
146    {
147        ComponentDependencyRegistryImpl componentDependencyRegistry = 
148                new ComponentDependencyRegistryImpl(
149                        pageClassLoaderContextManager,
150                        componentInstantiatorSource.getProxyFactory().getPlasticManager(),
151                        componentClassResolver,
152                        templateParser,
153                        componentTemplateLocator,
154                        componentDependencyFile,
155                        productionMode);
156        componentDependencyRegistry.listen(internalComponentInvalidationEventHub);
157        componentDependencyRegistry.listen(resourceChangeTracker);
158        componentDependencyRegistry.listen(componentTemplateSource.getInvalidationEventHub());
159        // TODO: remove
160        componentDependencyRegistry.setupThreadCleanup(perthreadManager);
161        return componentDependencyRegistry;
162    }
163
164}