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 <[email protected]>
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 + "]";
}
}