myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lof...@apache.org
Subject [myfaces-tobago] 02/02: TOBAGO-2055: Merging of theme resources may fail in some cases
Date Thu, 10 Sep 2020 14:38:20 GMT
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 <udo.schnurpfeil@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>


Mime
View raw message