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 298a4709e TAP5-2742: refactoring URLChangeTracker to make it 
parameterized
298a4709e is described below

commit 298a4709e485660dbadcaec1841a4a19788e2801
Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br>
AuthorDate: Sun Nov 27 12:59:28 2022 -0300

    TAP5-2742: refactoring URLChangeTracker to make it parameterized
---
 .../internal/services/ClassNameHolder.java         | 30 ++++++++++
 .../services/ComponentInstantiatorSourceImpl.java  | 57 +++++++++++++++++--
 .../services/ComponentTemplateSourceImpl.java      | 25 +++++----
 .../internal/services/MessagesSourceImpl.java      |  2 +-
 .../internal/services/TemplateTrackingInfo.java    | 65 ++++++++++++++++++++++
 .../services/ComponentTemplateSourceImplTest.java  | 12 +++-
 .../ioc/internal/util/URLChangeTracker.java        | 44 ++++++++-------
 7 files changed, 195 insertions(+), 40 deletions(-)

diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClassNameHolder.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClassNameHolder.java
new file mode 100644
index 000000000..832e50aaf
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClassNameHolder.java
@@ -0,0 +1,30 @@
+// Copyright 2022 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.internal.services;
+
+import org.apache.tapestry5.ioc.internal.util.URLChangeTracker;
+
+/**
+ * Interface that defines types who provide a class name for {@linkplain 
URLChangeTracker} purposes.
+ *
+ * @since 5.8.3
+ */
+public interface ClassNameHolder
+{
+    /**
+     * Returns the class name associated with a given resource tracked by 
{@link URLChangeTracker}.
+     */
+    String getClassName();
+}
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 c3e91f270..a64798b7b 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
@@ -12,10 +12,11 @@
 
 package org.apache.tapestry5.internal.services;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.beanmodel.services.PlasticProxyFactoryImpl;
@@ -81,7 +82,7 @@ public final class ComponentInstantiatorSourceImpl implements 
ComponentInstantia
 {
     private final Set<String> controlledPackageNames = 
CollectionFactory.newSet();
 
-    private final URLChangeTracker changeTracker;
+    private final URLChangeTracker<ClassName> changeTracker;
 
     private final ClassLoader parent;
 
@@ -150,7 +151,7 @@ public final class ComponentInstantiatorSourceImpl 
implements ComponentInstantia
         this.transformerChain = transformerChain;
         this.logger = logger;
         this.loggerSource = loggerSource;
-        this.changeTracker = new URLChangeTracker(classpathURLConverter);
+        this.changeTracker = new 
URLChangeTracker<ClassName>(classpathURLConverter);
         this.tracker = tracker;
         this.invalidationHub = invalidationHub;
         this.productionMode = productionMode;
@@ -173,10 +174,12 @@ public final class ComponentInstantiatorSourceImpl 
implements ComponentInstantia
 
     public synchronized void checkForUpdates()
     {
-        final Set<String> changedResources = 
changeTracker.getChangedResourcesMemos();
+        final Set<ClassName> changedResources = 
changeTracker.getChangedResourcesInfo();
         if (!changedResources.isEmpty())
         {
-            invalidationHub.fireInvalidationEvent(new 
ArrayList<>(changedResources));
+            invalidationHub.fireInvalidationEvent(changedResources.stream()
+                    .map(ClassNameHolder::getClassName)
+                    .collect(Collectors.toList()));
         }
     }
 
@@ -308,7 +311,7 @@ public final class ComponentInstantiatorSourceImpl 
implements ComponentInstantia
                         Resource baseResource = new ClasspathResource(parent, 
PlasticInternalUtils
                                 .toClassPath(className));
 
-                        changeTracker.add(baseResource.toURL(), className);
+                        changeTracker.add(baseResource.toURL(), new 
ClassName(className));
 
                         if (isRoot)
                         {
@@ -502,4 +505,46 @@ public final class ComponentInstantiatorSourceImpl 
implements ComponentInstantia
             }
         }
     }
