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}