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 40550e1ad TAP5-2742: introducingtypes of dependencies
40550e1ad is described below

commit 40550e1ad0732db04612a6d64646f36a34242b27
Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br>
AuthorDate: Sat May 13 12:21:27 2023 -0300

    TAP5-2742: introducingtypes of dependencies
---
 .../tapestry5/corelib/pages/PageCatalog.java       |  10 +-
 .../ComponentDependencyGraphvizGeneratorImpl.java  |  50 +++---
 .../services/ComponentDependencyRegistry.java      |  36 +++-
 .../services/ComponentDependencyRegistryImpl.java  | 193 ++++++++++++---------
 .../services/ComponentInstantiatorSourceImpl.java  |   6 +-
 .../internal/services/PageSourceImpl.java          |  43 ++++-
 .../PageClassloaderContextManagerImpl.java         |  11 +-
 .../ComponentDependencyRegistryImplTest.java       |  87 ++++++++--
 8 files changed, 293 insertions(+), 143 deletions(-)

diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
index e887c0da1..31c557649 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
@@ -46,6 +46,7 @@ import org.apache.tapestry5.http.services.Request;
 import org.apache.tapestry5.internal.PageCatalogTotals;
 import 
org.apache.tapestry5.internal.services.ComponentDependencyGraphvizGenerator;
 import org.apache.tapestry5.internal.services.ComponentDependencyRegistry;
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import org.apache.tapestry5.internal.services.PageSource;
 import org.apache.tapestry5.internal.services.ReloadHelper;
 import org.apache.tapestry5.internal.structure.ComponentPageElement;
@@ -370,7 +371,14 @@ public class PageCatalog
     
     public List<String> getDependencies() 
     {
-        List<String> dependencies = new 
ArrayList<>(componentDependencyRegistry.getDependencies(getSelectedPageClassName()));
+        final String selectedPageClassName = getSelectedPageClassName();
+        List<String> dependencies = new ArrayList<>();
+        dependencies.addAll(
+                
componentDependencyRegistry.getDependencies(selectedPageClassName, 
DependencyType.USAGE));
+        dependencies.addAll(
+                
componentDependencyRegistry.getDependencies(selectedPageClassName, 
DependencyType.INJECT_PAGE));
+        dependencies.addAll(
+                
componentDependencyRegistry.getDependencies(selectedPageClassName, 
DependencyType.SUPERCLASS));
         Collections.sort(dependencies);
         return dependencies;
     }
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
index 81a179e46..005f2a26a 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
@@ -17,6 +17,7 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import org.apache.tapestry5.services.ComponentClassResolver;
 
 public class ComponentDependencyGraphvizGeneratorImpl implements 
ComponentDependencyGraphvizGenerator {
@@ -48,34 +49,41 @@ public class ComponentDependencyGraphvizGeneratorImpl 
implements ComponentDepend
         
         final Set<String> allClasses = new HashSet<>();
         
-        for (String className : classNames)
+        for (DependencyType dependencyType : DependencyType.values()) 
         {
-            addDependencies(className, allClasses);
-        }
-        
-        final StringBuilder dependencySection = new StringBuilder();
-        
-        for (String className : allClasses) 
-        {
-            final Node node = 
createNode(componentClassResolver.getLogicalName(className), className);
-            dotFile.append(getNodeDefinition(node));
-            for (String dependency : node.dependencies)
+
+            for (String className : classNames)
+            {
+                addDependencies(className, allClasses, dependencyType);
+            }
+            
+            final StringBuilder dependencySection = new StringBuilder();
+            
+            for (String className : allClasses) 
             {
-                dependencySection.append(getNodeDependencyDefinition(node, 
dependency));
+                final Node node = 
createNode(componentClassResolver.getLogicalName(className), className, 
dependencyType);
+                dotFile.append(getNodeDefinition(node, dependencyType));
+                for (String dependency : node.dependencies)
+                {
+                    dependencySection.append(getNodeDependencyDefinition(node, 
dependency));
+                }
             }
+            
+            dotFile.append("\n");
+            dotFile.append(dependencySection);
+            dotFile.append("\n");
+
         }
         
-        dotFile.append("\n");
-        dotFile.append(dependencySection);
-        dotFile.append("\n");
 
         dotFile.append("}");
         
         return dotFile.toString();
     }
     
-    private String getNodeDefinition(Node node) 
+    private String getNodeDefinition(Node node, DependencyType dependencyType) 
     {
+        // TODO: add some diferentiation between dependency types
         return String.format("\t%s [label=\"%s\", tooltip=\"%s\"];\n", 
node.id, node.label, node.className);
     }
     