+    private static class ClassName implements ClassNameHolder
+    {
+        private String className;
+
+        public ClassName(String className) 
+        {
+            super();
+            this.className = className;
+        }
+
+        @Override
+        public String getClassName() 
+        {
+            return className;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(className);
+        }
+
+        @Override
+        public boolean equals(Object obj) 
+        {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof ClassName)) {
+                return false;
+            }
+            ClassName other = (ClassName) obj;
+            return Objects.equals(className, other.className);
+        }
+
+        @Override
+        public String toString() 
+        {
+            return className;
+        }
+        
+    }
+    
 }
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
index f8e2b83ae..4cfaa9dd2 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
@@ -20,6 +20,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.tapestry5.TapestryConstants;
 import org.apache.tapestry5.commons.Location;
@@ -53,7 +54,7 @@ public final class ComponentTemplateSourceImpl extends 
InvalidationEventHubImpl
 {
     private final TemplateParser parser;
 
-    private final URLChangeTracker tracker;
+    private final URLChangeTracker<TemplateTrackingInfo> tracker;
 
     private final ComponentResourceLocator locator;
     
@@ -120,11 +121,11 @@ public final class ComponentTemplateSourceImpl extends 
InvalidationEventHubImpl
                                        ComponentRequestSelectorAnalyzer 
componentRequestSelectorAnalyzer,
                                        ThreadLocale threadLocale, Logger 
logger)
     {
-        this(productionMode, parser, locator, new 
URLChangeTracker(classpathURLConverter), componentRequestSelectorAnalyzer, 
threadLocale, logger);
+        this(productionMode, parser, locator, new 
URLChangeTracker<TemplateTrackingInfo>(classpathURLConverter), 
componentRequestSelectorAnalyzer, threadLocale, logger);
     }
 
     ComponentTemplateSourceImpl(boolean productionMode, TemplateParser parser, 
ComponentResourceLocator locator,
-                                URLChangeTracker tracker, 
ComponentRequestSelectorAnalyzer componentRequestSelectorAnalyzer,
+                                URLChangeTracker<TemplateTrackingInfo> 
tracker, ComponentRequestSelectorAnalyzer componentRequestSelectorAnalyzer,
                                 ThreadLocale threadLocale, Logger logger)
     {
         super(productionMode, logger);
@@ -211,7 +212,7 @@ public final class ComponentTemplateSourceImpl extends 
InvalidationEventHubImpl
         if (!r.exists())
             return missingTemplate;
 
-        tracker.add(r.toURL(), className);
+        tracker.add(r.toURL(), new TemplateTrackingInfo(r.getPath(), 
className));
 
         return parser.parseTemplate(r);
     }
