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

commit 06e1c00dc7dbb35dd055d9c495ccea63904aab0d
Author: Volker Lamp <vl...@apache.org>
AuthorDate: Sun Apr 30 12:35:29 2023 +0200

    TAP5-1733: Gracefully deal with FormsRequirePostException in prod mode.
---
 .../FormsRequirePostExceptionHandlerAssistant.java | 61 +++++++++++++++++++++
 .../apache/tapestry5/modules/TapestryModule.java   | 13 ++++-
 ...msRequirePostExceptionHandlerAssistantTest.java | 63 ++++++++++++++++++++++
 .../ioc/internal/OperationTrackerImpl.java         | 17 ++++--
 4 files changed, 150 insertions(+), 4 deletions(-)

diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistant.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistant.java
new file mode 100644
index 000000000..4ea0150e0
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistant.java
@@ -0,0 +1,61 @@
+// Copyright 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.
+// 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;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.ExceptionHandlerAssistant;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.commons.util.FormsRequirePostException;
+import org.apache.tapestry5.corelib.components.Form;
+import org.apache.tapestry5.services.ComponentSource;
+import org.apache.tapestry5.services.PageRenderLinkSource;
+import org.apache.tapestry5.services.RequestExceptionHandler;
+
+/**
+ * Handles {@link FormsRequirePostException}s (thrown by the {@link Form} 
component when the request method was
+ * other than post) by redirecting to the page containing the form.
+ * <p>
+ * This assistant is contributed to the default {@link 
RequestExceptionHandler} service in a way that it is
+ * effective only in production mode.
+ * 
+ * @see ExceptionHandlerAssistant
+ * @see RequestExceptionHandler
+ * @see SymbolConstants#PRODUCTION_MODE
+ */
+public class FormsRequirePostExceptionHandlerAssistant implements 
ExceptionHandlerAssistant
+{
+    final ComponentSource componentSource;
+
+    final PageRenderLinkSource linkSource;
+
+    public FormsRequirePostExceptionHandlerAssistant(final ComponentSource 
componentSource, final PageRenderLinkSource linkSource)
+    {
+        this.componentSource = componentSource;
+        this.linkSource = linkSource;
+    }
+
+    @Override
+    public Object handleRequestException(Throwable exception, List<Object> 
exceptionContext) throws IOException
+    {
+        ComponentResources cr = 
componentSource.getActivePage().getComponentResources();
+
+        String pageName = cr.getPageName();
+
+        return linkSource.createPageRenderLink(pageName);
+    }
+}
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 467bcd2a3..b9fc36e16 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -107,6 +107,7 @@ import org.apache.tapestry5.commons.services.PropertyAccess;
 import org.apache.tapestry5.commons.services.TypeCoercer;
 import org.apache.tapestry5.commons.util.AvailableValues;
 import org.apache.tapestry5.commons.util.CollectionFactory;
+import org.apache.tapestry5.commons.util.FormsRequirePostException;
 import org.apache.tapestry5.commons.util.StrategyRegistry;
 import org.apache.tapestry5.corelib.components.BeanEditor;
 import org.apache.tapestry5.corelib.components.PropertyDisplay;
@@ -136,6 +137,7 @@ import org.apache.tapestry5.http.services.Session;
 import org.apache.tapestry5.internal.ComponentOverrideImpl;
 import org.apache.tapestry5.internal.DefaultNullFieldStrategy;
 import org.apache.tapestry5.internal.DefaultValueLabelProvider;
+import org.apache.tapestry5.internal.FormsRequirePostExceptionHandlerAssistant;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.InternalSymbols;
 import org.apache.tapestry5.internal.PropertyOverridesImpl;
@@ -2854,5 +2856,14 @@ public final class TapestryModule
             return info;
         }
     }
