    001// Copyright 2010-2013 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
    015package org.apache.tapestry5.internal.services;
    016
    017import org.apache.tapestry5.internal.InternalConstants;
    018import org.apache.tapestry5.internal.structure.Page;
    019import org.apache.tapestry5.ioc.ScopeConstants;
    020import org.apache.tapestry5.ioc.annotations.PostInjection;
    021import org.apache.tapestry5.ioc.annotations.Scope;
    022import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    023import org.apache.tapestry5.ioc.services.PerthreadManager;
    024import org.apache.tapestry5.ioc.util.ExceptionUtils;
    025import org.apache.tapestry5.services.ComponentClassResolver;
    026import org.apache.tapestry5.services.RequestGlobals;
    027import org.slf4j.Logger;
    028
    029import java.util.Map;
    030
    031/**
    032 * In Tapestry 5.1, the implementation of this worked with the page pool (a pool of page instances, reserved
    033 * to individual requests/threads). Page pooling was deprecated in 5.2 and removed in 5.3.
    034 *
    035 * @since 5.2
    036 */
    037@Scope(ScopeConstants.PERTHREAD)
    038public class RequestPageCacheImpl implements RequestPageCache, Runnable
    039{
    040    private final Logger logger;
    041
    042    private final ComponentClassResolver resolver;
    043
    044    private final PageSource pageSource;
    045
    046    private final RequestGlobals requestGlobals;
    047
    048    private final Map<String, Page> cache = CollectionFactory.newMap();
    049
    050    public RequestPageCacheImpl(Logger logger, ComponentClassResolver resolver, PageSource pageSource, RequestGlobals requestGlobals)
    051    {
    052        this.logger = logger;
    053        this.resolver = resolver;
    054        this.pageSource = pageSource;
    055        this.requestGlobals = requestGlobals;
    056    }
    057
    058    @PostInjection
    059    public void listenForThreadCleanup(PerthreadManager perthreadManager)
    060    {
    061        perthreadManager.addThreadCleanupCallback(this);
    062    }
    063
    064    public void run()
    065    {
    066        for (Page page : cache.values())
    067        {
    068            try
    069            {
    070                page.detached();
    071            } catch (Throwable t)
    072            {
    073                logger.error("Error detaching page {}: {}", page, ExceptionUtils.toMessage(t), t);
    074            }
    075        }
    076    }
    077
    078    public Page get(String pageName)
    079    {
    080        String canonical = resolver.canonicalizePageName(pageName);
    081
    082        Page page = cache.get(canonical);
    083
    084        if (page == null)
    085        {
    086            page = pageSource.getPage(canonical);
    087
    088            try
    089            {
    090                page.attached();
    091            } catch (Throwable t)
    092            {
    093                throw new RuntimeException(String.format("Unable to attach page %s: %s", canonical,
    094                        ExceptionUtils.toMessage(t)), t);
    095            }
    096
    097            cache.put(canonical, page);
    098        }
    099
    100        // A bit of a hack but whatever.
    101        if (canonical.equals(requestGlobals.getActivePageName()))
    102        {
    103            requestGlobals.getRequest().setAttribute(InternalConstants.ACTIVE_PAGE_LOADED, true);
    104        }
    105
    106        return page;
    107    }
    108}