This is an automated email from the ASF dual-hosted git repository.

thiagohp pushed a commit to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git


The following commit(s) were added to refs/heads/javax by this push:
     new 2b9cf7dae TAP5-2770: trying to recover when a ClassCastException 
happens
2b9cf7dae is described below

commit 2b9cf7dae05c8f8dbb10aa7afda496b4969bdfd7
Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br>
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) 
         {

Reply via email to