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>

Reply via email to