diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java b/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java index 0739ff87b22..cb5364ae285 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java @@ -17,6 +17,10 @@ package org.apache.wicket.markup; import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.wicket.Application; import org.apache.wicket.MarkupContainer; @@ -61,6 +65,8 @@ public static MarkupFactory get() return Application.get().getMarkupSettings().getMarkupFactory(); } + private final Map> additionalMarkupFilters = new LinkedHashMap<>(); + /** * Construct. */ @@ -108,7 +114,7 @@ public IMarkupLoader getMarkupLoader() public MarkupParser newMarkupParser(final MarkupResourceStream resource) { // Markup parsers can not be re-used - return new MarkupParser(newXmlPullParser(), resource) + final MarkupParser markupParser = new MarkupParser(newXmlPullParser(), resource) { @Override protected IMarkupFilter onAppendMarkupFilter(final IMarkupFilter filter) @@ -116,6 +122,17 @@ protected IMarkupFilter onAppendMarkupFilter(final IMarkupFilter filter) return MarkupFactory.this.onAppendMarkupFilter(filter); } }; + + additionalMarkupFilters.entrySet().forEach((entry) -> { + final IMarkupFilter markupFilter = entry.getKey(); + final Class beforeFilter = entry.getValue(); + if (beforeFilter == null) { + markupParser.add(markupFilter); + } else { + markupParser.add(markupFilter, beforeFilter); + } + }); + return markupParser; } /** @@ -454,4 +471,50 @@ public final Markup loadMarkup(final MarkupContainer container, // Markup not found. Errors should throw a Wicket exception return null; } + + /** + * Adds an additional {@link IMarkupFilter} to {@link MarkupParser}. + * @param markupFilter added markupFilter + */ + public void addAdditionalMarkupFilter(final IMarkupFilter markupFilter) { + addAdditionalMarkupFilter(markupFilter, null); + } + + /** + * Adds an additional {@link IMarkupFilter} to {@link MarkupParser}. + * @param markupFilter added markupFilter + * @param beforeFilterClass add filter before given beforeFilterClass + */ + public void addAdditionalMarkupFilter(final IMarkupFilter markupFilter, final Class beforeFilterClass) { + if (markupFilter != null) { + additionalMarkupFilters.put(markupFilter, beforeFilterClass); + } + } + + /** + * Remove an additional {@link IMarkupFilter}. + * @param markupFilter removedMarkupFilter + */ + public void removeAdditionalMarkupFilter(final IMarkupFilter markupFilter) { + if (markupFilter !=null) { + additionalMarkupFilters.remove(markupFilter); + } + } + + /** + * Remove additional {@link IMarkupFilter}s + * @param markupFilterClass filter-class + */ + public void removeAdditionalMarkupFilters(final Class markupFilterClass) { + if (markupFilterClass != null) { + final Set removedMarkupFilters = additionalMarkupFilters + .keySet() + .stream() + .filter(e -> markupFilterClass.isAssignableFrom(e.getClass())) + .collect(Collectors.toSet()); + removedMarkupFilters + .stream() + .forEach(additionalMarkupFilters::remove); + } + } } diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/MarkupFactoryTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/MarkupFactoryTest.java new file mode 100644 index 00000000000..ead5c0fb690 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/MarkupFactoryTest.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.wicket.markup; + +import java.text.ParseException; + +import org.apache.wicket.markup.parser.AbstractMarkupFilter; +import org.apache.wicket.markup.parser.IMarkupFilter; +import org.apache.wicket.util.resource.StringResourceStream; +import org.apache.wicket.util.tester.WicketTestCase; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author Hans Hosea Schaefer + */ +class MarkupFactoryTest extends WicketTestCase { + + private IMarkupFilter dummyMarkupFilter = new DummyMarkupFilter() {}; + private IMarkupFilter secondMarkupFilter = new DummyMarkupFilter() {}; + + @Test + public void testAdditionalMarkupFiltersAdded() { + final MarkupFactory markupFactory = new MarkupFactory(); + markupFactory.addAdditionalMarkupFilter(secondMarkupFilter); + markupFactory.addAdditionalMarkupFilter(dummyMarkupFilter, secondMarkupFilter.getClass()); + + final MarkupParser markupParser = markupFactory.newMarkupParser(new MarkupResourceStream(new StringResourceStream(""))); + final MarkupParser.MarkupFilterList markupFilters = markupParser.getMarkupFilters(); + Assertions.assertTrue(markupFilters.contains(secondMarkupFilter)); + Assertions.assertTrue(markupFilters.contains(dummyMarkupFilter)); + } + + @Test + public void testAdditionalMarkupFiltersAddedAndOneRemoved() { + final MarkupFactory markupFactory = new MarkupFactory(); + markupFactory.addAdditionalMarkupFilter(secondMarkupFilter); + markupFactory.addAdditionalMarkupFilter(dummyMarkupFilter, secondMarkupFilter.getClass()); + markupFactory.removeAdditionalMarkupFilter(secondMarkupFilter); + + final MarkupParser markupParser = markupFactory.newMarkupParser(new MarkupResourceStream(new StringResourceStream(""))); + final MarkupParser.MarkupFilterList markupFilters = markupParser.getMarkupFilters(); + Assertions.assertFalse(markupFilters.contains(secondMarkupFilter)); + Assertions.assertTrue(markupFilters.contains(dummyMarkupFilter)); + } + + @Test + public void testAdditionalMarkupFiltersAddedAndOneRemovedByClass() { + final MarkupFactory markupFactory = new MarkupFactory(); + markupFactory.addAdditionalMarkupFilter(secondMarkupFilter); + markupFactory.addAdditionalMarkupFilter(dummyMarkupFilter, secondMarkupFilter.getClass()); + markupFactory.removeAdditionalMarkupFilters(secondMarkupFilter.getClass()); + + final MarkupParser markupParser = markupFactory.newMarkupParser(new MarkupResourceStream(new StringResourceStream(""))); + final MarkupParser.MarkupFilterList markupFilters = markupParser.getMarkupFilters(); + Assertions.assertFalse(markupFilters.contains(secondMarkupFilter)); + Assertions.assertTrue(markupFilters.contains(dummyMarkupFilter)); + } + + @Test + public void testAdditionalMarkupFiltersAddedAndAllRemovedByClass() { + final MarkupFactory markupFactory = new MarkupFactory(); + markupFactory.addAdditionalMarkupFilter(secondMarkupFilter); + markupFactory.addAdditionalMarkupFilter(dummyMarkupFilter, secondMarkupFilter.getClass()); + markupFactory.removeAdditionalMarkupFilters(IMarkupFilter.class); + + final MarkupParser markupParser = markupFactory.newMarkupParser(new MarkupResourceStream(new StringResourceStream(""))); + final MarkupParser.MarkupFilterList markupFilters = markupParser.getMarkupFilters(); + Assertions.assertFalse(markupFilters.contains(secondMarkupFilter)); + Assertions.assertFalse(markupFilters.contains(dummyMarkupFilter)); + } + + + static abstract class DummyMarkupFilter extends AbstractMarkupFilter { + protected MarkupElement onComponentTag(final ComponentTag tag) throws ParseException { + return null; + } + } +} \ No newline at end of file