You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2020/09/10 14:38:18 UTC

[myfaces-tobago] branch master updated (9477940 -> f9ebbd4)

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

lofwyr pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git.


    from 9477940  Upgrade some npm libs
     new 6c31025  chore: slight internal refactoring
     new f9ebbd4  TOBAGO-2055: Merging of theme resources may fail in some cases

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/myfaces/tobago/context/ThemeImpl.java   |  76 ++++++----
 .../myfaces/tobago/context/ThemeResources.java     | 163 ++++++++++++++++++---
 .../internal/config/TobagoConfigBuilder.java       |  52 +++----
 .../tobago/internal/config/TobagoConfigImpl.java   |  45 +++---
 .../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 +-
 ...config2.xml => tobago-config-theme-merge-1.xml} |  25 +++-
 ...config2.xml => tobago-config-theme-merge-2.xml} |  27 +++-
 17 files changed, 452 insertions(+), 256 deletions(-)
 create mode 100644 tobago-core/src/test/java/org/apache/myfaces/tobago/context/ThemeResourcesUnitTest.java
 delete mode 100644 tobago-core/src/test/java/org/apache/myfaces/tobago/internal/mock/faces/MockTheme.java
 copy tobago-core/src/test/resources/{theme-config2.xml => tobago-config-theme-merge-1.xml} (78%)
 copy tobago-core/src/test/resources/{theme-config2.xml => tobago-config-theme-merge-2.xml} (78%)


[myfaces-tobago] 02/02: TOBAGO-2055: Merging of theme resources may fail in some cases