@@ -116,21 +124,21 @@ public class ComponentDependencyGraphvizGeneratorImpl 
implements ComponentDepend
         return label.replace('.', '_').replace('/', '_');
     }
 
-    private void addDependencies(String className, Set<String> allClasses) 
+    private void addDependencies(String className, Set<String> allClasses, 
DependencyType type) 
     {
         if (!allClasses.contains(className))
         {
             allClasses.add(className);
-            for (String dependency : 
componentDependencyRegistry.getDependencies(className))
+            for (String dependency : 
componentDependencyRegistry.getDependencies(className, type))
             {
-                addDependencies(dependency, allClasses);
+                addDependencies(dependency, allClasses, type);
             }
         }
     }
 
-    private Node createNode(String logicalName, String className) 
+    private Node createNode(String logicalName, String className, 
DependencyType type) 
     {
-        return new Node(logicalName, className, 
componentDependencyRegistry.getDependencies(className));
+        return new Node(logicalName, className, 
componentDependencyRegistry.getDependencies(className, type));
     }
 
     private static final class Node {
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 5eebb690e..1613095c2 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
@@ -34,6 +34,29 @@ import org.apache.tapestry5.plastic.PlasticField;
  */
 public interface ComponentDependencyRegistry {
 
+    /**
+     * Enum class defining the types of dependency components, pages and 
mixins can
+     * have among them.
+     */
+    public static enum DependencyType
+    {
+        
+        /**
+         * Simple usage of components and mixins in components and pages
+         */
+        USAGE,
+        
+        /**
+         * Superclass/subclass dependency.
+         */
+        SUPERCLASS,
+        
+        /**
+         * Dependency by usage of the {@linkplain InjectPage} annotation.
+         */
+        INJECT_PAGE;
+    }
+
     /**
      * Name of the file where the dependency information is stored between 
webapp runs.
      */
@@ -76,16 +99,11 @@ public interface ComponentDependencyRegistry {
     Set<String> getDependents(String className);
     
     /**
-     * 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.
+     * Returns the fully qualified names of the direct dependencies of a given 
component
+     * and a given dependency type.
+     * @see DependencyType
      */
-    Set<String> getPageDependencies(String className);
+    Set<String> getDependencies(String className, DependencyType type);
     
     /**
      * 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 e86c701ec..92a41e34b 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
@@ -1,4 +1,4 @@
-// Copyright 2022 The Apache Software Foundation
+// Copyright 2022, 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.
@@ -33,7 +33,6 @@ 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;
@@ -53,7 +52,6 @@ import 
org.apache.tapestry5.internal.structure.ComponentPageElement;
 import org.apache.tapestry5.ioc.Orderable;
 import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.model.EmbeddedComponentModel;
@@ -77,18 +75,14 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
     private static final String META_ATTRIBUTE_SEPARATOR = ",";
     
     // Key is a component, values are the components that depend on it.
-    final private Map<String, Set<String>> map;
-    
-    // Dependencies that are only for invalidation (i.e. from one component to 
-    // a page injected through @InjectPage
-    final private Set<InvalidationOnlyDependency> invalidationOnlyDependencies;
+    final private Map<String, Set<Dependency>> map;
     
     // Cache to check which classes were already processed or not.
     final private Set<String> alreadyProcessed;
     
     final private File storedDependencies;
     
-    final private static ThreadLocal<Boolean> INVALIDATIONS_ENABLED = 
ThreadLocal.withInitial(() -> Boolean.TRUE);
+    final private static ThreadLocal<Integer> INVALIDATIONS_DISABLED = 
ThreadLocal.withInitial(() -> 0);
     
     final private PlasticManager plasticManager;
     
@@ -113,7 +107,6 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
         this.pageClassloaderContextManager = pageClassloaderContextManager;
         map = new HashMap<>();
         alreadyProcessed = new HashSet<>();
-        invalidationOnlyDependencies = new 
HashSet<InvalidationOnlyDependency>();
         this.plasticManager = plasticManager;
         this.resolver = componentClassResolver;
         this.templateParser = templateParser;
@@ -141,14 +134,16 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                             .collect(Collectors.toSet());
                     for (String dependency : dependencies) 
                     {
-                        add(className, dependency);
+                        
+                        // TODO: fix storing and reading dependency file
+//                        add(className, dependency);
                         alreadyProcessed.add(dependency);
                     }
                     alreadyProcessed.add(className);
                 }
             } catch (IOException e) 
             {
-                throw new TapestryException("Exception trying to read " + 
ComponentDependencyRegistry.FILENAME, e);
+                throw new TapestryException("Exception trying to read " + 
FILENAME, e);
             }
         }
         
@@ -183,16 +178,15 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
             if (field.isAnnotationPresent(InjectComponent.class))
             {
                 final Class<?> dependency = field.getType();
-                add(component, dependency);
+                add(component, dependency, DependencyType.USAGE);
                 processClass.accept(dependency);
             }
             
             // Page injection annotation
-            if (field.isAnnotationPresent(InjectComponent.class))
+            if (field.isAnnotationPresent(InjectPage.class))
             {
                 final Class<?> dependency = field.getType();
-                invalidationOnlyDependencies.add(
-                        new InvalidationOnlyDependency(className, 
dependency.getName()));
+                add(component, dependency, DependencyType.INJECT_PAGE);
             }
             
             // @Component
@@ -210,7 +204,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
         if (isTransformed(superclass))
         {
             processClass.accept(superclass);
-            add(component, superclass);
+            add(component, superclass, DependencyType.SUPERCLASS);
         }
         
         alreadyProcessed.add(className);
@@ -258,13 +252,13 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                     if (logicalName != null)
                     {
                         dependency = 
resolver.resolveComponentTypeToClassName(logicalName);
-                        add(className, dependency);
+                        add(className, dependency, DependencyType.USAGE);
                         processClassName.accept(dependency);
                     }
                     for (String mixin : 
TapestryInternalUtils.splitAtCommas(componentToken.getMixins()))
                     {
                         dependency = 
resolver.resolveMixinTypeToClassName(mixin);
-                        add(className, dependency);
+                        add(className, dependency, DependencyType.USAGE);
                         processClassName.accept(dependency);
                     }
                 }
@@ -305,7 +299,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
             {
                 dependency = 
resolver.resolveComponentTypeToClassName(typeFromAnnotation);
             }
-            add(field.getDeclaringClass().getName(), dependency);
+            add(field.getDeclaringClass().getName(), dependency, 
DependencyType.USAGE);
             processClassName.accept(dependency);
         }
     }
@@ -319,7 +313,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                     getFieldTypeClassName(field) : 
                     resolver.resolveMixinTypeToClassName(mixinType);
             
-            add(getDeclaringClassName(field), mixinClassName);
+            add(getDeclaringClassName(field), mixinClassName, 
DependencyType.USAGE);
             processClassName.accept(mixinClassName);
         }
     }
@@ -343,7 +337,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
             {
                 for (Class dependency : mixinClasses.value()) 
                 {
-                    add(field.getDeclaringClass(), dependency);
+                    add(field.getDeclaringClass(), dependency, 
DependencyType.USAGE);
                     processClass.accept(dependency);
                 }
             }
@@ -356,7 +350,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                     // Logic adapted from MixinsWorker
                     Orderable<String> typeAndOrder = 
TapestryInternalUtils.mixinTypeAndOrder(mixin);
                     final String dependency = 
resolver.resolveMixinTypeToClassName(typeAndOrder.getTarget());
-                    add(getDeclaringClassName(field), dependency);
+                    add(getDeclaringClassName(field), dependency, 
DependencyType.USAGE);
                     processClassName.accept(dependency);
                 }
             }
@@ -379,7 +373,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                 for (String id : componentPageElement.getEmbeddedElementIds()) 
                 {
                     final ComponentPageElement child = 
componentPageElement.getEmbeddedElement(id);
-                    add(componentPageElement, child);
+                    add(componentPageElement, child, DependencyType.USAGE);
                     register(child);
                 }
                 
@@ -388,7 +382,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                 final ComponentModel componentModel = 
componentResources.getComponentModel();
                 for (String mixinClassName : 
componentModel.getMixinClassNames()) 
                 {
-                    add(componentClassName, mixinClassName);
+                    add(componentClassName, mixinClassName, 
DependencyType.USAGE);
                 }
                 
                 // Mixins applied to embedded component instances
@@ -401,7 +395,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                     final List<String> mixinClassNames = embeddedComponentModel
                             .getMixinClassNames();
                     for (String mixinClassName : mixinClassNames) {
-                        add(componentClassName, mixinClassName);
+                        add(componentClassName, mixinClassName, 
DependencyType.USAGE);
                     }
                 }
                 
@@ -410,7 +404,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                 Class<?> parent = component.getClass().getSuperclass();
                 if (parent != null && !Object.class.equals(parent))
                 {
-                    add(componentClassName, parent.getName());
+                    add(componentClassName, parent.getName(), 
DependencyType.SUPERCLASS);
                 }
                 
                 // Dependencies from injecting annotations: 
@@ -420,7 +414,8 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                 {
                     for (String dependency : 
metaDependencies.split(META_ATTRIBUTE_SEPARATOR)) 
                     {
-                        add(componentClassName, dependency);
+                        add(componentClassName, dependency, 
+                                isPage(dependency) ? 
DependencyType.INJECT_PAGE : DependencyType.USAGE);
                     }
                 }
                 
@@ -468,24 +463,19 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
         {
             alreadyProcessed.remove(className);
             map.remove(className);
-            final Collection<Set<String>> allDependentSets = map.values();
-            for (Set<String> dependents : allDependentSets) 
+            final Collection<Set<Dependency>> allDependentSets = map.values();
+            for (Set<Dependency> dependents : allDependentSets) 
             {
                 if (dependents != null) 
                 {
-                    dependents.remove(className);
-                }
-            }
-        }
-        synchronized (invalidationOnlyDependencies) 
-        {
-            final Iterator<InvalidationOnlyDependency> iterator = 
invalidationOnlyDependencies.iterator();
-            while (iterator.hasNext())
-            {
-                InvalidationOnlyDependency dependency = iterator.next();
-                if (dependency.className.equals(className) || 
dependency.dependency.equals(className))
-                {
-                    iterator.remove();
+                    final Iterator<Dependency> iterator = 
dependents.iterator();
+                    while (iterator.hasNext())
+                    {
+                        if (className.equals(iterator.next().className))
+                        {
+                            iterator.remove();
+                        }
+                    }
                 }
             }
         }
@@ -506,44 +496,49 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
     @Override
     public Set<String> getDependents(String className) 
     {
-        final Set<String> dependents = map.get(className);
-        return dependents != null ? dependents : Collections.emptySet();
+        final Set<Dependency> dependents = map.get(className);
+        return dependents != null 
+                ? dependents.stream().map(d -> 
d.className).collect(Collectors.toSet()) 
+                : Collections.emptySet();
     }
     
-    private Set<String> getDependencies(String className, Predicate<String> 
filter) 
+    @Override
+    public Set<String> getDependencies(String className, DependencyType type) 
     {
         Set<String> dependencies = Collections.emptySet();
         if (alreadyProcessed.contains(className))
         {
             dependencies = map.entrySet().stream()
-                .filter(e -> e.getValue().contains(className))
+                .filter(e -> contains(e.getValue(), className, type))
                 .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) 
+
+    private boolean contains(Set<Dependency> dependencies, String className, 
DependencyType type) 
     {
-        return getDependencies(className, this::isPage);
+        boolean contains = false;
+        for (Dependency dependency : dependencies) 
+        {
+            if (dependency.type.equals(type) && 
dependency.className.equals(className))
+            {
+                contains = true;
+                break;
+            }
+        }
+        return contains;
     }
 
-    private void add(ComponentPageElement component, ComponentPageElement 
dependency) 
+    private void add(ComponentPageElement component, ComponentPageElement 
dependency, DependencyType type) 
     {
-        add(getClassName(component), getClassName(dependency));
+        add(getClassName(component), getClassName(dependency), type);
     }
     
     // Just for unit tests
-    void add(String component, String dependency, boolean 
markAsAlreadyProcessed)
+    void add(String component, String dependency, DependencyType type, boolean 
markAsAlreadyProcessed)
     {
         if (markAsAlreadyProcessed)
         {
@@ -551,31 +546,32 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
         }
         if (dependency != null)
         {
-            add(component, dependency);
+            add(component, dependency, type);
         }
     }
     
-    private void add(Class<?> component, Class<?> dependency) 
+    private void add(Class<?> component, Class<?> dependency, DependencyType 
type) 
     {
         if (plasticManager.shouldInterceptClassLoading(dependency.getName()))
         {
-            add(component.getName(), dependency.getName());
+            add(component.getName(), dependency.getName(), type);
         }
     }
     
-    private void add(String component, String dependency) 
+    private void add(String component, String dependency, DependencyType type) 
     {
         Objects.requireNonNull(component, "Parameter component cannot be 
null");
         Objects.requireNonNull(dependency, "Parameter dependency cannot be 
null");
+        Objects.requireNonNull(dependency, "Parameter type cannot be null");
         synchronized (map) 
         {
-            Set<String> dependents = map.get(dependency);
+            Set<Dependency> dependents = map.get(dependency);
             if (dependents == null) 
             {
                 dependents = new HashSet<>();
                 map.put(dependency, dependents);
             }
-            dependents.add(component);
+            dependents.add(new Dependency(component, type));
         }
     }
     
@@ -589,7 +585,7 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
     List<String> listen(List<String> resources)
     {
         List<String> furtherDependents;
-        if (!INVALIDATIONS_ENABLED.get())
+        if (INVALIDATIONS_DISABLED.get() > 0)
         {
             furtherDependents = Collections.emptyList();
         }
@@ -616,14 +612,6 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                     }
                 }
                 
-                for (InvalidationOnlyDependency invalidationOnlyDependency : 
invalidationOnlyDependencies) 
-                {
-                    if (invalidationOnlyDependency.dependency.equals(resource))
-                    {
-                        
furtherDependents.add(invalidationOnlyDependency.dependency);
-                    }
-                }
-                
                 clear(resource);
             }
         }
@@ -645,14 +633,15 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
                 JSONObject jsonObject = new JSONObject();
                 for (String className : map.keySet())
                 {
-                    final Set<String> dependencies = 
getDependencies(className);
-                    jsonObject.put(className, JSONArray.from(dependencies));
+                    // TODO: rewrite this
+//                    final Set<String> dependencies = 
getDependencies(className);
+//                    jsonObject.put(className, JSONArray.from(dependencies));
                 }
                 bufferedWriter.write(jsonObject.toString());
             }
             catch (IOException e) 
             {
-                throw new TapestryException("Exception trying to read " + 
ComponentDependencyRegistry.FILENAME, e);
+                throw new TapestryException("Exception trying to read " + 
FILENAME, e);
             }
         } 
     }
@@ -672,7 +661,9 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
     @Override
     public Set<String> getRootClasses() {
         return alreadyProcessed.stream()
-                .filter(c -> getDependencies(c).isEmpty())
+                .filter(c -> getDependencies(c, 
DependencyType.USAGE).isEmpty() &&
+                        getDependencies(c, 
DependencyType.INJECT_PAGE).isEmpty() &&
+                        getDependencies(c, 
DependencyType.SUPERCLASS).isEmpty())
                 .collect(Collectors.toSet());
     }
     
@@ -690,13 +681,13 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
     @Override
     public void disableInvalidations() 
     {
-        INVALIDATIONS_ENABLED.set(false);
+        INVALIDATIONS_DISABLED.set(INVALIDATIONS_DISABLED.get() + 1);
     }
 
     @Override
     public void enableInvalidations() 
     {
-        INVALIDATIONS_ENABLED.set(true);
+        INVALIDATIONS_DISABLED.set(INVALIDATIONS_DISABLED.get() - 1);
     }
 
     /**
@@ -896,4 +887,44 @@ public class ComponentDependencyRegistryImpl implements 
ComponentDependencyRegis
         
     }
     
+    private static final class Dependency
+    {
+        private final String className;
+        private final DependencyType type;
+        
+        public Dependency(String className, DependencyType dependencyType) 
+        {
+            super();
+            this.className = className;
+            this.type = dependencyType;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(className, type);
+        }
+
+        @Override
+        public boolean equals(Object obj) 
+        {
+            if (this == obj) 
+            {
+                return true;
+            }
+            if (!(obj instanceof Dependency)) 
+            {
+                return false;
+            }
+            Dependency other = (Dependency) obj;
+            return Objects.equals(className, other.className) && type == 
other.type;
+        }
+
+        @Override
+        public String toString() 
+        {
+            return "Dependency [className=" + className + ", dependencyType=" 
+ type + "]";
+        }
+        
+    }
+    
 }
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
index 351b60200..bfafdeeb1 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
@@ -37,6 +37,7 @@ import 
org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.model.MutableComponentModelImpl;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import org.apache.tapestry5.ioc.Invokable;
 import org.apache.tapestry5.ioc.LoggerSource;
 import org.apache.tapestry5.ioc.OperationTracker;
@@ -345,8 +346,9 @@ public final class ComponentInstantiatorSourceImpl 
implements ComponentInstantia
                         
                         // Make sure the dependencies have been processed in 
case
                         // there was some invalidation going on and they're 
not there.
-                        
-                        final Set<String> dependencies = 
componentDependencyRegistry.getDependencies(className);
+
+                        // TODO: maybe we need superclasses here too?
+                        final Set<String> dependencies = 
componentDependencyRegistry.getDependencies(className, DependencyType.USAGE);
                         for (String dependency : dependencies)
                         {
                             if (!OPEN_INSTANTIATORS.get().contains(dependency))
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 e95056278..5d9dd16e5 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
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.internal.services;
 
 import java.lang.ref.SoftReference;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -27,6 +28,7 @@ import 
org.apache.tapestry5.commons.services.InvalidationEventHub;
 import org.apache.tapestry5.commons.util.CollectionFactory;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
 import org.apache.tapestry5.internal.structure.ComponentPageElement;
 import org.apache.tapestry5.internal.structure.Page;
@@ -128,6 +130,11 @@ public class PageSourceImpl implements PageSource
         // 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).
+        
+        if (!productionMode && invalidateUnknownContext)
+        {
+            componentDependencyRegistry.disableInvalidations();
+        }
 
         while (true)
         {
@@ -137,6 +144,10 @@ public class PageSourceImpl implements PageSource
 
             if (page != null)
             {
+                if (invalidateUnknownContext && !productionMode)
+                {
+                    componentDependencyRegistry.enableInvalidations();
+                }
                 return page;
             }
             
@@ -150,9 +161,7 @@ public class PageSourceImpl implements PageSource
 //            {
 //                
getPage(componentClassResolver.resolvePageClassNameToPageName(superclassName), 
false);
 //            }
-            final Set<String> pageDependencies = 
componentDependencyRegistry.getPageDependencies(className);
-            
-            preprocessPageClassLoaderContexts(className, pageDependencies);
+            final List<String> pageDependencies = 
preprocessPageDependencies(className);
             
             for (String pageClassName : pageDependencies)
             {
@@ -169,7 +178,6 @@ public class PageSourceImpl implements PageSource
 
             pageCache.put(key, ref);
             
-            // TODO: remove this?
             if (!productionMode)
             {
                 final ComponentPageElement rootElement = page.getRootElement();
@@ -178,18 +186,39 @@ public class PageSourceImpl implements PageSource
                 PageClassloaderContext context = 
pageClassloaderContextManager.get(className);
                 if (invalidateUnknownContext && context.isUnknown())
                 {
-                    componentDependencyRegistry.disableInvalidations();
                     
pageClassloaderContextManager.invalidateAndFireInvalidationEvents(context);
-                    componentDependencyRegistry.enableInvalidations();
                     pageClassloaderContextManager.get(className);
+                    preprocessPageDependencies(className);
                     return getPage(canonicalPageName, false);
                 }
             }
             
         }
+        
+        
+    }
+
+    private List<String> preprocessPageDependencies(final String className) {
+        final List<String> pageDependencies = new ArrayList<>();
+        pageDependencies.addAll(
+                new 
ArrayList<String>(componentDependencyRegistry.getDependencies(className, 
DependencyType.INJECT_PAGE)));
+        pageDependencies.addAll(
+                new 
ArrayList<String>(componentDependencyRegistry.getDependencies(className, 
DependencyType.SUPERCLASS)));
+        
+        final Iterator<String> iterator = pageDependencies.iterator();
+        while (iterator.hasNext())
+        {
+            if (!iterator.next().contains(".pages."))
+            {
+                iterator.remove();
+            }
+        }
+        
+        preprocessPageClassLoaderContexts(className, pageDependencies);
+        return pageDependencies;
     }
 
-    private void preprocessPageClassLoaderContexts(String className, final 
Set<String> pageDependencies) {
+    private void preprocessPageClassLoaderContexts(String className, final 
List<String> pageDependencies) {
         for (int i = 0; i < 2; i++)
         {
             pageClassloaderContextManager.get(className);
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassloaderContextManagerImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassloaderContextManagerImpl.java
index ba8c3e9f6..553e668de 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassloaderContextManagerImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassloaderContextManagerImpl.java
@@ -28,6 +28,7 @@ import 
org.apache.tapestry5.commons.internal.util.TapestryException;
 import org.apache.tapestry5.commons.services.InvalidationEventHub;
 import org.apache.tapestry5.commons.services.PlasticProxyFactory;
 import org.apache.tapestry5.internal.services.ComponentDependencyRegistry;
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import 
org.apache.tapestry5.internal.services.InternalComponentInvalidationEventHub;
 import org.apache.tapestry5.ioc.annotations.ComponentClasses;
 import org.apache.tapestry5.plastic.PlasticUtils;
@@ -238,7 +239,7 @@ public class PageClassloaderContextManagerImpl implements 
PageClassloaderContext
                 {
 
                     alreadyProcessed.add(className);
-
+                    
                     // Sorting dependencies alphabetically so we have 
consistent results.
                     List<String> dependencies = new 
ArrayList<>(getDependenciesWithoutPages(className));
                     Collections.sort(dependencies);
@@ -354,11 +355,9 @@ public class PageClassloaderContextManagerImpl implements 
PageClassloaderContext
         return context;
     }
 
-    private Set<String> getDependenciesWithoutPages(String className) {
-        final Set<String> dependencies = 
componentDependencyRegistry.getDependencies(className);
-        return dependencies.stream()
-                .filter(c -> !componentClassResolver.isPage(c))
-                .collect(Collectors.toSet());
+    private Set<String> getDependenciesWithoutPages(String className) 
+    {
+        return componentDependencyRegistry.getDependencies(className, 
DependencyType.USAGE);
     }
 
     private Class<?> loadClass(String className, PageClassloaderContext 
context) 
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
index c3dd3ff7a..aea62e595 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
@@ -75,6 +75,7 @@ import 
org.apache.tapestry5.integration.app1.pages.BlockHolder;
 import 
org.apache.tapestry5.integration.app1.pages.EmbeddedComponentTypeConflict;
 import org.apache.tapestry5.integration.app1.pages.InstanceMixinDependencies;
 import org.apache.tapestry5.integration.app1.pages.MixinParameterDefault;
+import 
org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType;
 import org.apache.tapestry5.internal.services.templates.DefaultTemplateLocator;
 import org.apache.tapestry5.ioc.internal.QuietOperationTracker;
 import org.apache.tapestry5.modules.TapestryModule;
@@ -214,38 +215,47 @@ public class ComponentDependencyRegistryImplTest
         result = componentDependencyRegistry.listen(resources);
         Collections.sort(result);
         assertEquals(result, Arrays.asList("d", "dd"));
-        assertEquals("bar", 
componentDependencyRegistry.getDependencies("foo").iterator().next());
+        assertEquals("bar", getDependencies("foo").iterator().next());
         assertEquals("foo", 
componentDependencyRegistry.getDependents("bar").iterator().next());        
         
         configurePCCM(false);
         result = componentDependencyRegistry.listen(Collections.emptyList());
         assertEquals(result, Collections.emptyList());
         assertEquals(componentDependencyRegistry.getDependents("bar").size(), 
0);
-        
assertEquals(componentDependencyRegistry.getDependencies("foo").size(), 0);
+        assertEquals(getDependencies("foo").size(), 0);
         
     }
     
+    private Set<String> getDependencies(String className)
+    {
+        return componentDependencyRegistry.getDependencies(className, 
DependencyType.USAGE);
+    }
+    
     @Test
     public void dependency_methods()
     {
         
         final String foo = "foo";
         final String bar = "bar";
-        final String something = "d";
-        final String other = "dd";
-        final String fulano = "a";
-        final String beltrano = "aa";
+        final String something = "something";
+        final String other = "other";
+        final String fulano = "fulano";
+        final String beltrano = "beltrano";
+        final String sicrano = "sicrano";
         
         assertEquals(
                 "getDependents() should never return null", 
                 Collections.emptySet(),
-                componentDependencyRegistry.getDependencies(foo));
+                getDependencies(foo));
 
         assertEquals(
                 "getDependents() should never return null", 
                 Collections.emptySet(),
                 componentDependencyRegistry.getDependents(foo));
 
+        // In Brazil, Fulano, Beltrano and Sicrano are the most used people
+        // placeholder names, in that order.
+        
         add(foo, bar);
         add(something, fulano);
         add(other, beltrano);
@@ -254,18 +264,24 @@ public class ComponentDependencyRegistryImplTest
         add(bar, null);
         add(fulano, null);
         add(beltrano, null);
+        add(beltrano, sicrano);
+        add(sicrano, null);
         
-        assertEquals(new HashSet<>(Arrays.asList(fulano, beltrano)), 
componentDependencyRegistry.getDependencies(other));
-        assertEquals(new HashSet<>(Arrays.asList(fulano)), 
componentDependencyRegistry.getDependencies(something));
-        assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependencies(fulano));
-        assertEquals(new HashSet<>(Arrays.asList(bar)), 
componentDependencyRegistry.getDependencies(foo));
-        assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependencies(bar));
+        assertEquals(new HashSet<>(Arrays.asList(fulano, beltrano)), 
getDependencies(other));
+        assertEquals(new HashSet<>(Arrays.asList(fulano)), 
getDependencies(something));
+        assertEquals(new HashSet<>(Arrays.asList()), getDependencies(fulano));
+        assertEquals(new HashSet<>(Arrays.asList(bar)), getDependencies(foo));
+        assertEquals(new HashSet<>(Arrays.asList()), getDependencies(bar));
+        assertEquals(new HashSet<>(Arrays.asList(sicrano)), 
getDependencies(beltrano));
 
         assertEquals(new HashSet<>(Arrays.asList(foo)), 
componentDependencyRegistry.getDependents(bar));
         assertEquals(new HashSet<>(Arrays.asList(other, something)), 
componentDependencyRegistry.getDependents(fulano));
         assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependents(foo));
+        assertEquals(new HashSet<>(Arrays.asList(other)), 
componentDependencyRegistry.getDependents(beltrano));
+        assertEquals(new HashSet<>(Arrays.asList(beltrano)), 
componentDependencyRegistry.getDependents(sicrano));
         
-        assertEquals(new HashSet<>(Arrays.asList(bar, fulano, beltrano)), 
componentDependencyRegistry.getRootClasses());
+        assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)), 
+                componentDependencyRegistry.getRootClasses());
         
         assertTrue(componentDependencyRegistry.contains(foo));
         assertTrue(componentDependencyRegistry.contains(bar));
@@ -273,6 +289,7 @@ public class ComponentDependencyRegistryImplTest
         assertTrue(componentDependencyRegistry.contains(something));
         assertTrue(componentDependencyRegistry.contains(fulano));
         assertTrue(componentDependencyRegistry.contains(beltrano));
+        assertTrue(componentDependencyRegistry.contains(sicrano));
         assertFalse(componentDependencyRegistry.contains("blah"));
 
         assertTrue(componentDependencyRegistry.getClassNames().contains(foo));
@@ -281,11 +298,49 @@ public class ComponentDependencyRegistryImplTest
         
assertTrue(componentDependencyRegistry.getClassNames().contains(something));
         
assertTrue(componentDependencyRegistry.getClassNames().contains(fulano));
         
assertTrue(componentDependencyRegistry.getClassNames().contains(beltrano));
+        
assertTrue(componentDependencyRegistry.getClassNames().contains(sicrano));
+        
assertFalse(componentDependencyRegistry.getClassNames().contains("blah"));
+        
+        // Testing the clear method
+        componentDependencyRegistry.clear(beltrano);
+        
+        assertEquals(new HashSet<>(Arrays.asList(fulano)), 
getDependencies(other));
+        assertEquals(new HashSet<>(Arrays.asList(fulano)), 
getDependencies(something));
+        assertEquals(new HashSet<>(Arrays.asList()), getDependencies(fulano));
+        assertEquals(new HashSet<>(Arrays.asList(bar)), getDependencies(foo));
+        assertEquals(new HashSet<>(Arrays.asList()), getDependencies(bar));
+        assertEquals(new HashSet<>(Arrays.asList()), getDependencies(sicrano));
+
+        assertEquals(new HashSet<>(Arrays.asList(foo)), 
componentDependencyRegistry.getDependents(bar));
+        assertEquals(new HashSet<>(Arrays.asList(other, something)), 
componentDependencyRegistry.getDependents(fulano));
+        assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependents(foo));
+        assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependents(beltrano));
+        assertEquals(new HashSet<>(Arrays.asList()), 
componentDependencyRegistry.getDependents(sicrano));
+        
+        assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)), 
componentDependencyRegistry.getRootClasses());
+        
+        assertTrue(componentDependencyRegistry.contains(foo));
+        assertTrue(componentDependencyRegistry.contains(bar));
+        assertTrue(componentDependencyRegistry.contains(other));
+        assertTrue(componentDependencyRegistry.contains(something));
+        assertTrue(componentDependencyRegistry.contains(fulano));
+        assertTrue(componentDependencyRegistry.contains(sicrano));
+        assertFalse(componentDependencyRegistry.contains(beltrano));
+        assertFalse(componentDependencyRegistry.contains("blah"));
+
+        assertTrue(componentDependencyRegistry.getClassNames().contains(foo));
+        assertTrue(componentDependencyRegistry.getClassNames().contains(bar));
+        
assertTrue(componentDependencyRegistry.getClassNames().contains(other));
+        
assertTrue(componentDependencyRegistry.getClassNames().contains(something));
+        
assertTrue(componentDependencyRegistry.getClassNames().contains(fulano));
+        
assertTrue(componentDependencyRegistry.getClassNames().contains(sicrano));
+        
assertFalse(componentDependencyRegistry.getClassNames().contains(beltrano));
         
assertFalse(componentDependencyRegistry.getClassNames().contains("blah"));
         
     }
     
-    @Test
+    // Tested code isn't being used at the moment
+    @Test(enabled = false)
     public void register()
     {
         
@@ -347,7 +402,7 @@ public class ComponentDependencyRegistryImplTest
     private void assertDependencies(Class clasz, Class... dependencies) {
         assertEquals(
                 setOf(dependencies),
-                componentDependencyRegistry.getDependencies(clasz.getName()));
+                getDependencies(clasz.getName()));
     }
 
     private static Set<String> setOf(Class ... classes)
@@ -364,7 +419,7 @@ public class ComponentDependencyRegistryImplTest
     
     private void add(String component, String dependency)
     {
-        componentDependencyRegistry.add(component, dependency, true);
+        componentDependencyRegistry.add(component, dependency, 
DependencyType.USAGE, true);
     }
 
     private static final class MockMappedConfiguration<String, URL> implements 
MappedConfiguration<String, URL>


Reply via email to