-
+    
+    // TAP5-1733
+    @Contribute(RequestExceptionHandler.class)
+    public static void 
gracefullyHandleFormsRequirePostException(MappedConfiguration<Class, Object> 
configuration,
+        @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE) boolean 
productionMode)
+    {
+        if (productionMode)
+            configuration.addInstance(FormsRequirePostException.class, 
FormsRequirePostExceptionHandlerAssistant.class);
+    }
+    
 }
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistantTest.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistantTest.java
new file mode 100644
index 000000000..40e7df6df
--- /dev/null
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/internal/FormsRequirePostExceptionHandlerAssistantTest.java
@@ -0,0 +1,63 @@
+// Copyright 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.
+// 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;
+
+import java.io.IOException;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.commons.util.FormsRequirePostException;
+import org.apache.tapestry5.http.Link;
+import org.apache.tapestry5.runtime.Component;
+import org.apache.tapestry5.services.ComponentSource;
+import org.apache.tapestry5.services.PageRenderLinkSource;
+import org.apache.tapestry5.test.TapestryTestCase;
+import org.testng.annotations.Test;
+
+public class FormsRequirePostExceptionHandlerAssistantTest extends 
TapestryTestCase
+{
+    @Test
+    public void foo()
+    {
+        ComponentSource componentSource = newMock(ComponentSource.class);
+        Component page = newMock(Component.class);
+        ComponentResources componentResources = mockComponentResources();
+        PageRenderLinkSource linkSource = mockPageRenderLinkSource();
+        Link link = mockLink("/foo");
+
+        expect(componentSource.getActivePage()).andReturn(page).atLeastOnce();
+        
expect(page.getComponentResources()).andReturn(componentResources).atLeastOnce();
+        train_getPageName(componentResources, "foo");
+
+        
expect(linkSource.createPageRenderLink("foo")).andReturn(link).atLeastOnce();
+
+        replay();
+
+        FormsRequirePostExceptionHandlerAssistant assistant = new 
FormsRequirePostExceptionHandlerAssistant(componentSource, linkSource);
+
+        FormsRequirePostException exception = new 
FormsRequirePostException("doesn't matter", null);
+
+        try
+        {
+            Link l = (Link) assistant.handleRequestException(exception, null);
+            assertEquals(l.toURI(), link.toURI());
+        }
+        catch (IOException e)
+        {
+            fail();
+        }
+        
+        verify();
+    }
+}
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
index 067b56023..1170548b5 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/OperationTrackerImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2008-2013 The Apache Software Foundation
+// Copyright 2008-2013, 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.
@@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.internal;
 
 import org.apache.tapestry5.commons.util.CollectionFactory;
 import org.apache.tapestry5.commons.util.ExceptionUtils;
+import org.apache.tapestry5.commons.util.FormsRequirePostException;
 import org.apache.tapestry5.commons.util.Stack;
 import org.apache.tapestry5.ioc.IOOperation;
 import org.apache.tapestry5.ioc.Invokable;
@@ -87,7 +88,7 @@ public class OperationTrackerImpl implements OperationTracker
 
         } catch (RuntimeException ex)
         {
-            return logAndRethrow(ex);
+            return handleRuntimeException(ex);
         } catch (Error ex)
         {
             return handleError(ex);
@@ -115,7 +116,7 @@ public class OperationTrackerImpl implements 
OperationTracker
 
         } catch (RuntimeException ex)
         {
-            return logAndRethrow(ex);
+            return handleRuntimeException(ex);
         } catch (Error ex)
         {
             return handleError(ex);
@@ -128,6 +129,16 @@ public class OperationTrackerImpl implements 
OperationTracker
         }
     }
 
+    private <T> T handleRuntimeException(RuntimeException ex)
+    {
+        // This is to prevent the error level log messages
+        if (ExceptionUtils.findCause(ex, FormsRequirePostException.class) != 
null)
+            // pass through without logging
+            throw ex;
+        else
+            return logAndRethrow(ex);
+    }
+
     private void handleFinally()
     {
         operations.pop();

Reply via email to