    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;
    050
    051/**
    052 * @since 5.3
    053 */
    054@SuppressWarnings("deprecation")
    055@Marker(Core.class)
    056public class PageLoadModule
    057{
    058
    059    /**
    060     * Contributes factory defaults that may be overridden.
    061     */
    062    public static void contributeFactoryDefaults(MappedConfiguration<String, Object> configuration)
    063    {
    064        configuration.add(SymbolConstants.MULTIPLE_CLASSLOADERS, false);
    065        configuration.add(SymbolConstants.COMPONENT_DEPENDENCY_FILE, ComponentDependencyRegistry.FILENAME);
    066    }
    067
    068    public static void bind(ServiceBinder binder)
    069    {
    070        binder.bind(ComponentRequestSelectorAnalyzer.class, DefaultComponentRequestSelectorAnalyzer.class);
    071        binder.bind(ComponentResourceLocator.class, DefaultComponentResourceLocator.class);
    072        binder.bind(ComponentTemplateSource.class, ComponentTemplateSourceImpl.class);
    073        binder.bind(PagePreloader.class, PagePreloaderImpl.class);
    074        binder.bind(PageClassLoaderContextManager.class, PageClassLoaderContextManagerImpl.class);
    075    }
    076
    077    @Startup
    078    public static void preloadPages(PagePreloader preloader,
    079                                    @Symbol(SymbolConstants.PRELOADER_MODE)
    080                                    PreloaderMode mode,
    081                                    @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
    082                                    boolean productionMode)
    083    {
    084        if (mode.isEnabledFor(productionMode))
    085        {
    086            preloader.preloadPages();
    087        }
    088    }
    089
    090    @Startup
    091    @Order("before:*")
    092    public void preloadPageClassLoaderContexts(
    093            PageClassLoaderContextManager pageClassLoaderContextManager,
    094            ComponentDependencyRegistry componentDependencyRegistry,
    095            @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode,
    096            @Symbol(SymbolConstants.MULTIPLE_CLASSLOADERS) boolean multipleClassLoaders)
    097    {
    098        if (!productionMode && multipleClassLoaders)
    099        {
    100            // Preload the page activation context tree for the already known classes
    101            for (int i = 0; i < 5; i++)
    102            {
    103                for (String className : componentDependencyRegistry.getClassNames())
    104                {
    105                    pageClassLoaderContextManager.get(className);
    106                }
    107            }
    108        }
    109        // Preload the dependency information for all pages
    110        // when in production mode. Without that, exceptions during
    111        // page assembly will occurr. This should add just a few
    112        // seconds to page initialization. If it takes too long,
    113        // we can create a version of preload() that accepts a boolean
    114        // parameter defining whether templates should be parsed or not
    115        // (the exception occurrs when a superclass isn't loaded
    116        // and transformed before a subclass)
    117        else if (productionMode)
    118        {
    119            pageClassLoaderContextManager.preload();
    120        }
    121    }
    122
    123    public static PageCachingReferenceTypeService buildPageCachingReferenceTypeService(
    124            List<PageCachingReferenceTypeService> configuration,
    125            ChainBuilder chainBuilder)
    126    {
    127        return chainBuilder.build(PageCachingReferenceTypeService.class, configuration);
    128    }
    129
    130    public static void contributePageCachingReferenceTypeService(
    131            OrderedConfiguration<PageCachingReferenceTypeService> configuration)
    132    {
    133        configuration.add("Fallback", p -> ReferenceType.SOFT, "after:*");
    134    }
    135
    136    public static ComponentDependencyRegistry buildComponentDependencyRegistry(
    137            InternalComponentInvalidationEventHub internalComponentInvalidationEventHub,
    138            ResourceChangeTracker resourceChangeTracker,
    139            ComponentTemplateSource componentTemplateSource,
    140            PageClassLoaderContextManager pageClassLoaderContextManager,
    141            ComponentInstantiatorSource componentInstantiatorSource,
    142            ComponentClassResolver componentClassResolver,
    143            TemplateParser templateParser,
    144            ComponentTemplateLocator componentTemplateLocator,
    145            PerthreadManager perthreadManager,
    146            @Symbol(SymbolConstants.COMPONENT_DEPENDENCY_FILE) String componentDependencyFile,
    147            @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode)
    148    {
    149        ComponentDependencyRegistryImpl componentDependencyRegistry =
    150                new ComponentDependencyRegistryImpl(
    151                        pageClassLoaderContextManager,
    152                        componentInstantiatorSource.getProxyFactory().getPlasticManager(),
    153                        componentClassResolver,
    154                        templateParser,
    155                        componentTemplateLocator,
    156                        componentDependencyFile,
    157                        productionMode);
    158        componentDependencyRegistry.listen(internalComponentInvalidationEventHub);
    159        componentDependencyRegistry.listen(resourceChangeTracker);
    160        componentDependencyRegistry.listen(componentTemplateSource.getInvalidationEventHub());
    161        // TODO: remove
    162        componentDependencyRegistry.setupThreadCleanup(perthreadManager);
    163        return componentDependencyRegistry;
    164    }
    165
    166}