@@ -246,18 +247,22 @@ public final class ComponentTemplateSourceImpl extends 
InvalidationEventHubImpl
      */
     public void checkForUpdates()
     {
-        final Set<String> changedResourcesMemos = 
tracker.getChangedResourcesMemos();
-        if (!changedResourcesMemos.isEmpty())
+        final Set<TemplateTrackingInfo> changedResourcesInfo = 
tracker.getChangedResourcesInfo();
+        if (!changedResourcesInfo.isEmpty())
         {
-            logger.info("Changed template(s) found: {}", String.join(", ", 
changedResourcesMemos));
+            if (logger.isInfoEnabled())
+            {
+                logger.info("Changed template(s) found: {}", String.join(", ", 
+                        
changedResourcesInfo.stream().map(TemplateTrackingInfo::getTemplate).collect(Collectors.toList())));
+            }
             
             final Iterator<Entry<MultiKey, Resource>> 
templateResourcesIterator = templateResources.entrySet().iterator();
-            for (String className : changedResourcesMemos) 
+            for (TemplateTrackingInfo info : changedResourcesInfo) 
             {
                 while (templateResourcesIterator.hasNext())
                 {
                     final MultiKey key = 
templateResourcesIterator.next().getKey();
-                    if (className.equals((String) key.getValues()[0]))
+                    if (info.getClassName().equals((String) 
key.getValues()[0]))
                     {
                         templates.remove(templateResources.get(key));
                         templateResourcesIterator.remove();
@@ -265,7 +270,7 @@ public final class ComponentTemplateSourceImpl extends 
InvalidationEventHubImpl
                 }
             }
             
-            fireInvalidationEvent(new ArrayList<>(changedResourcesMemos));
+            
fireInvalidationEvent(changedResourcesInfo.stream().map(TemplateTrackingInfo::getClassName).collect(Collectors.toList()));
         }
     }
 
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
index 43b7e70d1..9acd5dfc9 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
@@ -44,7 +44,7 @@ import java.util.Map;
  */
 public class MessagesSourceImpl extends InvalidationEventHubImpl implements 
MessagesSource
 {
-    private final URLChangeTracker tracker;
+    private final URLChangeTracker<TemplateTrackingInfo> tracker;
 
     private final PropertiesFileParser propertiesFileParser;
 
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateTrackingInfo.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateTrackingInfo.java
new file mode 100644
index 000000000..0f50c3b96
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateTrackingInfo.java
@@ -0,0 +1,65 @@
+// Copyright 2022 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.internal.services;
+
+import java.util.Objects;
+
+/**
+ * Class that holds information about a template for tracking.
+ */
+final public class TemplateTrackingInfo implements ClassNameHolder
+{
+    public TemplateTrackingInfo(String template, String className) 
+    {
+        super();
+        this.template = template;
+        this.className = className;
+    }
+    private String template;
+    private String className;
+    
+    public String getTemplate() {
+        return template;
+    }
+    
+    public String getClassName() 
+    {
+        return className;
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hash(className, template);
+    }
+
+    @Override
+    public boolean equals(Object obj) 
+    {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof TemplateTrackingInfo)) {
+            return false;
+        }
+        TemplateTrackingInfo other = (TemplateTrackingInfo) obj;
+        return Objects.equals(className, other.className) && 
Objects.equals(template, other.template);
+    }
+
+    @Override
+    public String toString() 
+    {
+        return "TemplateTrackingInfo [template=" + template + ", className=" + 
className + "]";
+    }
+    
+}
\ No newline at end of file
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImplTest.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImplTest.java
index e44a4580a..31ff8feb9 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImplTest.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImplTest.java
@@ -106,9 +106,11 @@ public class ComponentTemplateSourceImplTest extends 
InternalBaseTestCase
         Resource resource = mockResource();
         ComponentResourceLocator locator = mockLocator(model, english, 
resource);
 
-        train_getComponentClassName(model, PACKAGE + ".Fred");
+        final String className = PACKAGE + ".Fred";
+        train_getComponentClassName(model, className);
 
         expect(resource.exists()).andReturn(true);
+        expect(resource.getPath()).andReturn(className.replace(".", "/") + 
".tml");
         expect(resource.toURL()).andReturn(null);
 
         train_parseTemplate(parser, resource, template);
@@ -219,11 +221,13 @@ public class ComponentTemplateSourceImplTest extends 
InternalBaseTestCase
         ComponentModel model = mockComponentModel();
         ComponentResourceLocator locator = 
newMock(ComponentResourceLocator.class);
 
-        train_getComponentClassName(model, PACKAGE + ".Fred");
+        final String className = PACKAGE + ".Fred";
+        train_getComponentClassName(model, className);
 
         expect(locator.locateTemplate(model, 
english)).andReturn(resource).once();
 
         expect(resource.exists()).andReturn(true).anyTimes();
+        expect(resource.getPath()).andReturn(className.replace(".", "/") + 
".tml").anyTimes();
         expect(resource.toURL()).andReturn(null).anyTimes();
 
         expect(locator.locateTemplate(model, 
french)).andReturn(resource).once();
@@ -289,13 +293,15 @@ public class ComponentTemplateSourceImplTest extends 
InternalBaseTestCase
         Resource resource = mockResource();
         ComponentResourceLocator locator = mockLocator(model, english, null);
 
-        train_getComponentClassName(model, "foo.Bar");
+        final String className = "foo.Bar";
+        train_getComponentClassName(model, className);
 
         train_getParentModel(model, parentModel);
 
         expect(locator.locateTemplate(parentModel, 
english)).andReturn(resource).once();
 
         expect(resource.exists()).andReturn(true);
+        expect(resource.getPath()).andReturn(className.replace(".", "/") + 
".tml");
         expect(resource.toURL()).andReturn(null);
 
         train_parseTemplate(parser, resource, template);
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/URLChangeTracker.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/URLChangeTracker.java
index 2e78e0697..151c5d7be 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/URLChangeTracker.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/URLChangeTracker.java
@@ -14,10 +14,6 @@
 
 package org.apache.tapestry5.ioc.internal.util;
 
