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();