This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-doxia-sitetools.git
The following commit(s) were added to refs/heads/master by this push:
new f976f25 Support conditional resources from skins (#610)
f976f25 is described below
commit f976f25f4146d0435fe33b620606c2fd57cf90f9
Author: Konrad Windszus <[email protected]>
AuthorDate: Tue Feb 24 18:26:47 2026 +0100
Support conditional resources from skins (#610)
Extend Skin descriptor with resource conditions.
All resources without a condition are always included,
the other ones only if the condition evaluates to true.
This closes #609
---
doxia-site-renderer/pom.xml | 3 +-
.../doxia/siterenderer/DefaultSiteRenderer.java | 96 ++++++++++++++----
.../siterenderer/DefaultSiteRendererTest.java | 108 +++++++++++++++------
.../src/test/resources/site/site.xml | 5 +
.../resources/skin-minimal/META-INF/maven/site.vm | 1 +
.../META-INF/maven/site.vm | 1 +
.../META-INF/maven/skin.xml | 38 ++++++++
.../skin-with-conditional-resources/js/exclude.js | 1 +
.../skin-with-conditional-resources/js/include.js | 1 +
.../skin-with-conditional-resources/js/include2.js | 1 +
.../skin-with-conditional-resources/js/include3.js | 1 +
doxia-skin-model/pom.xml | 2 +-
doxia-skin-model/src/main/mdo/skin.mdo | 42 +++++++-
13 files changed, 251 insertions(+), 49 deletions(-)
diff --git a/doxia-site-renderer/pom.xml b/doxia-site-renderer/pom.xml
index 7ad23f5..5cbbd3d 100644
--- a/doxia-site-renderer/pom.xml
+++ b/doxia-site-renderer/pom.xml
@@ -37,7 +37,6 @@ under the License.
<velocityToolsVersion>3.1</velocityToolsVersion>
<mermaidVersion>11.12.2</mermaidVersion>
</properties>
-
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
@@ -218,6 +217,8 @@ under the License.
<configuration>
<excludes combine.children="append">
<exclude>src/main/resources/js/*</exclude>
+ <exclude>src/test/resources/**/*.vm</exclude>
+ <exclude>src/test/resources/**/*.js</exclude>
</excludes>
</configuration>
</plugin>
diff --git
a/doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DefaultSiteRenderer.java
b/doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DefaultSiteRenderer.java
index 1380b8b..82ed93e 100644
---
a/doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DefaultSiteRenderer.java
+++
b/doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DefaultSiteRenderer.java
@@ -38,6 +38,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -67,12 +68,14 @@ import
org.apache.maven.doxia.parser.manager.ParserNotFoundException;
import org.apache.maven.doxia.parser.module.ParserModule;
import org.apache.maven.doxia.parser.module.ParserModuleManager;
import org.apache.maven.doxia.site.SiteModel;
+import org.apache.maven.doxia.site.skin.ResourceCondition;
import org.apache.maven.doxia.site.skin.SkinModel;
import org.apache.maven.doxia.site.skin.io.xpp3.SkinXpp3Reader;
import org.apache.maven.doxia.siterenderer.SiteRenderingContext.SiteDirectory;
import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
import org.apache.maven.doxia.util.XmlValidator;
import org.apache.velocity.Template;
+import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
@@ -563,29 +566,30 @@ public class DefaultSiteRenderer implements Renderer {
/**
* Create a Velocity Context for a Doxia document, containing every
information about rendered document.
*
- * @param docRenderingContext the document's rendering context
+ * @param docRenderingContext the document's rendering context (may be
{@code null} in which case the context does not contain document-specific
information)
* @param siteRenderingContext the site rendering context
* @return a Velocity tools managed context
*/
protected Context createDocumentVelocityContext(
DocumentRenderingContext docRenderingContext, SiteRenderingContext
siteRenderingContext) {
Context context =
createToolManagedVelocityContext(siteRenderingContext);
- //
----------------------------------------------------------------------
- // Data objects
- //
----------------------------------------------------------------------
-
- context.put("relativePath", docRenderingContext.getRelativePath());
-
- String currentFilePath = docRenderingContext.getOutputName();
- context.put("currentFilePath", currentFilePath);
- // TODO Deprecated -- will be removed!
- context.put("currentFileName", currentFilePath);
-
- String alignedFilePath = PathTool.calculateLink(currentFilePath,
docRenderingContext.getRelativePath());
- context.put("alignedFilePath", alignedFilePath);
- // TODO Deprecated -- will be removed!
- context.put("alignedFileName", alignedFilePath);
-
+ if (docRenderingContext != null) {
+ //
----------------------------------------------------------------------
+ // Data objects
+ //
----------------------------------------------------------------------
+
+ context.put("relativePath", docRenderingContext.getRelativePath());
+
+ String currentFilePath = docRenderingContext.getOutputName();
+ context.put("currentFilePath", currentFilePath);
+ // TODO Deprecated -- will be removed!
+ context.put("currentFileName", currentFilePath);
+
+ String alignedFilePath = PathTool.calculateLink(currentFilePath,
docRenderingContext.getRelativePath());
+ context.put("alignedFilePath", alignedFilePath);
+ // TODO Deprecated -- will be removed!
+ context.put("alignedFileName", alignedFilePath);
+ }
context.put("site", siteRenderingContext.getSiteModel());
// TODO Deprecated -- will be removed!
context.put("decoration", siteRenderingContext.getSiteModel());
@@ -845,6 +849,8 @@ public class DefaultSiteRenderer implements Renderer {
public void copyResources(SiteRenderingContext siteRenderingContext, File
outputDirectory) throws IOException {
ZipFile file = getZipFile(siteRenderingContext.getSkin().getFile());
+ Context velocityContext = createDocumentVelocityContext(null,
siteRenderingContext);
+ Map<String, String> resourceConditions =
createResourceConditionsMap(siteRenderingContext.getSkinModel());
try {
for (Enumeration<? extends ZipEntry> e = file.entries();
e.hasMoreElements(); ) {
ZipEntry entry = e.nextElement();
@@ -857,7 +863,9 @@ public class DefaultSiteRenderer implements Renderer {
// resource
continue;
}
-
+ if (!isResourceRelevant(entry.getName(),
velocityContext, resourceConditions)) {
+ continue;
+ }
destFile.getParentFile().mkdirs();
copyFileFromZip(file, entry, destFile);
@@ -931,6 +939,58 @@ public class DefaultSiteRenderer implements Renderer {
}
}
+ private boolean isResourceRelevant(String name, Context velocityContext,
Map<String, String> resourceConditions) {
+ if (resourceConditions == null ||
!resourceConditions.containsKey(name)) {
+ LOGGER.debug("No condition for resource '{}'", name);
+ } else {
+ String condition = resourceConditions.get(name);
+ LOGGER.debug(
+ "Evaluating condition for resource '{}' with condition
'{}'",
+ name,
+ escapeLineBreaksForLogging(condition));
+ StringWriter writer = new StringWriter();
+ Velocity.evaluate(velocityContext, writer,
"conditional-resource-evaluation", condition);
+ String result = writer.toString().trim();
+ LOGGER.debug("Condition evaluation result: {}", result);
+ if (!Boolean.parseBoolean(result)) {
+ LOGGER.debug("Excluding resource '{}'", name);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private Map<String, String> createResourceConditionsMap(SkinModel
skinModel) {
+ if (skinModel == null) {
+ LOGGER.debug("No skin model provided, so no resource conditions
will be applied.");
+ return Collections.emptyMap();
+ }
+ Map<String, String> resourceConditions = new HashMap<>();
+ for (ResourceCondition resource : skinModel.getResourceConditions()) {
+ if (resource.getVtlCondition() != null
+ && !resource.getVtlCondition().isEmpty()) {
+ for (String resourceName : resource.getResourceNames()) {
+ if (resourceConditions.containsKey(resourceName)) {
+ LOGGER.warn(
+ "Multiple conditions found for resource '{}'.
Only the first one will be used.",
+ resourceName);
+ continue;
+ }
+ LOGGER.debug(
+ "Adding condition for resource '{}' with condition
'{}'",
+ resourceName,
+
escapeLineBreaksForLogging(resource.getVtlCondition()));
+ resourceConditions.put(resourceName,
resource.getVtlCondition());
+ }
+ }
+ }
+ return resourceConditions;
+ }
+
+ private static String escapeLineBreaksForLogging(String input) {
+ return input.replaceAll("\\r?\\n", "\\\\n");
+ }
+
private static void copyFileFromZip(ZipFile file, ZipEntry entry, File
destFile) throws IOException {
FileOutputStream fos = new FileOutputStream(destFile);
diff --git
a/doxia-site-renderer/src/test/java/org/apache/maven/doxia/siterenderer/DefaultSiteRendererTest.java
b/doxia-site-renderer/src/test/java/org/apache/maven/doxia/siterenderer/DefaultSiteRendererTest.java
index 34151df..d41ed81 100644
---
a/doxia-site-renderer/src/test/java/org/apache/maven/doxia/siterenderer/DefaultSiteRendererTest.java
+++
b/doxia-site-renderer/src/test/java/org/apache/maven/doxia/siterenderer/DefaultSiteRendererTest.java
@@ -20,7 +20,6 @@ package org.apache.maven.doxia.siterenderer;
import javax.inject.Inject;
-import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -28,7 +27,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.net.URI;
import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -37,6 +43,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarOutputStream;
+import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import org.apache.commons.io.IOUtils;
@@ -59,6 +66,7 @@ import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.ReflectionUtils;
import org.codehaus.plexus.util.StringUtils;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -98,9 +106,16 @@ public class DefaultSiteRendererTest {
@Inject
private PlexusContainer container;
- private File skinJar = new File(getBasedir(),
"target/test-classes/skin.jar");
+ private static File minimalSkinJar;
- private File minimalSkinJar = new File(getBasedir(),
"target/test-classes/minimal-skin.jar");
+ @BeforeAll
+ static void beforeAll() throws IOException {
+ // only create once, as otherwise Windows might have issues
overwriting/deleting it while MS Defender is
+ // scanning it
+ // as multiple test are using it
+ minimalSkinJar = new File(getBasedir(),
"target/test-classes/minimal-skin.jar");
+
createJarFromDirectory(getTestFile("src/test/resources/skin-minimal").toPath(),
minimalSkinJar.toPath());
+ }
/**
* @throws java.lang.Exception if something goes wrong.
@@ -108,28 +123,36 @@ public class DefaultSiteRendererTest {
@BeforeEach
protected void setUp() throws Exception {
siteRenderer = (SiteRenderer) container.lookup(SiteRenderer.class);
+ }
- InputStream skinIS =
getClass().getResourceAsStream("velocity-toolmanager.vm");
- JarOutputStream jarOS = new JarOutputStream(new
FileOutputStream(skinJar));
- try {
- jarOS.putNextEntry(new ZipEntry("META-INF/maven/site.vm"));
- IOUtil.copy(skinIS, jarOS);
- jarOS.closeEntry();
- } finally {
- IOUtil.close(skinIS);
- IOUtil.close(jarOS);
+ private static void createJarFromDirectory(Path srcDirectory, Path
jarfile) throws IOException {
+ Map<String, String> env = new HashMap<>();
+ env.put("create", "true");
+ try (FileSystem zipfs = FileSystems.newFileSystem(URI.create("jar:" +
jarfile.toUri()), env)) {
+ deepCopy(srcDirectory, zipfs);
}
+ }
- skinIS = new ByteArrayInputStream(
- "<main
id=\"contentBox\">$bodyContent</main>".getBytes(StandardCharsets.UTF_8));
- jarOS = new JarOutputStream(new FileOutputStream(minimalSkinJar));
- try {
- jarOS.putNextEntry(new ZipEntry("META-INF/maven/site.vm"));
- IOUtil.copy(skinIS, jarOS);
- jarOS.closeEntry();
- } finally {
- IOUtil.close(skinIS);
- IOUtil.close(jarOS);
+ private static void deepCopy(Path src, FileSystem zipfs) throws
IOException {
+ try (Stream<Path> stream = Files.walk(src)) {
+ stream.forEach(source -> {
+ try {
+ // skip root
+ if (!src.equals(source)) {
+ Path relativeSrcPath = src.relativize(source);
+ if (Files.isDirectory(source)) {
+
Files.createDirectories(zipfs.getPath(relativeSrcPath.toString()));
+ } else {
+ Files.copy(
+ source,
+ zipfs.getPath(relativeSrcPath.toString()),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
}
}
@@ -219,11 +242,12 @@ public class DefaultSiteRendererTest {
SiteModel siteModel =
new SiteXpp3Reader().read(new
FileInputStream(getTestFile("src/test/resources/site/site.xml")));
- SiteRenderingContext ctxt = getSiteRenderingContext(siteModel,
"src/test/resources/site", false);
+ SiteRenderingContext ctxt =
+ getSiteRenderingContext(siteModel, minimalSkinJar,
"src/test/resources/site", false);
ctxt.setRootDirectory(getTestFile(""));
siteRenderer.render(siteRenderer.locateDocumentFiles(ctxt,
true).values(), ctxt, outputDirectory);
- ctxt = getSiteRenderingContext(siteModel,
"src/test/resources/site-validate", true);
+ ctxt = getSiteRenderingContext(siteModel, minimalSkinJar,
"src/test/resources/site-validate", true);
ctxt.setRootDirectory(getTestFile(""));
siteRenderer.render(siteRenderer.locateDocumentFiles(ctxt,
true).values(), ctxt, outputDirectory);
@@ -268,7 +292,8 @@ public class DefaultSiteRendererTest {
void mermaidWithExternalJs() throws Exception {
SiteModel siteModel = new SiteXpp3Reader()
.read(new
FileInputStream(getTestFile("src/test/resources/site-mermaid-externaljs/site.xml")));
- SiteRenderingContext context = getSiteRenderingContext(siteModel,
"src/test/resources/site", false);
+ SiteRenderingContext context =
+ getSiteRenderingContext(siteModel, minimalSkinJar,
"src/test/resources/site", false);
renderDocument(context, "src/test/resources/site/markdown",
"mermaid.md", "md", "markdown");
@@ -325,7 +350,13 @@ public class DefaultSiteRendererTest {
void velocityToolManagerForSkin() throws Exception {
StringWriter writer = new StringWriter();
- File skinFile = skinJar;
+ File skinFile = new File(getBasedir(), "target/test-classes/skin.jar");
+ try (InputStream skinIS =
getClass().getResourceAsStream("velocity-toolmanager.vm");
+ JarOutputStream jarOS = new JarOutputStream(new
FileOutputStream(skinFile))) {
+ jarOS.putNextEntry(new ZipEntry("META-INF/maven/site.vm"));
+ IOUtil.copy(skinIS, jarOS);
+ jarOS.closeEntry();
+ }
Map<String, Object> attributes = new HashMap<>();
@@ -391,9 +422,30 @@ public class DefaultSiteRendererTest {
assertEquals(expectedOutputFiles, outputFiles);
}
- private SiteRenderingContext getSiteRenderingContext(SiteModel siteModel,
String siteDir, boolean validate)
+ @Test
+ void copyResourcesConditionally() throws Exception {
+ File skinJar = new File(getBasedir(),
"target/test-classes/skin-with-conditional-resources.jar");
+ createJarFromDirectory(
+
getTestFile("src/test/resources/skin-with-conditional-resources")
+ .toPath(),
+ skinJar.toPath());
+
+ SiteModel siteModel =
+ new SiteXpp3Reader().read(new
FileInputStream(getTestFile("src/test/resources/site/site.xml")));
+ SiteRenderingContext context = getSiteRenderingContext(siteModel,
skinJar, "src/test/resources/site", false);
+ File sourceDirectory = getTestFile("src/test/resources/site-validate");
+ context.setRootDirectory(sourceDirectory);
+ Path outputDirectory = Files.createTempDirectory("site-output-");
+ siteRenderer.copyResources(context, outputDirectory.toFile());
+ assertTrue(Files.exists(outputDirectory.resolve("js/include.js")));
+ assertTrue(Files.exists(outputDirectory.resolve("js/include2.js")));
+ assertTrue(Files.exists(outputDirectory.resolve("js/include3.js")));
+ assertFalse(Files.exists(outputDirectory.resolve("js/exclude.js")));
+ }
+
+ private SiteRenderingContext getSiteRenderingContext(
+ SiteModel siteModel, File skinFile, String siteDir, boolean
validate)
throws RendererException, IOException {
- File skinFile = minimalSkinJar;
final Map<String, String> attributes = new HashMap<>();
attributes.put("outputEncoding", "UTF-8");
diff --git a/doxia-site-renderer/src/test/resources/site/site.xml
b/doxia-site-renderer/src/test/resources/site/site.xml
index b12888d..860377f 100644
--- a/doxia-site-renderer/src/test/resources/site/site.xml
+++ b/doxia-site-renderer/src/test/resources/site/site.xml
@@ -52,4 +52,9 @@ under the License.
</item>
</menu>
</body>
+ <custom>
+ <fluidoSkin>
+ <sourceLineNumbersEnabled>true</sourceLineNumbersEnabled>
+ </fluidoSkin>
+ </custom>
</site>
diff --git
a/doxia-site-renderer/src/test/resources/skin-minimal/META-INF/maven/site.vm
b/doxia-site-renderer/src/test/resources/skin-minimal/META-INF/maven/site.vm
new file mode 100644
index 0000000..c04cadf
--- /dev/null
+++ b/doxia-site-renderer/src/test/resources/skin-minimal/META-INF/maven/site.vm
@@ -0,0 +1 @@
+<main id="contentBox">$bodyContent</main>
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/site.vm
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/site.vm
new file mode 100644
index 0000000..9166b9c
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/site.vm
@@ -0,0 +1 @@
+$bodyContent
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/skin.xml
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/skin.xml
new file mode 100644
index 0000000..b4a3a39
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/META-INF/maven/skin.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<skin xmlns="http://maven.apache.org/SKIN/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/SKIN/2.1.0
http://maven.apache.org/xsd/skin-2.1.0.xsd">
+ <prerequisites>
+ <doxia-sitetools>2.2.0</doxia-sitetools>
+ </prerequisites>
+ <resource-conditions>
+ <resource-condition>
+ <resource-name>js/exclude.js</resource-name>
+ <vtl-condition>false</vtl-condition>
+ </resource-condition>
+ <resource-condition>
+ <resource-name>js/include2.js</resource-name>
+ <resource-name>js/include3.js</resource-name>
+ <vtl-condition><![CDATA[$site.getCustomValue(
'fluidoSkin.sourceLineNumbersEnabled', 'false' )]]></vtl-condition>
+ </resource-condition>
+ </resource-conditions>
+</skin>
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/exclude.js
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/exclude.js
new file mode 100644
index 0000000..73836a4
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/exclude.js
@@ -0,0 +1 @@
+// must not be copied (conditionally)
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include.js
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include.js
new file mode 100644
index 0000000..8135953
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include.js
@@ -0,0 +1 @@
+// must be copied (unconditionally)
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include2.js
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include2.js
new file mode 100644
index 0000000..22acdcb
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include2.js
@@ -0,0 +1 @@
+// must be copied (conditionally)
\ No newline at end of file
diff --git
a/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include3.js
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include3.js
new file mode 100644
index 0000000..22acdcb
--- /dev/null
+++
b/doxia-site-renderer/src/test/resources/skin-with-conditional-resources/js/include3.js
@@ -0,0 +1 @@
+// must be copied (conditionally)
\ No newline at end of file
diff --git a/doxia-skin-model/pom.xml b/doxia-skin-model/pom.xml
index c322ea0..7eaeaeb 100644
--- a/doxia-skin-model/pom.xml
+++ b/doxia-skin-model/pom.xml
@@ -49,7 +49,7 @@ under the License.
<model>src/main/mdo/skin.mdo</model>
</models>
<!-- TODO Do not forget to update the version in the description.
See DOXIASITETOOLS-98. -->
- <version>2.0.0</version>
+ <version>2.1.0</version>
<firstVersion>1.7.0</firstVersion>
</configuration>
<executions>
diff --git a/doxia-skin-model/src/main/mdo/skin.mdo
b/doxia-skin-model/src/main/mdo/skin.mdo
index 60bb8f1..941ad7e 100644
--- a/doxia-skin-model/src/main/mdo/skin.mdo
+++ b/doxia-skin-model/src/main/mdo/skin.mdo
@@ -29,7 +29,7 @@ under the License.
<p>An XSD is available at:</p>
<ul>
<!-- There is no property filtering in Modello, this has to be updated
manually. See DOXIASITETOOLS-98. -->
- <li><a
href="https://maven.apache.org/xsd/skin-2.0.0.xsd">https://maven.apache.org/xsd/skin-2.0.0.xsd</a></li>
+ <li><a
href="https://maven.apache.org/xsd/skin-2.1.0.xsd">https://maven.apache.org/xsd/skin-2.1.0.xsd</a></li>
</ul>
]]></description>
@@ -67,6 +67,16 @@ under the License.
<type>String</type>
<required>false</required>
</field>
+ <field xdoc.separator="blank" xml.tagName="resource-conditions">
+ <name>resourceConditions</name>
+ <version>2.1.0+</version>
+ <description>Resource conditions</description>
+ <association>
+ <type>ResourceCondition</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <required>false</required>
+ </field>
</fields>
<codeSegments>
<codeSegment>
@@ -97,5 +107,35 @@ under the License.
</field>
</fields>
</class>
+ <class java.clone="deep">
+ <name>ResourceCondition</name>
+ <version>2.1.0+</version>
+ <description>Describes the condition for including a specific Skin
resource. If multiple conditions are defined for a single resource only the
first matching condition determines the outcome. Resources not matching a
condition will always be included.</description>
+ <fields>
+ <field xml.tagName="resource-name">
+ <name>resourceNames</name>
+ <version>2.1.0+</version>
+ <association xml.itemsStyle="flat">
+ <type>String</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description><![CDATA[
+ A resource name to which this condition applies. Refers to the
relative path within the JAR (i.e. must always use "/" as separator and must
not start with a slash). Multiple resource names can be specified sharing the
same condition.
+ ]]>
+ </description>
+ <required>true</required>
+ </field>
+ <field xml.tagName="vtl-condition">
+ <name>vtlCondition</name>
+ <version>2.1.0+</version>
+ <type>String</type>
+ <description><![CDATA[
+ The Velocity (VTL) expression to be evaluated to decide if the
resource should be included. Only if the condition evaluates to true, the
resource will be included.
+ ]]>
+ </description>
+ <required>true</required>
+ </field>
+ </fields>
+ </class>
</classes>
</model>