This is an automated email from the ASF dual-hosted git repository. thiagohp pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push: new 2c75fdbf2 TAP5-2756: allow non-soft references in the page cache 2c75fdbf2 is described below commit 2c75fdbf2cb07ca926144541a41e572a48bc878c Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br> AuthorDate: Sat Jun 17 18:59:39 2023 -0300 TAP5-2756: allow non-soft references in the page cache --- .../internal/services/PageSourceImpl.java | 55 +++++++++++++++++----- .../apache/tapestry5/modules/PageLoadModule.java | 20 ++++++++ .../pageload/PageCachingReferenceTypeService.java | 38 +++++++++++++++ .../tapestry5/services/pageload/ReferenceType.java | 34 +++++++++++++ .../integration/app1/services/AppModule.java | 10 ++++ 5 files changed, 145 insertions(+), 12 deletions(-) diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java index fe92fe3df..48a004fd8 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java @@ -40,8 +40,10 @@ import org.apache.tapestry5.services.ComponentMessages; import org.apache.tapestry5.services.ComponentTemplates; import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer; import org.apache.tapestry5.services.pageload.ComponentResourceSelector; +import org.apache.tapestry5.services.pageload.PageCachingReferenceTypeService; import org.apache.tapestry5.services.pageload.PageClassLoaderContext; import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager; +import org.apache.tapestry5.services.pageload.ReferenceType; import org.slf4j.Logger; public class PageSourceImpl implements PageSource @@ -56,6 +58,8 @@ public class PageSourceImpl implements PageSource private final PageClassLoaderContextManager pageClassLoaderContextManager; + private final PageCachingReferenceTypeService pageCachingReferenceTypeService; + private final Logger logger; final private boolean productionMode; @@ -100,12 +104,13 @@ public class PageSourceImpl implements PageSource } - private final Map<CachedPageKey, SoftReference<Page>> pageCache = CollectionFactory.newConcurrentMap(); + private final Map<CachedPageKey, Object> pageCache = CollectionFactory.newConcurrentMap(); public PageSourceImpl(PageLoader pageLoader, ComponentRequestSelectorAnalyzer selectorAnalyzer, ComponentDependencyRegistry componentDependencyRegistry, ComponentClassResolver componentClassResolver, PageClassLoaderContextManager pageClassLoaderContextManager, + PageCachingReferenceTypeService pageCachingReferenceTypeService, @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode, @Symbol(SymbolConstants.MULTIPLE_CLASSLOADERS) boolean multipleClassLoaders, Logger logger) @@ -115,6 +120,7 @@ public class PageSourceImpl implements PageSource this.componentDependencyRegistry = componentDependencyRegistry; this.componentClassResolver = componentClassResolver; this.productionMode = productionMode; + this.pageCachingReferenceTypeService = pageCachingReferenceTypeService; this.multipleClassLoaders = multipleClassLoaders; this.pageClassLoaderContextManager = pageClassLoaderContextManager; this.logger = logger; @@ -151,9 +157,11 @@ public class PageSourceImpl implements PageSource while (true) { - SoftReference<Page> ref = pageCache.get(key); - - Page page = ref == null ? null : ref.get(); + + Page page; + Object object = pageCache.get(key); + + page = toPage(object); if (page != null) { @@ -181,9 +189,15 @@ public class PageSourceImpl implements PageSource page = pageLoader.loadPage(canonicalPageName, selector); - ref = new SoftReference<Page>(page); - - pageCache.put(key, ref); + 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) { @@ -298,10 +312,10 @@ public class PageSourceImpl implements PageSource if (componentClassResolver.isPage(className)) { pageName = componentClassResolver.resolvePageClassNameToPageName(className); - final Iterator<Entry<CachedPageKey, SoftReference<Page>>> iterator = pageCache.entrySet().iterator(); + final Iterator<Entry<CachedPageKey, Object>> iterator = pageCache.entrySet().iterator(); while (iterator.hasNext()) { - final Entry<CachedPageKey, SoftReference<Page>> entry = iterator.next(); + final Entry<CachedPageKey, Object> entry = iterator.next(); final String entryPageName = entry.getKey().pageName; if (entryPageName.equalsIgnoreCase(pageName)) { @@ -324,12 +338,29 @@ public class PageSourceImpl implements PageSource public Set<Page> getAllPages() { - return F.flow(pageCache.values()).map(new Mapper<SoftReference<Page>, Page>() + return F.flow(pageCache.values()).map(new Mapper<Object, Page>() { - public Page map(SoftReference<Page> element) + public Page map(Object object) { - return element.get(); + return toPage(object); } }).removeNulls().toSet(); } + + private Page toPage(Object object) + { + Page page; + if (object instanceof SoftReference) + { + @SuppressWarnings("unchecked") + SoftReference<Page> ref = (SoftReference<Page>) object; + page = ref == null ? null : ref.get(); + } + else + { + page = (Page) object; + } + return page; + } + } diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/PageLoadModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/PageLoadModule.java index 1a993ab03..8e80d0bd1 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/PageLoadModule.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/PageLoadModule.java @@ -12,8 +12,11 @@ package org.apache.tapestry5.modules; +import java.util.List; + import org.apache.tapestry5.SymbolConstants; import org.apache.tapestry5.commons.MappedConfiguration; +import org.apache.tapestry5.commons.OrderedConfiguration; import org.apache.tapestry5.http.TapestryHttpSymbolConstants; import org.apache.tapestry5.internal.pageload.DefaultComponentRequestSelectorAnalyzer; import org.apache.tapestry5.internal.pageload.DefaultComponentResourceLocator; @@ -25,13 +28,17 @@ import org.apache.tapestry5.ioc.ServiceBinder; import org.apache.tapestry5.ioc.annotations.Marker; import org.apache.tapestry5.ioc.annotations.Startup; import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.services.ChainBuilder; +import org.apache.tapestry5.services.ComponentLibraryInfoSource; import org.apache.tapestry5.services.Core; import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer; import org.apache.tapestry5.services.pageload.ComponentResourceLocator; +import org.apache.tapestry5.services.pageload.PageCachingReferenceTypeService; import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager; import org.apache.tapestry5.services.pageload.PageClassLoaderContextManagerImpl; import org.apache.tapestry5.services.pageload.PagePreloader; import org.apache.tapestry5.services.pageload.PreloaderMode; +import org.apache.tapestry5.services.pageload.ReferenceType; /** * @since 5.3 @@ -89,5 +96,18 @@ public class PageLoadModule } } } + + public static PageCachingReferenceTypeService buildPageCachingReferenceTypeService( + List<PageCachingReferenceTypeService> configuration, + ChainBuilder chainBuilder) + { + return chainBuilder.build(PageCachingReferenceTypeService.class, configuration); + } + + public static void contributePageCachingReferenceTypeService( + OrderedConfiguration<PageCachingReferenceTypeService> configuration) + { + configuration.add("Fallback", p -> ReferenceType.SOFT, "after:*"); + } } diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageCachingReferenceTypeService.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageCachingReferenceTypeService.java new file mode 100644 index 000000000..d58d8f912 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageCachingReferenceTypeService.java @@ -0,0 +1,38 @@ +// Copyright 2023 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.services.pageload; + +import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration; + +/** + * A service which defines whether cache page instances should have soft references pointing to + * it (the default) or strong, non-garbage-collectable ones. This service is a chain of command + * of itself + * + * @see ReferenceType + * @since 5.8.3 + */ +@UsesOrderedConfiguration(PageCachingReferenceTypeService.class) +public interface PageCachingReferenceTypeService +{ + /** + * Defines which reference type should be used to cache instances of the given page. + * Returning <code>null</code> means this implementation doesn't handle wit the given page. + * @param canonicalPageName the name of the page. + * @return a ReferenceType object or <code>null</code> + */ + ReferenceType get(String canonicalPageName); + +} diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/ReferenceType.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/ReferenceType.java new file mode 100644 index 000000000..979931110 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/ReferenceType.java @@ -0,0 +1,34 @@ +// Copyright 2023 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package org.apache.tapestry5.services.pageload; + +import java.lang.ref.SoftReference; + +/** + * Defines the types of reference the page cache can use. + * @see PageCachingReferenceTypeService + * @since 5.8.3 + */ +public enum ReferenceType +{ + /** + * Use a soft reference ({@linkplain SoftReference}) to cached page instances. + */ + SOFT, + + /** + * Use a strong (normal) reference to cached page instances. + */ + STRONG +} \ No newline at end of file diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java index 5f57836bf..3851f684d 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java @@ -59,8 +59,10 @@ import org.apache.tapestry5.services.ValueEncoderFactory; import org.apache.tapestry5.services.ValueLabelProvider; import org.apache.tapestry5.services.compatibility.Compatibility; import org.apache.tapestry5.services.compatibility.Trait; +import org.apache.tapestry5.services.pageload.PageCachingReferenceTypeService; import org.apache.tapestry5.services.pageload.PagePreloader; import org.apache.tapestry5.services.pageload.PreloaderMode; +import org.apache.tapestry5.services.pageload.ReferenceType; import org.apache.tapestry5.services.rest.MappedEntityManager; import org.apache.tapestry5.services.security.ClientWhitelist; import org.apache.tapestry5.services.security.WhitelistAnalyzer; @@ -418,5 +420,13 @@ public class AppModule { configuration.add("org.apache.tapestry5.integration.app1.data.rest.entities"); } + + public static void contributePageCachingReferenceTypeService( + OrderedConfiguration<PageCachingReferenceTypeService> configuration) + { + // Just some pages to make sure the feature doesn't cause regressions. + configuration.add("Index", p -> p.equals("Index") || p.contains("Bean") + ? ReferenceType.STRONG : null); + } }