This is an automated email from the ASF dual-hosted git repository. lofwyr pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git commit f9ebbd4fe683e1d7484c8925e89a1bd4bd621b27 Author: Udo Schnurpfeil AuthorDate: Thu Sep 10 16:38:00 2020 +0200 TOBAGO-2055: Merging of theme resources may fail in some cases --- .../apache/myfaces/tobago/context/ThemeImpl.java | 53 ++++--- .../myfaces/tobago/context/ThemeResources.java | 163 ++++++++++++++++++--- .../internal/config/TobagoConfigBuilder.java | 52 +++---- .../tobago/internal/config/TobagoConfigImpl.java | 11 +- .../tobago/internal/config/TobagoConfigMerger.java | 4 +- .../tobago/internal/config/TobagoConfigParser.java | 25 +++- .../tobago/context/ThemeResourcesUnitTest.java | 73 +++++++++ .../internal/config/AbstractTobagoTestBase.java | 13 +- .../config/TobagoConfigMergingUnitTest.java | 52 +++++-- .../config/TobagoConfigParserUnitTest.java | 6 +- .../internal/context/ThemeParserUnitTest.java | 30 ++-- .../tobago/internal/mock/faces/MockTheme.java | 79 ---------- .../resources/tobago-config-for-unit-tests.xml | 16 +- .../src/test/resources/tobago-config-merge-0.xml | 13 +- .../src/test/resources/tobago-config-merge-1.xml | 9 +- ...merge-0.xml => tobago-config-theme-merge-1.xml} | 26 +++- ...merge-0.xml => tobago-config-theme-merge-2.xml} | 28 +++- 17 files changed, 428 insertions(+), 225 deletions(-) diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeImpl.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeImpl.java index 1cb786b..cfdd088 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeImpl.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeImpl.java @@ -40,8 +40,8 @@ public class ThemeImpl implements Theme, Serializable { private ThemeImpl fallback; private String fallbackName; private List fallbackList; - private final ThemeResources productionResources; - private final ThemeResources resources; + private ThemeResources productionResources; + private ThemeResources developmentResources; private ThemeScript[] productionScripts; private ThemeStyle[] productionStyles; private ThemeScript[] scripts; @@ -51,8 +51,22 @@ public class ThemeImpl implements Theme, Serializable { private boolean locked = false; public ThemeImpl() { - resources = new ThemeResources(false); - productionResources = new ThemeResources(true); + developmentResources = new ThemeResources(); + productionResources = new ThemeResources(); + } + + public static ThemeImpl merge(ThemeImpl base, ThemeImpl add) { + base.checkUnlocked(); + add.checkUnlocked(); + final ThemeImpl result = new ThemeImpl(); + assert add.name.equals(base.name); + result.name = add.name; + result.displayName = add.displayName != null ? add.displayName : base.displayName; + result.fallbackName = add.fallbackName != null ? add.fallbackName : base.fallbackName; + result.version = add.version != null ? add.version : base.version; + result.productionResources = ThemeResources.merge(base.productionResources, add.productionResources); + result.developmentResources = ThemeResources.merge(base.developmentResources, add.developmentResources); + return result; } private void checkUnlocked() throws IllegalStateException { @@ -134,35 +148,36 @@ public class ThemeImpl implements Theme, Serializable { final ThemeImpl fallbackTheme = getFallback(); if (fallbackTheme != null) { fallbackTheme.resolveResources(); - addResources(fallbackTheme.getProductionResources()); - addResources(fallbackTheme.getResources()); + productionResources = ThemeResources.merge(fallbackTheme.getProductionResources(), productionResources); + developmentResources = ThemeResources.merge(fallbackTheme.getDevelopmentResources(), developmentResources); } } + /** + * @deprecated since 5.0.0 + */ + @Deprecated public ThemeResources getResources() { - return resources; + return developmentResources; } - public ThemeResources getProductionResources() { - return productionResources; + /** + * @since 5.0.0 + */ + public ThemeResources getDevelopmentResources() { + return developmentResources; } - private void addResources(final ThemeResources themeResources) { - checkUnlocked(); - - if (themeResources.isProduction()) { - productionResources.merge(themeResources); - } else { - resources.merge(themeResources); - } + public ThemeResources getProductionResources() { + return productionResources; } public void init() { checkUnlocked(); productionScripts = sortScripts(productionResources.getScriptList()); productionStyles = sortStyles(productionResources.getStyleList()); - scripts = sortScripts(resources.getScriptList()); - styles = sortStyles(resources.getStyleList()); + scripts = sortScripts(developmentResources.getScriptList()); + styles = sortStyles(developmentResources.getStyleList()); } private ThemeScript[] sortScripts(List list) { diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeResources.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeResources.java index 4355195..7949538 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeResources.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/ThemeResources.java @@ -19,7 +19,12 @@ package org.apache.myfaces.tobago.context; +import org.apache.myfaces.tobago.exception.TobagoConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.Serializable; +import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; @@ -30,53 +35,169 @@ import java.util.List; */ public final class ThemeResources implements Serializable { - private final boolean production; - private final List scriptList = new ArrayList<>(); - private final List scriptExcludes = new ArrayList<>(); - private final List styleList = new ArrayList<>(); - private final List styleExcludes = new ArrayList<>(); + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + /** + * @deprecated since 5.0.0 + */ + @Deprecated + private boolean production; + + private final List includeScripts = new ArrayList<>(); + private final List excludeScripts = new ArrayList<>(); + private final List includeStyles = new ArrayList<>(); + private final List excludeStyles = new ArrayList<>(); + + public ThemeResources() { + } + /** + * @deprecated since 5.0.0 + */ + @Deprecated public ThemeResources(final boolean production) { this.production = production; } - public void merge(final ThemeResources toAddResources) { - if (this == toAddResources) { + /** + * @deprecated since 5.0.0, use static {@link #merge} + */ + @Deprecated + public void merge(final ThemeResources fallback) { + if (this == fallback) { return; } - for (int i = toAddResources.scriptList.size() - 1; i >= 0; i--) { - final ThemeScript script = toAddResources.scriptList.get(i); - scriptList.remove(script); - if (!scriptExcludes.contains(script)) { - scriptList.add(0, script); + for (int i = fallback.includeScripts.size() - 1; i >= 0; i--) { + final ThemeScript script = fallback.includeScripts.get(i); + includeScripts.remove(script); + if (!excludeScripts.contains(script)) { + includeScripts.add(0, script); } } - for (int i = toAddResources.styleList.size() - 1; i >= 0; i--) { - final ThemeStyle style = toAddResources.styleList.get(i); - styleList.remove(style); - if (!styleExcludes.contains(style)) { - styleList.add(0, style); + for (int i = fallback.includeStyles.size() - 1; i >= 0; i--) { + final ThemeStyle style = fallback.includeStyles.get(i); + includeStyles.remove(style); + if (!excludeStyles.contains(style)) { + includeStyles.add(0, style); } } } + /** + * @since 5.0.0 + */ + public static ThemeResources merge(final ThemeResources base, final ThemeResources add) { + if (base.production != add.production) { + throw new TobagoConfigurationException("Resources mismatch!"); + } + final ThemeResources result = new ThemeResources(base.production); + + for (ThemeScript includeScript : base.includeScripts) { + if (!add.excludeScripts.contains(includeScript)) { + result.addIncludeScript(includeScript); + } + } + for (ThemeScript includeScript : add.includeScripts) { + result.addIncludeScript(includeScript); + } + + for (ThemeStyle includeStyle : base.includeStyles) { + if (!add.excludeStyles.contains(includeStyle)) { + result.addIncludeStyle(includeStyle); + } + } + for (ThemeStyle includeStyle : add.includeStyles) { + result.addIncludeStyle(includeStyle); + } + + return result; + } + + /** + * @deprecated since 5.0.0 + */ + @Deprecated public boolean isProduction() { return production; } + /** + * @since 5.0.0 + */ + public boolean addIncludeScript(final ThemeScript script) { + for (ThemeScript resource : includeScripts) { + if (resource.getName().equals(script.getName())) { + LOG.warn("Overwriting include script '{}'", script.getName()); + includeScripts.remove(resource); + break; + } + } + return includeScripts.add(script); + } + + /** + * @since 5.0.0 + */ + public boolean addExcludeScript(final ThemeScript script) { + for (ThemeScript resource : excludeScripts) { + if (resource.getName().equals(script.getName())) { + LOG.warn("Overwriting exclude script '{}'", script.getName()); + includeScripts.remove(resource); + break; + } + } + return excludeScripts.add(script); + } + + /** + * @deprecated since 5.0.0, use {@link #addIncludeScript} or {@link #addExcludeScript} + */ + @Deprecated public boolean addScript(final ThemeScript script, final boolean exclude) { - return exclude ? scriptExcludes.add(script) : scriptList.add(script); + return exclude ? addExcludeScript(script) : addIncludeScript(script); + } + + /** + * @since 5.0.0 + */ + public boolean addIncludeStyle(final ThemeStyle style) { + for (ThemeStyle resource : includeStyles) { + if (resource.getName().equals(style.getName())) { + LOG.warn("Overwriting include style '{}'", style.getName()); + includeStyles.remove(resource); + break; + } + } + return includeStyles.add(style); + } + + /** + * @since 5.0.0 + */ + public boolean addExcludeStyle(final ThemeStyle style) { + for (ThemeStyle resource : excludeStyles) { + if (resource.getName().equals(style.getName())) { + LOG.warn("Overwriting exclude style '{}'", style.getName()); + includeStyles.remove(resource); + break; + } + } + return excludeStyles.add(style); } + /** + * @deprecated since 5.0.0, use {@link #addIncludeStyle} or {@link #addExcludeStyle} + */ + @Deprecated public boolean addStyle(final ThemeStyle style, final boolean exclude) { - return exclude ? styleExcludes.add(style) : styleList.add(style); + return exclude ? addExcludeStyle(style) : addIncludeStyle(style); } public List getScriptList() { - return scriptList; + return includeScripts; } public List getStyleList() { - return styleList; + return includeStyles; } } diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java index 5fee911..5b3617c 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java @@ -49,8 +49,6 @@ public class TobagoConfigBuilder { private static final String WEB_INF_TOBAGO_CONFIG_XML = "WEB-INF/tobago-config.xml"; private static final String META_INF_TOBAGO_CONFIG_XML = "META-INF/tobago-config.xml"; - private final List configFragmentList = new ArrayList<>(); - @Inject private ServletContext servletContext; @@ -58,36 +56,33 @@ public class TobagoConfigBuilder { @Produces public TobagoConfig buildTobagoConfig() { - if (tobagoConfig!= null) { - return tobagoConfig; - } else { - try { - tobagoConfig = initializeConfigFromFiles(); - // prepare themes - tobagoConfig.resolveThemes(); - tobagoConfig.initDefaultValidatorInfo(); - tobagoConfig.lock(); - - servletContext.setAttribute(TobagoConfig.TOBAGO_CONFIG, tobagoConfig); - return tobagoConfig; - } catch (final Exception e) { - final String error = "Tobago can't be initialized! Application will not run correctly!"; - LOG.error(error, e); - throw new TobagoConfigurationException(error, e); - } + if (tobagoConfig == null) { + init(); } + return tobagoConfig; } - protected TobagoConfigImpl initializeConfigFromFiles() - throws ServletException, IOException, SAXException, ParserConfigurationException, URISyntaxException { - configFromClasspath(); - configFromWebInf(); - final TobagoConfigSorter sorter = new TobagoConfigSorter(configFragmentList); - final TobagoConfigMerger merger = new TobagoConfigMerger(sorter.topologicalSort()); - return merger.merge(); + private void init() { + final List configFragmentList = new ArrayList<>(); + try { + configFromClasspath(configFragmentList); + configFromWebInf(configFragmentList); + final TobagoConfigSorter sorter = new TobagoConfigSorter(configFragmentList); + final TobagoConfigMerger merger = new TobagoConfigMerger(sorter.topologicalSort()); + tobagoConfig = merger.merge(); + // prepare themes + tobagoConfig.resolveThemes(); + tobagoConfig.initDefaultValidatorInfo(); + tobagoConfig.lock(); + servletContext.setAttribute(TobagoConfig.TOBAGO_CONFIG, tobagoConfig); + } catch (final Exception e) { + final String error = "Tobago can't be initialized! Application will not run correctly!"; + LOG.error(error, e); + throw new TobagoConfigurationException(error, e); + } } - private void configFromWebInf() + private void configFromWebInf(final List configFragmentList) throws IOException, SAXException, ParserConfigurationException, URISyntaxException { final URL url = servletContext.getResource("/" + WEB_INF_TOBAGO_CONFIG_XML); @@ -96,7 +91,8 @@ public class TobagoConfigBuilder { } } - private void configFromClasspath() throws ServletException { + private void configFromClasspath(final List configFragmentList) + throws ServletException { try { if (LOG.isInfoEnabled()) { diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigImpl.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigImpl.java index f40d5b9..c859d4b 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigImpl.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigImpl.java @@ -135,7 +135,8 @@ public class TobagoConfigImpl extends TobagoConfig { if (defaultTheme == null) { final String error = "Did not found any theme! " + "Please ensure you have a tobago-config.xml with a theme-definition in your " - + "theme JAR. Please add a theme JAR to your WEB-INF/lib"; + + "theme JAR. Please add a theme JAR to your classpath. Usually " + + "tobago-theme-standard.jar in WEB-INF/lib"; LOG.error(error); throw new TobagoConfigurationException(error); } else { @@ -202,7 +203,13 @@ public class TobagoConfigImpl extends TobagoConfig { protected void addAvailableTheme(final ThemeImpl availableTheme) { checkUnlocked(); - availableThemes.put(availableTheme.getName(), availableTheme); + final String name = availableTheme.getName(); + if (availableThemes.containsKey(name)) { + final ThemeImpl base = availableThemes.get(name); + availableThemes.put(name, ThemeImpl.merge(base, availableTheme)); + } else { + availableThemes.put(name, availableTheme); + } } public Map getAvailableThemes() { diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java index 0f2fb19..e28e389 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java @@ -111,7 +111,7 @@ public class TobagoConfigMerger { } - resolveThemes(result, result.getAvailableThemes()); + resolveThemes(result.getAvailableThemes()); if (sanitizerClass != null) { try { @@ -128,7 +128,7 @@ public class TobagoConfigMerger { return result; } - private void resolveThemes(final TobagoConfigImpl tobagoConfig, final Map map) { + private void resolveThemes(final Map map) { for (final ThemeImpl theme : map.values()) { final String fallbackName = theme.getFallbackName(); final ThemeImpl fallback = map.get(fallbackName); diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java index 4a4fe5a..3ace262 100644 --- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java +++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java @@ -220,9 +220,17 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver { final String scriptPriority = attributes.getValue(ATTR_PRIORITY); script.setPriority(scriptPriority != null ? Integer.parseUnsignedInt(scriptPriority) : MAX_PRIORITY); if (production) { - currentTheme.getProductionResources().addScript(script, exclude); + if (exclude) { + currentTheme.getProductionResources().addExcludeScript(script); + } else { + currentTheme.getProductionResources().addIncludeScript(script); + } } else { - currentTheme.getResources().addScript(script, exclude); + if (exclude) { + currentTheme.getDevelopmentResources().addExcludeScript(script); + } else { + currentTheme.getDevelopmentResources().addIncludeScript(script); + } } break; @@ -232,9 +240,17 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver { final String stylePriority = attributes.getValue(ATTR_PRIORITY); style.setPriority(stylePriority != null ? Integer.parseUnsignedInt(stylePriority) : MAX_PRIORITY); if (production) { - currentTheme.getProductionResources().addStyle(style, exclude); + if (exclude) { + currentTheme.getProductionResources().addExcludeStyle(style); + } else { + currentTheme.getProductionResources().addIncludeStyle(style); + } } else { - currentTheme.getResources().addStyle(style, exclude); + if (exclude) { + currentTheme.getDevelopmentResources().addExcludeStyle(style); + } else { + currentTheme.getDevelopmentResources().addIncludeStyle(style); + } } break; @@ -266,6 +282,7 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver { case SET_NOSNIFF_HEADER: case THEME_DEFINITIONS: case DISPLAY_NAME: + case VERSION: case VERSIONED: case FALLBACK: case SANITIZER: diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/context/ThemeResourcesUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/context/ThemeResourcesUnitTest.java new file mode 100644 index 0000000..35b3a97 --- /dev/null +++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/context/ThemeResourcesUnitTest.java @@ -0,0 +1,73 @@ +package org.apache.myfaces.tobago.context; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +class ThemeResourcesUnitTest { + + @Test + public void basic() { + final ThemeResources resources = new ThemeResources(false); + // empty + // empty + Assert.assertEquals(0, resources.getScriptList().size()); + Assert.assertEquals(0, resources.getStyleList().size()); + + final ThemeScript a = new ThemeScript(); + a.setName("a"); + // a + // empty + resources.addIncludeScript(a); + Assert.assertEquals(1, resources.getScriptList().size()); + Assert.assertEquals(0, resources.getStyleList().size()); + Assert.assertEquals("a", resources.getScriptList().get(0).getName()); + + final ThemeScript b = new ThemeScript(); + b.setName("b"); + resources.addIncludeScript(b); + // a b + // empty + Assert.assertEquals(2, resources.getScriptList().size()); + Assert.assertEquals(0, resources.getStyleList().size()); + Assert.assertEquals("a", resources.getScriptList().get(0).getName()); + Assert.assertEquals("b", resources.getScriptList().get(1).getName()); + + final ThemeStyle c = new ThemeStyle(); + c.setName("c"); + resources.addIncludeStyle(c); + // a b + // c + Assert.assertEquals(2, resources.getScriptList().size()); + Assert.assertEquals(1, resources.getStyleList().size()); + Assert.assertEquals("a", resources.getScriptList().get(0).getName()); + Assert.assertEquals("b", resources.getScriptList().get(1).getName()); + Assert.assertEquals("c", resources.getStyleList().get(0).getName()); + + // merging exclude + final ThemeResources resources2 = new ThemeResources(false); + final ThemeScript aEx = new ThemeScript(); + aEx.setName("a"); + resources2.addExcludeScript(aEx); + final ThemeStyle d = new ThemeStyle(); + d.setName("d"); + resources2.addIncludeStyle(d); + + final ThemeResources merge = ThemeResources.merge(resources, resources2); + // a b merge with -a -> b + // c merge with d -> c d + Assert.assertEquals(1, merge.getScriptList().size()); + Assert.assertEquals(2, merge.getStyleList().size()); + Assert.assertEquals("b", merge.getScriptList().get(0).getName()); + Assert.assertEquals("c", merge.getStyleList().get(0).getName()); + Assert.assertEquals("d", merge.getStyleList().get(1).getName()); + } + + @Test + public void prodVsDev() { + final ThemeResources dev = new ThemeResources(false); + Assert.assertFalse(dev.isProduction()); + + final ThemeResources prod = new ThemeResources(true); + Assert.assertTrue(prod.isProduction()); + } +} \ No newline at end of file diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java index 5ca6eaf..ff5e123 100644 --- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java +++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java @@ -33,9 +33,7 @@ import org.apache.myfaces.tobago.component.UIPanel; import org.apache.myfaces.tobago.component.UIPopup; import org.apache.myfaces.tobago.component.UIStyle; import org.apache.myfaces.tobago.config.TobagoConfig; -import org.apache.myfaces.tobago.context.ThemeImpl; import org.apache.myfaces.tobago.context.TobagoContext; -import org.apache.myfaces.tobago.internal.mock.faces.MockTheme; import org.apache.myfaces.tobago.internal.webapp.HtmlResponseWriter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -43,7 +41,6 @@ import org.junit.jupiter.api.BeforeEach; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.Locale; import static org.apache.myfaces.tobago.util.ResourceUtils.TOBAGO_RESOURCE_BUNDLE; @@ -76,18 +73,12 @@ public abstract class AbstractTobagoTestBase extends AbstractJsfTestCase { getFacesContext().setResponseWriter(new HtmlResponseWriter(stringWriter, "", StandardCharsets.UTF_8)); // Tobago specific extensions - - final TobagoConfigImpl tobagoConfig = TobagoConfigMergingUnitTest.loadAndMerge("tobago-config-for-unit-tests.xml"); - final ThemeImpl theme = new MockTheme("default", "Default Mock Theme", Collections.emptyList()); - final ThemeImpl one = new MockTheme("one", "Mock Theme One", Collections.singletonList(theme)); - tobagoConfig.addAvailableTheme(theme); - tobagoConfig.addAvailableTheme(one); - tobagoConfig.resolveThemes(); + final TobagoConfigImpl tobagoConfig = TobagoConfigMergingUnitTest.load("tobago-config-for-unit-tests.xml"); tobagoConfig.initDefaultValidatorInfo(); servletContext.setAttribute(TobagoConfig.TOBAGO_CONFIG, tobagoConfig); final TobagoContext tobagoContext = new TobagoContext(); - tobagoContext.setTheme(one); + tobagoContext.setTheme(tobagoConfig.getDefaultTheme()); facesContext.getViewRoot().setLocale(Locale.ENGLISH); request.setAttribute(TobagoContext.BEAN_NAME, tobagoContext); diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java index 85959f7..5c7bf8e 100644 --- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java +++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java @@ -39,7 +39,7 @@ public class TobagoConfigMergingUnitTest { public void testPreventFrameAttacksCascadingDefault() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml", "tobago-config-merge-1.xml"); @@ -50,7 +50,7 @@ public class TobagoConfigMergingUnitTest { public void testPreventFrameAttacks() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge("tobago-config-merge-0.xml"); + final TobagoConfigImpl config = load("tobago-config-merge-0.xml"); Assertions.assertFalse(config.isPreventFrameAttacks()); } @@ -59,7 +59,7 @@ public class TobagoConfigMergingUnitTest { public void testPreventFrameAttacksDefault() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge("tobago-config-merge-1.xml"); + final TobagoConfigImpl config = load("tobago-config-merge-1.xml"); Assertions.assertTrue(config.isPreventFrameAttacks()); } @@ -68,7 +68,7 @@ public class TobagoConfigMergingUnitTest { public void testContentSecurityPolicy() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml"); Assertions.assertSame(config.getContentSecurityPolicy().getMode(), ContentSecurityPolicy.Mode.ON); @@ -81,7 +81,7 @@ public class TobagoConfigMergingUnitTest { public void testContentSecurityPolicyExtend() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml", "tobago-config-merge-1.xml"); @@ -96,7 +96,7 @@ public class TobagoConfigMergingUnitTest { public void testContentSecurityPolicyOff() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml", "tobago-config-merge-1.xml", "tobago-config-merge-2.xml"); @@ -109,7 +109,7 @@ public class TobagoConfigMergingUnitTest { public void testContentSecurityPolicyNameAttribute() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml", "tobago-config-merge-3.xml"); @@ -123,7 +123,7 @@ public class TobagoConfigMergingUnitTest { public void testMimeTypes() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-merge-0.xml", "tobago-config-merge-1.xml", "tobago-config-merge-2.xml"); @@ -139,7 +139,7 @@ public class TobagoConfigMergingUnitTest { public void testResourcePriority() throws IOException, SAXException, ParserConfigurationException, URISyntaxException { - final TobagoConfigImpl config = loadAndMerge( + final TobagoConfigImpl config = load( "tobago-config-5.0.xml", "tobago-config-5.0-replace.xml"); final String[] expected = new String[]{ @@ -161,7 +161,7 @@ public class TobagoConfigMergingUnitTest { ex[i++].setName(script); } - config.resolveThemes(); +// config.resolveThemes(); final Theme defaultTheme = config.getDefaultTheme(); final ThemeScript[] scripts = defaultTheme.getScriptResources(true); @@ -170,7 +170,32 @@ public class TobagoConfigMergingUnitTest { Assertions.assertEquals("some-version-2", defaultTheme.getVersion()); } - public static TobagoConfigImpl loadAndMerge(final String... names) + @Test + public void testMergeThemePatch() + throws IOException, SAXException, ParserConfigurationException, URISyntaxException { + + final TobagoConfigImpl config12 = load( + "tobago-config-theme-merge-1.xml", + "tobago-config-theme-merge-2.xml"); + Assertions.assertEquals("2.0", config12.getDefaultTheme().getVersion()); + + final ThemeScript[] scripts12 = config12.getDefaultTheme().getScriptResources(false); + Assertions.assertEquals(2, scripts12.length); + Assertions.assertEquals("script-1", scripts12[0].getName()); + Assertions.assertEquals("script-2", scripts12[1].getName()); + + final TobagoConfigImpl config21 = load( + "tobago-config-theme-merge-2.xml", + "tobago-config-theme-merge-1.xml"); + Assertions.assertEquals("2.0", config21.getDefaultTheme().getVersion()); + + final ThemeScript[] scripts21 = config21.getDefaultTheme().getScriptResources(false); + Assertions.assertEquals(2, scripts21.length); + Assertions.assertEquals("script-1", scripts21[0].getName()); + Assertions.assertEquals("script-2", scripts21[1].getName()); + } + + public static TobagoConfigImpl load(final String... names) throws IOException, SAXException, ParserConfigurationException, URISyntaxException { final List list = new ArrayList<>(); @@ -183,6 +208,9 @@ public class TobagoConfigMergingUnitTest { final TobagoConfigSorter sorter = new TobagoConfigSorter(list); final TobagoConfigMerger merger = new TobagoConfigMerger(sorter.topologicalSort()); - return merger.merge(); + final TobagoConfigImpl result = merger.merge(); + result.resolveThemes(); + result.lock(); + return result; } } diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java index 22656ba..24071b5 100644 --- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java +++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java @@ -78,16 +78,14 @@ public class TobagoConfigParserUnitTest { final ThemeImpl theme1 = fragment.getThemeDefinitions().get(0); Assertions.assertEquals("my-theme-1", theme1.getName()); Assertions.assertEquals("My Theme 1", theme1.getDisplayName()); - Assertions.assertTrue(theme1.getProductionResources().isProduction()); Assertions.assertEquals("script.js", theme1.getProductionResources().getScriptList().get(0).getName()); Assertions.assertEquals("style.css", theme1.getProductionResources().getStyleList().get(0).getName()); final ThemeImpl theme2 = fragment.getThemeDefinitions().get(1); Assertions.assertEquals("my-theme-2", theme2.getName()); Assertions.assertEquals("my-theme-1", theme2.getFallbackName()); - Assertions.assertFalse(theme2.getResources().isProduction()); - Assertions.assertEquals(0, theme2.getResources().getScriptList().size()); - Assertions.assertEquals(0, theme2.getResources().getStyleList().size()); + Assertions.assertEquals(0, theme2.getDevelopmentResources().getScriptList().size()); + Assertions.assertEquals(0, theme2.getDevelopmentResources().getStyleList().size()); Assertions.assertEquals(0, theme2.getProductionResources().getScriptList().size()); Assertions.assertEquals(0, theme2.getProductionResources().getStyleList().size()); diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/context/ThemeParserUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/context/ThemeParserUnitTest.java index 38a8cf9..bb96413 100644 --- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/context/ThemeParserUnitTest.java +++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/context/ThemeParserUnitTest.java @@ -40,14 +40,13 @@ public class ThemeParserUnitTest { Enumeration urls = classLoader.getResources("theme-config.xml"); final TobagoConfigParser parser = new TobagoConfigParser(); - ThemeImpl theme = null; if (urls.hasMoreElements()) { final URL themeUrl = urls.nextElement(); - theme = parser.parse(themeUrl).getThemeDefinitions().get(0); + final ThemeImpl theme = parser.parse(themeUrl).getThemeDefinitions().get(0); Assertions.assertEquals("test", theme.getName()); - Assertions.assertNotNull(theme.getResources()); + Assertions.assertNotNull(theme.getDevelopmentResources()); Assertions.assertNotNull(theme.getProductionResources()); - final ThemeResources resources = theme.getResources(); + final ThemeResources resources = theme.getDevelopmentResources(); final ThemeResources productionResources = theme.getProductionResources(); Assertions.assertEquals(1, resources.getScriptList().size()); @@ -61,40 +60,37 @@ public class ThemeParserUnitTest { urls = classLoader.getResources("theme-config2.xml"); - ThemeImpl theme2 = null; if (urls.hasMoreElements()) { final URL themeUrl = urls.nextElement(); - theme2 = parser.parse(themeUrl).getThemeDefinitions().get(0); + final ThemeImpl theme2 = parser.parse(themeUrl).getThemeDefinitions().get(0); Assertions.assertEquals("test2", theme2.getName()); - Assertions.assertNotNull(theme2.getResources()); - Assertions.assertEquals(1, theme2.getResources().getScriptList().size()); - Assertions.assertEquals(1, theme2.getResources().getStyleList().size()); + Assertions.assertNotNull(theme2.getDevelopmentResources()); + Assertions.assertEquals(1, theme2.getDevelopmentResources().getScriptList().size()); + Assertions.assertEquals(1, theme2.getDevelopmentResources().getStyleList().size()); } else { Assertions.fail(); } urls = classLoader.getResources("theme-config3.xml"); - ThemeImpl theme3 = null; if (urls.hasMoreElements()) { final URL themeUrl = urls.nextElement(); - theme3 = parser.parse(themeUrl).getThemeDefinitions().get(0); + final ThemeImpl theme3 = parser.parse(themeUrl).getThemeDefinitions().get(0); Assertions.assertEquals("test3", theme3.getName()); - Assertions.assertEquals(0, theme3.getResources().getScriptList().size()); - Assertions.assertEquals(0, theme3.getResources().getStyleList().size()); + Assertions.assertEquals(0, theme3.getDevelopmentResources().getScriptList().size()); + Assertions.assertEquals(0, theme3.getDevelopmentResources().getStyleList().size()); } else { Assertions.fail(); } urls = classLoader.getResources("theme-config4.xml"); - ThemeImpl theme4 = null; if (urls.hasMoreElements()) { final URL themeUrl = urls.nextElement(); - theme4 = parser.parse(themeUrl).getThemeDefinitions().get(0); + final ThemeImpl theme4 = parser.parse(themeUrl).getThemeDefinitions().get(0); Assertions.assertEquals("test4", theme4.getName()); - Assertions.assertEquals(0, theme4.getResources().getScriptList().size()); - Assertions.assertEquals(0, theme4.getResources().getStyleList().size()); + Assertions.assertEquals(0, theme4.getDevelopmentResources().getScriptList().size()); + Assertions.assertEquals(0, theme4.getDevelopmentResources().getStyleList().size()); } else { Assertions.fail(); } diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/mock/faces/MockTheme.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/mock/faces/MockTheme.java deleted file mode 100644 index e10649c..0000000 --- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/mock/faces/MockTheme.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.myfaces.tobago.internal.mock.faces; - -import org.apache.myfaces.tobago.context.Theme; -import org.apache.myfaces.tobago.context.ThemeImpl; -import org.apache.myfaces.tobago.context.ThemeScript; -import org.apache.myfaces.tobago.context.ThemeStyle; - -import java.util.List; - -public class MockTheme extends ThemeImpl { - - private String name; - - private String displayName; - - private List fallbackThemeList; - - private String version; - - public MockTheme(final String name, final String displayName, final List fallbackThemeList) { - this.name = name; - this.displayName = displayName; - this.fallbackThemeList = fallbackThemeList; - } - - @Override - public String getName() { - return name; - } - - @Override - public List getFallbackList() { - return fallbackThemeList; - } - - @Override - public String getDisplayName() { - return displayName; - } - - @Override - public ThemeScript[] getScriptResources(final boolean production) { - return new ThemeScript[0]; - } - - @Override - public ThemeStyle[] getStyleResources(final boolean production) { - return new ThemeStyle[0]; - } - - @Override - public String getVersion() { - return version; - } - - @Override - public void setVersion(final String version) { - this.version = version; - } -} diff --git a/tobago-core/src/test/resources/tobago-config-for-unit-tests.xml b/tobago-core/src/test/resources/tobago-config-for-unit-tests.xml index a81a0ec..4a9c10d 100644 --- a/tobago-core/src/test/resources/tobago-config-for-unit-tests.xml +++ b/tobago-core/src/test/resources/tobago-config-for-unit-tests.xml @@ -20,14 +20,14 @@ + xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd" + version="5.0"> - - - odt - application/vnd.oasis.opendocument.text - - + + + test + 1.0 + + diff --git a/tobago-core/src/test/resources/tobago-config-merge-0.xml b/tobago-core/src/test/resources/tobago-config-merge-0.xml index 25342d5..be3ac6c 100644 --- a/tobago-core/src/test/resources/tobago-config-merge-0.xml +++ b/tobago-core/src/test/resources/tobago-config-merge-0.xml @@ -20,15 +20,22 @@ + xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd" + version="5.0"> name-0 false - default-src 'self' + 'self' + + + t1 + 1.0 + + + diff --git a/tobago-core/src/test/resources/tobago-config-merge-1.xml b/tobago-core/src/test/resources/tobago-config-merge-1.xml index 7ec3dae..316f578 100644 --- a/tobago-core/src/test/resources/tobago-config-merge-1.xml +++ b/tobago-core/src/test/resources/tobago-config-merge-1.xml @@ -35,6 +35,13 @@ image-src http://apache.org + + + t1 + foo-bar + + + test-1 @@ -49,5 +56,5 @@ test/three - + diff --git a/tobago-core/src/test/resources/tobago-config-merge-0.xml b/tobago-core/src/test/resources/tobago-config-theme-merge-1.xml similarity index 69% copy from tobago-core/src/test/resources/tobago-config-merge-0.xml copy to tobago-core/src/test/resources/tobago-config-theme-merge-1.xml index 25342d5..3f8df65 100644 --- a/tobago-core/src/test/resources/tobago-config-merge-0.xml +++ b/tobago-core/src/test/resources/tobago-config-theme-merge-1.xml @@ -20,15 +20,27 @@ + xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd" + version="5.0"> - name-0 + + name-1 + - false + + same-theme + - - default-src 'self' - + + + same-theme + 1.0 + + +