public Page getPage()

in tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java [158:255]


    public Page getPage(String canonicalPageName, boolean invalidateUnknownContext, Set<String> alreadyProcessed)
    {
        ComponentResourceSelector selector = selectorAnalyzer.buildSelectorForRequest();

        CachedPageKey key = new CachedPageKey(canonicalPageName, selector);

        // The while loop looks superfluous, but it helps to ensure that the Page instance,
        // with all of its mutable construction-time state, is properly published to other
        // threads (at least, as I understand Brian Goetz's explanation, it should be).
        
        while (true)
        {
            
            Page page;
            Object object = pageCache.get(key);
            
            page = toPage(object);

            if (page != null)
            {
                return page;
            }
            
            final String className = componentClassResolver.resolvePageNameToClassName(canonicalPageName);
            if (multipleClassLoaders)
            {
                
                // Avoiding problems in PlasticClassPool.createTransformation()
                // when the class being loaded has a page superclass
                final List<String> pageDependencies = getPageDependencies(className);
                CALL_STACK.get().add(className);
                
                for (String dependencyClassName : pageDependencies)
                {
                    // Avoiding infinite recursion caused by circular dependencies
                    if (!alreadyProcessed.contains(dependencyClassName) &&
                            !CALL_STACK.get().contains(className))
                    {
                        alreadyProcessed.add(dependencyClassName);
                        
                        // Avoiding infinite recursion when, through component overriding,
                        // a dependency resolves to the same canonical page name as the
                        // one already requested in this call.
                        final String dependencyPageName = componentClassResolver.resolvePageClassNameToPageName(dependencyClassName);
                        final String resolvedDependencyPageClass = componentClassResolver.resolvePageNameToClassName(dependencyPageName);
                        if (!canonicalPageName.equals(dependencyPageName)
                                && !className.equals(resolvedDependencyPageClass)
                                && !isAbstract(dependencyClassName))
                        {
                            page = getPage(dependencyPageName, 
                                    invalidateUnknownContext, alreadyProcessed);
                        }
                    }
                }
                
            }

            // In rare race conditions, we may see the same page loaded multiple times across
            // different threads. The last built one will "evict" the others from the page cache,
            // and the earlier ones will be GCed.

            page = pageLoader.loadPage(canonicalPageName, selector);

            final ReferenceType referenceType = pageCachingReferenceTypeService.get(canonicalPageName);
            if (referenceType.equals(ReferenceType.SOFT))
            {
                pageCache.put(key, new SoftReference<Page>(page));
            }
            else
            {
                pageCache.put(key, page);
            }
            
            if (!productionMode)
            {
                final ComponentPageElement rootElement = page.getRootElement();
                componentDependencyRegistry.clear(rootElement);
                componentDependencyRegistry.register(rootElement.getComponent().getClass());
                PageClassLoaderContext context = pageClassLoaderContextManager.get(className);
                
                if (context.isUnknown() && multipleClassLoaders)
                {
                    this.pageCache.remove(key);
                    if (invalidateUnknownContext)
                    {
                        pageClassLoaderContextManager.invalidateAndFireInvalidationEvents(context);
                        getPageDependencies(className);
                    }
                    context.getClassNames().clear();
                    // Avoiding bad invalidations
                    return getPage(canonicalPageName, false, alreadyProcessed);
                }
            }
            
        }
        
        
    }