-import org.apache.tapestry5.commons.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.services.ClasspathURLConverterImpl;
-import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
-
 import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -26,14 +22,21 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.tapestry5.commons.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.services.ClasspathURLConverterImpl;
+import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
+
 /**
  * Given a (growing) set of URLs, can periodically check to see if any of the 
underlying resources has changed. This
  * class is capable of using either millisecond-level granularity or 
second-level granularity. Millisecond-level
  * granularity is used by default. Second-level granularity is provided for 
compatibility with browsers vis-a-vis
  * resource caching -- that's how granular they get with their 
"If-Modified-Since", "Last-Modified" and "Expires"
  * headers.
+ * 
+ * @param <T> The type of the optional information about the tracked resource. 
This type should
+ * implement <code>equals()</code> and <code>hashCode().
  */
-public class URLChangeTracker
+public class URLChangeTracker<T>
 {
     private static final long FILE_DOES_NOT_EXIST_TIMESTAMP = -1L;
 
@@ -147,13 +150,14 @@ public class URLChangeTracker
      * 
      * @param url
      *            of the resource to add, or null if not known
-     * @param memo
-     *            some information about the tracked URL, most probably the 
associated class name
+     * @param resourceInfo
+     *            an optional object containing information about the tracked 
URL. It's
+     *            returned in the {@link #getChangedResourcesInfo()} method.
      * @return the current timestamp for the URL (possibly rounded off for 
granularity reasons), or 0 if the URL is
      *         null
      * @since 5.8.3
      */
-    public long add(URL url, String memo)
+    public long add(URL url, T resourceInfo)
     {
         if (url == null)
             return 0;
@@ -173,7 +177,7 @@ public class URLChangeTracker
         // A quick and imperfect fix for TAPESTRY-1918. When a file
         // is added, add the directory containing the file as well.
 
-        fileToTimestamp.put(resourceFile, new TrackingInfo(timestamp, memo));
+        fileToTimestamp.put(resourceFile, new TrackingInfo(timestamp, 
resourceInfo));
 
         if (trackFolderChanges)
         {
@@ -240,12 +244,12 @@ public class URLChangeTracker
     }
     
     /**
-     * Re-acquires the last updated timestamp for each URL and returns the 
memo value for all files with a changed timestamp.
+     * Re-acquires the last updated timestamp for each URL and returns the 
non-null resource information for all files with a changed timestamp.
      */
-    public Set<String> getChangedResourcesMemos()
+    public Set<T> getChangedResourcesInfo()
     {
         
-        Set<String> changedResourcesMemos = new HashSet<>();
+        Set<T> changedResourcesInfo = new HashSet<>();
 
         for (Map.Entry<File, TrackingInfo> entry : fileToTimestamp.entrySet())
         {
@@ -255,15 +259,15 @@ public class URLChangeTracker
 
             if (current != newTimestamp)
             {
-                if (value.memo != null)
+                if (value.resourceInfo != null)
                 {
-                    changedResourcesMemos.add(value.memo);
+                    changedResourcesInfo.add(value.resourceInfo);
                 }
                 value.timestamp = newTimestamp;
             }
         }
 
-        return changedResourcesMemos;
+        return changedResourcesInfo;
     }
 
 
@@ -310,22 +314,22 @@ public class URLChangeTracker
         return fileToTimestamp.size();
     }
     
-    private static final class TrackingInfo
+    private final class TrackingInfo
     {
         
         private long timestamp;
-        private String memo;
+        private T resourceInfo;
 
-        public TrackingInfo(long timestamp, String memo) 
+        public TrackingInfo(long timestamp, T resourceInfo) 
         {
             this.timestamp = timestamp;
-            this.memo = memo;
+            this.resourceInfo = resourceInfo;
         }
 
         @Override
         public String toString() 
         {
-            return "Info [timestamp=" + timestamp + ", memo=" + memo + "]";
+            return "Info [timestamp=" + timestamp + ", resourceInfo=" + 
resourceInfo + "]";
         }
         
     }

Reply via email to