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}