This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push:
new f58f36a99 TAP5-2770: trying to recover when a ClassCastException
happens
f58f36a99 is described below
commit f58f36a99fb0600f91880a3e136ba4e98963da26
Author: Thiago H. de Paula Figueiredo <[email protected]>
AuthorDate: Mon Mar 11 23:50:41 2024 -0300
TAP5-2770: trying to recover when a ClassCastException happens
by clearing the generated classes caches and trying to handle the
request again
---
.../services/PropertyConduitSourceImpl.java | 2 +-
.../ComponentRequestHandlerTerminator.java | 91 ++++++++++++++++++++--
.../internal/services/RequestPageCacheImpl.java | 8 +-
3 files changed, 92 insertions(+), 9 deletions(-)
diff --git
a/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/internal/services/PropertyConduitSourceImpl.java
b/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/internal/services/PropertyConduitSourceImpl.java
index 5ac0aac72..ad26631df 100644
---
a/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/internal/services/PropertyConduitSourceImpl.java
+++
b/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/internal/services/PropertyConduitSourceImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2007-2013 The Apache Software Foundation
+// Copyright 2007-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.
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentRequestHandlerTerminator.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentRequestHandlerTerminator.java
index 0ab7b9ffd..91e276d18 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentRequestHandlerTerminator.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentRequestHandlerTerminator.java
@@ -1,4 +1,4 @@
-// Copyright 2009, 2011 Apache Software Foundation
+// Copyright 2009, 2024 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.
@@ -15,14 +15,20 @@
package org.apache.tapestry5.internal.services;
import java.io.IOException;
+import java.util.Collections;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
-import org.apache.tapestry5.beanmodel.services.*;
+import org.apache.tapestry5.commons.services.InvalidationEventHub;
+import org.apache.tapestry5.ioc.annotations.ComponentClasses;
import org.apache.tapestry5.services.ComponentEventRequestHandler;
import org.apache.tapestry5.services.ComponentEventRequestParameters;
import org.apache.tapestry5.services.ComponentRequestHandler;
import org.apache.tapestry5.services.PageRenderRequestHandler;
import org.apache.tapestry5.services.PageRenderRequestParameters;
import org.apache.tapestry5.services.Traditional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Terminator for the {@link
org.apache.tapestry5.services.ComponentRequestHandler} pipeline, that feeds out
into the
@@ -33,24 +39,99 @@ import org.apache.tapestry5.services.Traditional;
*/
public class ComponentRequestHandlerTerminator implements
ComponentRequestHandler
{
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ComponentRequestHandlerTerminator.class);
+
private final ComponentEventRequestHandler componentEventRequestHandler;
private final PageRenderRequestHandler pageRenderRequestHandler;
+
+ private final InvalidationEventHub invalidationEventHub;
+
+ private final ComponentDependencyRegistry componentDependencyRegistry;
public ComponentRequestHandlerTerminator(@Traditional
ComponentEventRequestHandler componentEventRequestHandler,
- PageRenderRequestHandler
pageRenderRequestHandler)
+ PageRenderRequestHandler
pageRenderRequestHandler,
+ final @ComponentClasses
InvalidationEventHub invalidationEventHub,
+ final ComponentDependencyRegistry
componentDependencyRegistry)
{
this.componentEventRequestHandler = componentEventRequestHandler;
this.pageRenderRequestHandler = pageRenderRequestHandler;
+ this.invalidationEventHub = invalidationEventHub;
+ this.componentDependencyRegistry = componentDependencyRegistry;
}
public void handleComponentEvent(ComponentEventRequestParameters
parameters) throws IOException
{
- componentEventRequestHandler.handle(parameters);
+ boolean retry = run(() ->
componentEventRequestHandler.handle(parameters));
+ if (retry)
+ {
+ componentEventRequestHandler.handle(parameters);
+ }
}
public void handlePageRender(PageRenderRequestParameters parameters)
throws IOException
{
- pageRenderRequestHandler.handle(parameters);
+ boolean retry = run(() -> pageRenderRequestHandler.handle(parameters));
+ if (retry)
+ {
+ pageRenderRequestHandler.handle(parameters);
+ }
}
+
+ private static final Pattern PATTERN = Pattern.compile(
+ "class (\\S+) cannot be cast to class (\\S+).*");
+
+ private static interface RunnableWithIOException
+ {
+ public void run() throws IOException;
+ }
+
+ private boolean run(RunnableWithIOException runnable) throws IOException
+ {
+ boolean retry = false;
+ try {
+ runnable.run();
+ }
+ catch (RuntimeException e)
+ {
+ Throwable throwable = e;
+ while (!(throwable instanceof ClassCastException) &&
throwable.getCause() != null)
+ {
+ throwable = throwable.getCause();
+ }
+ if (throwable instanceof ClassCastException && throwable != null)
+ {
+ Matcher matcher = PATTERN.matcher(throwable.getMessage());
+ if (matcher.matches() && matcher.groupCount() >= 2 &&
+ isTransformed(matcher.group(1)) &&
+ isTransformed(matcher.group(2)))
+ {
+ LOGGER.warn("Caught exception and trying to recover by
invalidating generated classes caches: {}",
+ throwable.getMessage());
+ componentDependencyRegistry.disableInvalidations();
+
invalidationEventHub.fireInvalidationEvent(Collections.emptyList());
+ componentDependencyRegistry.enableInvalidations();
+ retry = true;
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ return retry;
+ }
+
+ /**
+ * Very simple, but fast, implementation.
+ */
+ private boolean isTransformed(String className)
+ {
+ return className != null && (
+ className.contains(".pages.") ||
+ className.contains(".components.") ||
+ className.contains(".base."));
+
+ }
+
}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
index 99563acb0..b75d1521c 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2010-2013 The Apache Software Foundation
+// Copyright 2010-2024 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.
@@ -40,8 +40,6 @@ import org.slf4j.Logger;
*/
@Scope(ScopeConstants.PERTHREAD)
public class RequestPageCacheImpl implements RequestPageCache, Runnable
-
-/// This should have a listener too!
{
private final Logger logger;
@@ -117,6 +115,10 @@ public class RequestPageCacheImpl implements
RequestPageCache, Runnable
private List<String> listen(List<String> resources)
{
+ if (resources.isEmpty())
+ {
+ cache.clear();
+ }
// TODO: we probably don't need this anymore
for (String resource : resources)
{