This is an automated email from the ASF dual-hosted git repository. thiagohp pushed a commit to branch better-page-invalidation in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/better-page-invalidation by this push: new f954dd70d TAP5-2742: fixing NestedBeanEditor test f954dd70d is described below commit f954dd70d2309cafa0c1dd76652a02f5aeda062c Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br> AuthorDate: Wed May 10 18:49:58 2023 -0300 TAP5-2742: fixing NestedBeanEditor test --- .../services/ComponentDependencyRegistry.java | 7 ++++ .../services/ComponentDependencyRegistryImpl.java | 46 ++++++++++++++++++---- .../internal/services/PageSourceImpl.java | 35 ++++++++++++---- .../internal/transform/InjectPageWorker.java | 15 +++++-- .../integration/app1/pages/NestedBeanDisplay.java | 5 ++- 5 files changed, 87 insertions(+), 21 deletions(-) diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistry.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistry.java index e2f10469a..5eebb690e 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistry.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistry.java @@ -77,9 +77,16 @@ public interface ComponentDependencyRegistry { /** * Returns the fully qualified names of the direct dependencies of a given component. + * Doesn't include dependencies that are pages. */ Set<String> getDependencies(String className); + /** + * Returns the fully qualified names of the direct dependencies of a given component, + * but just the ones that are pages. + */ + Set<String> getPageDependencies(String className); + /** * Signs up this registry to invalidation events from a given hub. */ diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImpl.java index 9e5198cef..e86c701ec 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImpl.java @@ -31,7 +31,9 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.WeakHashMap; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.tapestry5.ComponentResources; @@ -94,6 +96,8 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis final private TemplateParser templateParser; + final private Map<String, Boolean> isPageCache = new WeakHashMap<>(); + @SuppressWarnings("deprecation") final private ComponentTemplateLocator componentTemplateLocator; @@ -209,8 +213,6 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis add(component, superclass); } - Set<String> dynamicDependencies; - alreadyProcessed.add(className); for (Class<?> dependency : furtherDependencies) @@ -240,12 +242,12 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis // by listening separaterly to ComponentTemplateSource to invalidate caches // just when template changes. - ComponentModel mock = new ComponentModelMock(component, resolver.isPage(component.getName())); + final String className = component.getName(); + ComponentModel mock = new ComponentModelMock(component, isPage(className)); final Resource templateResource = componentTemplateLocator.locateTemplate(mock, Locale.getDefault()); String dependency; if (templateResource != null) { - final String className = component.getName(); final ComponentTemplate template = templateParser.parseTemplate(templateResource); for (TemplateToken token: template.getTokens()) { @@ -269,6 +271,22 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis } } } + + private boolean isNotPage(final String className) + { + return !isPage(className); + } + + private boolean isPage(final String className) + { + Boolean result = isPageCache.get(className); + if (result == null) + { + result = resolver.isPage(className); + isPageCache.put(className, result); + } + return result; + } private void registerComponentInstance(Field field, Consumer<String> processClassName) { @@ -491,9 +509,8 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis final Set<String> dependents = map.get(className); return dependents != null ? dependents : Collections.emptySet(); } - - @Override - public Set<String> getDependencies(String className) + + private Set<String> getDependencies(String className, Predicate<String> filter) { Set<String> dependencies = Collections.emptySet(); if (alreadyProcessed.contains(className)) @@ -501,12 +518,25 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis dependencies = map.entrySet().stream() .filter(e -> e.getValue().contains(className)) .map(e -> e.getKey()) + .filter(filter) .collect(Collectors.toSet()); } return dependencies; } + @Override + public Set<String> getDependencies(String className) + { + return getDependencies(className, this::isNotPage); + } + + @Override + public Set<String> getPageDependencies(String className) + { + return getDependencies(className, this::isPage); + } + private void add(ComponentPageElement component, ComponentPageElement dependency) { add(getClassName(component), getClassName(dependency)); @@ -570,7 +600,7 @@ public class ComponentDependencyRegistryImpl implements ComponentDependencyRegis } // Don't invalidate component dependency information when // PageClassloaderContextManager is merging contexts - // TODO is this still needed since the inception of INVALIDATIONS_ENABLED? + // TODO: is this still needed since the inception of INVALIDATIONS_ENABLED? else if (!pageClassloaderContextManager.isMerging()) { furtherDependents = new ArrayList<>(); 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 afcb51fdb..e95056278 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 @@ -143,12 +143,20 @@ public class PageSourceImpl implements PageSource // Avoiding problems in PlasticClassPool.createTransformation() // when the class being loaded has a page superclass final String className = componentClassResolver.resolvePageNameToClassName(canonicalPageName); - PageClassloaderContext context = pageClassloaderContextManager.get(className); - final Class<?> superclass = getSuperclass(className, context); - final String superclassName = superclass.getName(); - if (componentClassResolver.isPage(superclassName)) +// PageClassloaderContext context = pageClassloaderContextManager.get(className); +// final Class<?> superclass = getSuperclass(className, context); +// final String superclassName = superclass.getName(); +// if (componentClassResolver.isPage(superclassName)) +// { +// getPage(componentClassResolver.resolvePageClassNameToPageName(superclassName), false); +// } + final Set<String> pageDependencies = componentDependencyRegistry.getPageDependencies(className); + + preprocessPageClassLoaderContexts(className, pageDependencies); + + for (String pageClassName : pageDependencies) { - getPage(componentClassResolver.resolvePageClassNameToPageName(superclassName), false); + page = getPage(componentClassResolver.resolvePageClassNameToPageName(pageClassName), false); } // In rare race conditions, we may see the same page loaded multiple times across @@ -167,20 +175,31 @@ public class PageSourceImpl implements PageSource final ComponentPageElement rootElement = page.getRootElement(); componentDependencyRegistry.clear(rootElement); componentDependencyRegistry.register(rootElement); - context = pageClassloaderContextManager.get(className); - if (context.isUnknown()) + PageClassloaderContext context = pageClassloaderContextManager.get(className); + if (invalidateUnknownContext && context.isUnknown()) { componentDependencyRegistry.disableInvalidations(); pageClassloaderContextManager.invalidateAndFireInvalidationEvents(context); componentDependencyRegistry.enableInvalidations(); pageClassloaderContextManager.get(className); - return getPage(canonicalPageName); + return getPage(canonicalPageName, false); } } } } + private void preprocessPageClassLoaderContexts(String className, final Set<String> pageDependencies) { + for (int i = 0; i < 2; i++) + { + pageClassloaderContextManager.get(className); + for (String pageClassName : pageDependencies) + { + pageClassloaderContextManager.get(pageClassName); + } + } + } + private Class<?> getSuperclass(final String className, PageClassloaderContext context) { try { diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/InjectPageWorker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/InjectPageWorker.java index dc36b58f4..e7f4ba399 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/InjectPageWorker.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/InjectPageWorker.java @@ -1,4 +1,4 @@ -// Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation +// Copyright 2006, 2007, 2008, 2010, 2011, 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. @@ -16,6 +16,7 @@ package org.apache.tapestry5.internal.transform; import org.apache.tapestry5.annotations.InjectPage; import org.apache.tapestry5.commons.ObjectCreator; +import org.apache.tapestry5.internal.services.ComponentDependencyRegistry; import org.apache.tapestry5.ioc.internal.util.InternalUtils; import org.apache.tapestry5.ioc.services.PerthreadManager; import org.apache.tapestry5.model.MutableComponentModel; @@ -65,22 +66,26 @@ public class InjectPageWorker implements ComponentClassTransformWorker2 private final PerthreadManager perThreadManager; - public InjectPageWorker(ComponentSource componentSource, ComponentClassResolver resolver, PerthreadManager perThreadManager) + private final ComponentDependencyRegistry componentDependencyRegistry; + + public InjectPageWorker(ComponentSource componentSource, ComponentClassResolver resolver, PerthreadManager perThreadManager, + ComponentDependencyRegistry componentDependencyRegistry) { this.componentSource = componentSource; this.resolver = resolver; this.perThreadManager = perThreadManager; + this.componentDependencyRegistry = componentDependencyRegistry; } public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) { for (PlasticField field : plasticClass.getFieldsWithAnnotation(InjectPage.class)) { - addInjectedPage(field); + addInjectedPage(field, model); } } - private void addInjectedPage(PlasticField field) + private void addInjectedPage(PlasticField field, MutableComponentModel model) { InjectPage annotation = field.getAnnotation(InjectPage.class); @@ -94,5 +99,7 @@ public class InjectPageWorker implements ComponentClassTransformWorker2 .resolvePageClassNameToPageName(field.getTypeName()) : pageName; field.setConduit(new InjectedPageConduit(field.getPlasticClass().getClassName(), fieldName, injectedPageName)); + + componentDependencyRegistry.register(field, model); } } diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/NestedBeanDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/NestedBeanDisplay.java index 157ef7df8..02c434039 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/NestedBeanDisplay.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/NestedBeanDisplay.java @@ -24,7 +24,10 @@ public class NestedBeanDisplay @Property private Person parent; - Object initialize(Person person) + // Visibility changed from package-private to public due to smarter page invalidation + // (classes in different classloaders cannot access non-public method + // TODO: maybe find some way to avoid this? + public Object initialize(Person person) { parent = person;