Posted by lo...@apache.org.
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 <ud...@irian.eu>
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<Theme> 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<ThemeScript> 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<ThemeScript> scriptList = new ArrayList<>();
-  private final List<ThemeScript> scriptExcludes = new ArrayList<>();
-  private final List<ThemeStyle> styleList = new ArrayList<>();
-  private final List<ThemeStyle> 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<ThemeScript> includeScripts = new ArrayList<>();
+  private final List<ThemeScript> excludeScripts = new ArrayList<>();
+  private final List<ThemeStyle> includeStyles = new ArrayList<>();
+  private final List<ThemeStyle> 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<ThemeScript> getScriptList() {
-    return scriptList;
+    return includeScripts;
   }
 
   public List<ThemeStyle> 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<TobagoConfigFragment> 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<TobagoConfigFragment> 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<TobagoConfigFragment> 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<TobagoConfigFragment> 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<String, ThemeImpl> 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<String, ThemeImpl> map) {
+  private void resolveThemes(final Map<String, ThemeImpl> 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<TobagoConfigFragment> 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<URL> 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<Theme> fallbackThemeList;
-
-  private String version;
-
-  public MockTheme(final String name, final String displayName, final List<Theme> fallbackThemeList) {
-    this.name = name;
-    this.displayName = displayName;
-    this.fallbackThemeList = fallbackThemeList;
-  }
-
-  @Override
-  public String getName() {
-    return name;
-  }
-
-  @Override
-  public List<Theme> 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 @@
 <tobago-config
     xmlns="http://myfaces.apache.org/tobago/tobago-config"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-2.0.6.xsd"
-    version="2.0.6">
+    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd"
+    version="5.0">
 
-  <mime-types>
-    <mime-type>
-      <extension>odt</extension>
-      <type>application/vnd.oasis.opendocument.text</type>
-    </mime-type>
-  </mime-types>
+  <theme-definitions>
+    <theme-definition>
+      <name>test</name>
+      <version>1.0</version>
+    </theme-definition>
+  </theme-definitions>
 
 </tobago-config>
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 @@
 <tobago-config
     xmlns="http://myfaces.apache.org/tobago/tobago-config"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-2.0.xsd"
-    version="2.0">
+    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd"
+    version="5.0">
 
   <name>name-0</name>
 
   <prevent-frame-attacks>false</prevent-frame-attacks>
 
   <content-security-policy mode="on">
-    <directive>default-src 'self'</directive>
+    <directive name="default-src">'self'</directive>
   </content-security-policy>
 
+  <theme-definitions>
+    <theme-definition>
+      <name>t1</name>
+      <version>1.0</version>
+    </theme-definition>
+  </theme-definitions>
+
 </tobago-config>
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 @@
     <directive>image-src http://apache.org</directive>
   </content-security-policy>
 
+  <theme-definitions>
+    <theme-definition>
+      <name>t1</name>
+      <resource-path>foo-bar</resource-path>
+    </theme-definition>
+  </theme-definitions>
+
   <mime-types>
     <mime-type>
       <extension>test-1</extension>
@@ -49,5 +56,5 @@
       <type>test/three</type>
     </mime-type>
   </mime-types>
-  
+
 </tobago-config>
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 @@
 <tobago-config
     xmlns="http://myfaces.apache.org/tobago/tobago-config"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-2.0.xsd"
-    version="2.0">
+    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd"
+    version="5.0">
 
-  <name>name-0</name>
+  <name>
+    name-1
+  </name>
 
-  <prevent-frame-attacks>false</prevent-frame-attacks>
+  <theme-config>
+    <default-theme>same-theme</default-theme>
+  </theme-config>
 
-  <content-security-policy mode="on">
-    <directive>default-src 'self'</directive>
-  </content-security-policy>
+  <theme-definitions>
+    <theme-definition>
+      <name>same-theme</name>
+      <version>1.0</version>
+      <resources production="false">
+        <includes>
+          <script name="script-1"/>
+        </includes>
+      </resources>
+    </theme-definition>
+  </theme-definitions>
 
 </tobago-config>
diff --git a/tobago-core/src/test/resources/tobago-config-merge-0.xml b/tobago-core/src/test/resources/tobago-config-theme-merge-2.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-2.xml
index 25342d5..554bb25 100644
--- a/tobago-core/src/test/resources/tobago-config-merge-0.xml
+++ b/tobago-core/src/test/resources/tobago-config-theme-merge-2.xml
@@ -20,15 +20,29 @@
 <tobago-config
     xmlns="http://myfaces.apache.org/tobago/tobago-config"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-2.0.xsd"
-    version="2.0">
+    xsi:schemaLocation="http://myfaces.apache.org/tobago/tobago-config http://myfaces.apache.org/tobago/tobago-config-5.0.xsd"
+    version="5.0">
 
-  <name>name-0</name>
+  <name>
+    name-2
+  </name>
 
-  <prevent-frame-attacks>false</prevent-frame-attacks>
+  <ordering>
+    <after>
+      <name>name-1</name>
+    </after>
+  </ordering>
 
-  <content-security-policy mode="on">
-    <directive>default-src 'self'</directive>
-  </content-security-policy>
+  <theme-definitions>
+    <theme-definition>
+      <name>same-theme</name>
+      <version>2.0</version>
+      <resources production="false">
+        <includes>
+          <script name="script-2"/>
+        </includes>
+      </resources>
+    </theme-definition>
+  </theme-definitions>
 
 </tobago-config>


[myfaces-tobago] 01/02: chore: slight internal refactoring

Posted by lo...@apache.org.
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 6c3102514cd9fbec6b0ff144f49a49d40a729dfa
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Thu Sep 10 07:54:56 2020 +0200

    chore: slight internal refactoring
---
 .../apache/myfaces/tobago/context/ThemeImpl.java   | 31 ++++++++++----------
 .../tobago/internal/config/TobagoConfigImpl.java   | 34 +++++++++++-----------
 2 files changed, 32 insertions(+), 33 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 92aa282..1cb786b 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,24 +40,23 @@ public class ThemeImpl implements Theme, Serializable {
   private ThemeImpl fallback;
   private String fallbackName;
   private List<Theme> fallbackList;
-  private ThemeResources productionResources;
-  private ThemeResources resources;
+  private final ThemeResources productionResources;
+  private final ThemeResources resources;
   private ThemeScript[] productionScripts;
   private ThemeStyle[] productionStyles;
   private ThemeScript[] scripts;
   private ThemeStyle[] styles;
-  private boolean versioned;
   private String version;
 
-  private boolean unmodifiable = false;
+  private boolean locked = false;
 
   public ThemeImpl() {
     resources = new ThemeResources(false);
     productionResources = new ThemeResources(true);
   }
 
-  private void checkLocked() throws IllegalStateException {
-    if (unmodifiable) {
+  private void checkUnlocked() throws IllegalStateException {
+    if (locked) {
       throw new IllegalStateException("The configuration must not be changed after initialization!");
     }
   }
@@ -66,7 +65,7 @@ public class ThemeImpl implements Theme, Serializable {
    * Lock the configuration, so it cannot be modified any more.
    */
   public void lock() {
-    unmodifiable = true;
+    locked = true;
   }
 
   @Override
@@ -75,7 +74,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void setName(final String name) {
-    checkLocked();
+    checkUnlocked();
     this.name = name;
   }
 
@@ -85,7 +84,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void setDisplayName(final String displayName) {
-    checkLocked();
+    checkUnlocked();
     this.displayName = displayName;
   }
 
@@ -94,7 +93,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void setFallback(final ThemeImpl fallback) {
-    checkLocked();
+    checkUnlocked();
     this.fallback = fallback;
   }
 
@@ -103,7 +102,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void setFallbackName(final String fallbackName) {
-    checkLocked();
+    checkUnlocked();
     this.fallbackName = fallbackName;
   }
 
@@ -113,7 +112,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void resolveFallbacks() {
-    checkLocked();
+    checkUnlocked();
     fallbackList = new ArrayList<>();
     ThemeImpl actual = this;
     while (actual != null) {
@@ -131,7 +130,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void resolveResources() {
-    checkLocked();
+    checkUnlocked();
     final ThemeImpl fallbackTheme = getFallback();
     if (fallbackTheme != null) {
       fallbackTheme.resolveResources();
@@ -149,7 +148,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   private void addResources(final ThemeResources themeResources) {
-    checkLocked();
+    checkUnlocked();
 
     if (themeResources.isProduction()) {
       productionResources.merge(themeResources);
@@ -159,7 +158,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void init() {
-    checkLocked();
+    checkUnlocked();
     productionScripts = sortScripts(productionResources.getScriptList());
     productionStyles = sortStyles(productionResources.getStyleList());
     scripts = sortScripts(resources.getScriptList());
@@ -202,7 +201,7 @@ public class ThemeImpl implements Theme, Serializable {
   }
 
   public void setVersion(final String version) {
-    checkLocked();
+    checkUnlocked();
     this.version = version;
   }
 
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 a205cb4..f40d5b9 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
@@ -60,7 +60,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   private boolean createSessionSecret;
   private boolean checkSessionSecret;
   private boolean preventFrameAttacks;
-  private ContentSecurityPolicy contentSecurityPolicy;
+  private final ContentSecurityPolicy contentSecurityPolicy;
   private SecurityAnnotation securityAnnotation;
   private boolean setNosniffHeader;
   private Map<String, String> defaultValidatorInfo;
@@ -68,7 +68,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   private boolean decodeLineFeed;
   private Map<String, String> mimeTypes;
 
-  private boolean unmodifiable = false;
+  private boolean locked = false;
 
   protected TobagoConfigImpl(String fixme) { // CDI workaround fixme
     supportedThemeNames = new ArrayList<>();
@@ -88,7 +88,7 @@ public class TobagoConfigImpl extends TobagoConfig {
    * Lock the configuration, so it cannot be modified any more.
    */
   protected void lock() {
-    unmodifiable = true;
+    locked = true;
     supportedThemes = Collections.unmodifiableList(supportedThemes);
     for (final Theme theme : supportedThemes) {
       ((ThemeImpl) theme).lock();
@@ -101,20 +101,20 @@ public class TobagoConfigImpl extends TobagoConfig {
     mimeTypes = Collections.unmodifiableMap(mimeTypes);
   }
 
-  private void checkLocked() throws IllegalStateException {
-    if (unmodifiable) {
+  private void checkUnlocked() throws IllegalStateException {
+    if (locked) {
       throw new TobagoConfigurationException("The configuration must not be changed after initialization!");
     }
   }
 
   protected void addSupportedThemeName(final String name) {
-    checkLocked();
+    checkUnlocked();
     supportedThemeNames.add(name);
   }
 
   // TODO one init method
   protected void resolveThemes() {
-    checkLocked();
+    checkUnlocked();
 
     if (defaultThemeName != null) {
       defaultTheme = availableThemes.get(defaultThemeName);
@@ -186,7 +186,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setDefaultThemeName(final String defaultThemeName) {
-    checkLocked();
+    checkUnlocked();
     this.defaultThemeName = defaultThemeName;
   }
 
@@ -201,7 +201,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void addAvailableTheme(final ThemeImpl availableTheme) {
-    checkLocked();
+    checkUnlocked();
     availableThemes.put(availableTheme.getName(), availableTheme);
   }
 
@@ -211,7 +211,7 @@ public class TobagoConfigImpl extends TobagoConfig {
 
   protected synchronized void initDefaultValidatorInfo() {
     if (defaultValidatorInfo != null) {
-      checkLocked();
+      checkUnlocked();
     }
     final FacesContext facesContext = FacesContext.getCurrentInstance();
     if (facesContext != null) {
@@ -236,7 +236,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setCreateSessionSecret(final boolean createSessionSecret) {
-    checkLocked();
+    checkUnlocked();
     this.createSessionSecret = createSessionSecret;
   }
 
@@ -246,7 +246,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setCheckSessionSecret(final boolean checkSessionSecret) {
-    checkLocked();
+    checkUnlocked();
     this.checkSessionSecret = checkSessionSecret;
   }
 
@@ -257,7 +257,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setPreventFrameAttacks(final boolean preventFrameAttacks) {
-    checkLocked();
+    checkUnlocked();
     this.preventFrameAttacks = preventFrameAttacks;
   }
 
@@ -272,7 +272,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setSetNosniffHeader(final boolean setNosniffHeader) {
-    checkLocked();
+    checkUnlocked();
     this.setNosniffHeader = setNosniffHeader;
   }
 
@@ -282,7 +282,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   public void setSecurityAnnotation(final SecurityAnnotation securityAnnotation) {
-    checkLocked();
+    checkUnlocked();
     this.securityAnnotation = securityAnnotation;
   }
 
@@ -300,7 +300,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   protected void setSanitizer(final Sanitizer sanitizer) {
-    checkLocked();
+    checkUnlocked();
     this.sanitizer = sanitizer;
   }
 
@@ -310,7 +310,7 @@ public class TobagoConfigImpl extends TobagoConfig {
   }
 
   public void setDecodeLineFeed(final boolean decodeLineFeed) {
-    checkLocked();
+    checkUnlocked();
     this.decodeLineFeed = decodeLineFeed;
   }