You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/02/18 13:27:27 UTC

[jackrabbit-filevault] branch feature/JCRVLT-600-allow-undeclared-prefixes-in-docview-filenames created (now 72c8f82)

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

kwin pushed a change to branch feature/JCRVLT-600-allow-undeclared-prefixes-in-docview-filenames
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git.


      at 72c8f82  JCRVLT-600 optionally allow undeclared prefixes in docview filenames

This branch includes the following new commits:

     new 72c8f82  JCRVLT-600 optionally allow undeclared prefixes in docview filenames

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


[jackrabbit-filevault] 01/01: JCRVLT-600 optionally allow undeclared prefixes in docview filenames

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/JCRVLT-600-allow-undeclared-prefixes-in-docview-filenames
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit 72c8f822821851fe7c9f313f70d3376a0ac6449c
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Feb 18 14:27:17 2022 +0100

    JCRVLT-600 optionally allow undeclared prefixes in docview filenames
    
    add more test for namespaced file imports
---
 src/site/markdown/validation.md                    |  2 +-
 .../vault/fs/impl/io/AbstractArtifactHandler.java  |  2 +-
 .../vault/fs/impl/io/DocViewAnalyzer.java          |  4 +-
 .../vault/fs/impl/io/DocViewSAXHandler.java        | 57 ++++++--------
 .../vault/fs/impl/io/FileArtifactHandler.java      |  3 -
 .../jackrabbit/vault/fs/io/DocViewParser.java      | 44 ++++++++---
 .../jackrabbit/vault/util/DocViewProperty2.java    | 15 +++-
 ...spaceImportTest.java => NamespaceImportIT.java} | 92 ++++++++++++++--------
 .../namespace.zip/META-INF/vault/filter.xml        |  4 +
 .../namespace.zip/META-INF/vault/nodetypes.cnd     |  9 +++
 .../namespace.zip/META-INF/vault/properties.xml    | 18 +++++
 .../namespace.zip/jcr_root/.content.xml            | 17 ++++
 .../namespace.zip/jcr_root/testroot/.content.xml   |  4 +
 .../jcr_root/testroot/_cq_content.xml              | 20 +++++
 .../spi/impl/DocumentViewParserValidator.java      | 26 +++++-
 .../impl/DocumentViewParserValidatorFactory.java   | 10 ++-
 .../DocumentViewParserValidatorTest.java           | 38 +++++++--
 .../vault/validation/ValidationExecutorTest.java   |  5 ++
 .../simple-package/jcr_root/apps/_cq_content.xml   | 20 +++++
 19 files changed, 291 insertions(+), 99 deletions(-)

diff --git a/src/site/markdown/validation.md b/src/site/markdown/validation.md
index 176e987..ce37577 100644
--- a/src/site/markdown/validation.md
+++ b/src/site/markdown/validation.md
@@ -54,7 +54,7 @@ ID  |  Description | Options | Incremental Execution Limitations
 `jackrabbit-filter` |  Checks for validity of the [filter.xml](./filter.html) (according to a predefined  XML schema). In addition checks that every [docview xml node](./docview.html) is contained in the filter. It also makes sure that all filter root's ancestors are either known/valid roots or are contained in the package dependencies. For ancestor nodes which are not covered by a filter at least a `warn` is emitted. Also it makes sure that `pattern` values for includes/excludes as well [...]
 `jackrabbit-properties ` | Checks for validity of the  [properties.xml](./properties.html) | none | none
 `jackrabbit-dependencies` | Checks for overlapping filter roots of the referenced package dependencies as well as for valid package dependency references (i.e. references which can be resolved). | *severityForUnresolvedDependencies*: severity of validation messages for unresolved dependencies (default = `warn`) | none
-`jackrabbit-docviewparser` | Checks if all docview files in the package are compliant with the [(extended) Document View Format](docview.html). This involves checking for XML validity as well as checking for correct property types. | none | none
+`jackrabbit-docviewparser` | Checks if all docview files in the package are compliant with the [(extended) Document View Format](docview.html). This involves checking for XML validity as well as checking for correct property types. | *allowUndeclaredPrefixInFileName*: if set to `true` then prefixes only used in the encoded docview xml filename don't need to be declared in the XML itself, otherwise a missing declaration leads to a validation error. | none
 `jackrabbit-emptyelements` | Check for empty elements within DocView files (used for ordering purposes, compare with  [(extended) Document View Format](docview.html)) which are included in the filter with import=replace as those are actually not replaced! | none | none
 `jackrabbit-mergelimitations` | Checks for the limitation of import mode=merge outlined at [JCRVLT-255][jcrvlt-255]. | none | none
 `jackrabbit-oakindex` |  Checks if the package (potentially) modifies/creates an OakIndexDefinition. This is done by evaluating both the filter.xml for potential matches as well as the actual content for nodes with jcr:primaryType  `oak:indexDefinition`. | none | none
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
index f1f02ab..545f712 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
@@ -165,7 +165,7 @@ public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpab
                 rootNodePath += "/";
             }
             rootNodePath += rootNodeName;
-            new DocViewParser().parse(rootNodePath, source, handler, parentNode.getSession());
+            new DocViewParser(parentNode.getSession()).parse(rootNodePath, source, handler);
         } catch (XmlParseException e) {
             // wrap as repositoryException although not semantically correct for backwards compatibility
             throw new RepositoryException(e);
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
index df6f2c5..62ca89f 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
@@ -62,8 +62,8 @@ public class DocViewAnalyzer implements DocViewParserHandler {
                                InputSource source)
             throws IOException {
         try {
-        	DocViewParser docViewParser = new DocViewParser();
-        	docViewParser.parse(rootPath, source, new DocViewAnalyzer(listener), session);
+            DocViewParser docViewParser = new DocViewParser(session);
+            docViewParser.parse(rootPath, source, new DocViewAnalyzer(listener));
         } catch (XmlParseException e) {
             throw new IllegalStateException(e);
         }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java
index e192a25..07f29c3 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java
@@ -29,12 +29,12 @@ import java.util.Optional;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
 
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.NameFactory;
-import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
+import org.apache.jackrabbit.spi.commons.conversion.ParsingNameResolver;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
@@ -137,15 +137,15 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
     private final NamespaceSupport nsSupport;
 
     /**
-     * the default name path resolver
+     * the name path resolver to use for the filename (outside the docview), only relevant to resolve jcr:root element
      */
-    private final DefaultNamePathResolver npResolver = new DefaultNamePathResolver(this);
+    private final NameResolver nameResolver;
 
     /**
-     * Optional JCR session used for namespace lookup if not declared in XML
+     * Optional additional namespace resolver used for namespace lookup if not declared in XML
      */
-    private final @Nullable Session session;
-    
+    private final @Nullable NamespaceResolver nsResolver;
+
     private final DocViewParserHandler handler;
     private final String rootNodePath;
 
@@ -155,7 +155,7 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
     
     private Locator locator;
     
-    public DocViewSAXHandler(@NotNull DocViewParserHandler handler, @NotNull String rootNodePath, @Nullable Session session) {
+    public DocViewSAXHandler(@NotNull DocViewParserHandler handler, @NotNull String rootNodePath, @Nullable NamespaceResolver nsResolver) {
         super();
         Objects.requireNonNull(handler, "handler must not be null");
         this.handler = handler;
@@ -169,7 +169,8 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
         nodeStack = new LinkedList<>();
         currentPath = null;
         locator = new LocatorImpl();
-        this.session = session;
+        this.nsResolver = nsResolver;
+        this.nameResolver = new ParsingNameResolver(NameFactoryImpl.getInstance(), this);
     }
 
     /**
@@ -256,6 +257,9 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
         return new SimpleEntry<>(name, index);
     }
 
+    /**
+     * This considers both namespaces declared in the XML as well as namespaces from the underlying namespace resolver.
+     */
     @Override
     public String getURI(String prefix) throws NamespaceException {
         if (prefix.equals(Name.NS_EMPTY_PREFIX)) {
@@ -263,32 +267,23 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
         }
         String uri = nsSupport.getURI(prefix);
         if (uri == null) {
-            if (session != null) {
-                try {
-                    return session.getNamespaceURI(prefix);
-                } catch (NamespaceException e) {
-                    throw e;
-                } catch (RepositoryException e) {
-                    throw new NamespaceException("Unknown prefix " + prefix, e);
-                }
+            if (nsResolver != null) {
+                return nsResolver.getURI(prefix);
             }
             throw new NamespaceException("Unknown prefix " + prefix);
         }
         return uri;
     }
 
+    /**
+     * This considers both namespaces declared in the XML as well as namespaces from the underlying namespace resolver.
+     */
     @Override
     public String getPrefix(String uri) throws NamespaceException {
         String prefix = nsSupport.getPrefix(uri);
         if (prefix == null) {
-            if (session != null) {
-                try {
-                    return session.getNamespacePrefix(uri);
-                } catch (NamespaceException e) {
-                    throw e;
-                } catch (RepositoryException e) {
-                    throw new NamespaceException("Unmapped URL " + prefix, e);
-                }
+            if (nsResolver != null) {
+                return nsResolver.getPrefix(uri);
             }
             throw new NamespaceException("Unmapped URL " + uri);
         }
@@ -312,7 +307,7 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
                 Map.Entry<String, Integer> nameAndIndex = getNameAndIndex(Text.getName(rootNodePath));
                 index = nameAndIndex.getValue();
                 try {
-                    name = npResolver.getQName(nameAndIndex.getKey());
+                    name = nameResolver.getQName(nameAndIndex.getKey());
                 } catch (NamespaceException e) {
                     throw new SAXException("Unknown namespace prefix used in file name '" + nameAndIndex.getKey() + "'", e);
                 } catch (IllegalNameException e) {
@@ -329,9 +324,7 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
                     // root node element name should take precedence of root node name derived from path
                     currentPath = Text.getRelativeParent(rootNodePath, 1);
                 }
-                currentPath = PathUtil.append(currentPath, npResolver.getJCRName(name));
-            } catch (NamespaceException e) {
-                throw new SAXException("No prefix defined for namespace uri '" + uri + "' used in node name '" + nameAndIndex.getKey() + "'", e);
+                currentPath = PathUtil.append(currentPath, ISO9075.decode(qName));
             } catch (IllegalArgumentException e) {
                 throw new SAXException("Invalid name format used in node name '" + nameAndIndex.getKey() + "'", e);
             }
@@ -347,11 +340,9 @@ public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements
                         attributes.getURI(i),
                         ISO9075.decode(attributes.getLocalName(i)));
                 DocViewProperty2 property = DocViewProperty2.parse(
-                        pName.toString(),
-                        attributes.getValue(i),
-                        npResolver);
+                        pName,
+                        attributes.getValue(i));
                 props.add(property);
-                
             }
             DocViewNode2 ni = new DocViewNode2(name, index, props);
             handler.startDocViewNode(currentPath, ni, Optional.ofNullable(nodeStack.peek()), locator.getLineNumber(), locator.getColumnNumber());
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
index 9d14429..3e9ce06 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
@@ -28,8 +28,6 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.nodetype.NodeType;
-import javax.xml.parsers.ParserConfigurationException;
-
 import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.vault.fs.api.Artifact;
 import org.apache.jackrabbit.vault.fs.api.ArtifactType;
@@ -46,7 +44,6 @@ import org.apache.jackrabbit.vault.util.MimeTypes;
 import org.apache.jackrabbit.vault.util.PathUtil;
 import org.jetbrains.annotations.NotNull;
 import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 
 /**
  * Creates nt:file structures from  {@link SerializationType#XML_GENERIC} or
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
index 2a724c9..d8f1074 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
@@ -19,7 +19,6 @@ package org.apache.jackrabbit.vault.fs.io;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
@@ -29,24 +28,44 @@ import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.jackrabbit.vault.fs.api.SerializationType;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.apache.jackrabbit.spi.commons.namespace.SessionNamespaceResolver;
 import org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXHandler;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.xml.sax.InputSource;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
 
 /**
- * This is a thread-safe sax parser which deals with docview files and passes them to a given {@link DocViewParserHandler}.
+ * This is a thread-safe SAX parser which deals with docview files and passes them to a given {@link DocViewParserHandler}.
  * 
  */
 public class DocViewParser {
-	
-	/** 
-	 * Thrown in case the XML is not <a href="https://www.w3.org/TR/REC-xml/#sec-well-formed">well-formed</a>
-	 * or no valid docview format.
-	 */
+
+    private final @Nullable NamespaceResolver resolver;
+
+    public DocViewParser() {
+        this((NamespaceResolver)null);
+    }
+
+    /**
+     * 
+     * @param session uses the namespace from the session for resolving otherwise unknown namespace prefixes in docview files
+     */
+    public DocViewParser(@NotNull Session session) {
+        this(new SessionNamespaceResolver(session));
+    }
+
+    public DocViewParser(@Nullable NamespaceResolver resolver) {
+        this.resolver = resolver;
+    }
+
+    /**
+     * Thrown in case the XML is not
+     * <a href="https://www.w3.org/TR/REC-xml/#sec-well-formed">well-formed</a> or
+     * no valid docview format.
+     */
     public static final class XmlParseException extends Exception {
 
         /**
@@ -134,7 +153,7 @@ public class DocViewParser {
         // check for docview
         return str.contains("<jcr:root") && str.contains("\"http://www.jcp.org/jcr/1.0\"");
     }
-    
+
     private SAXParser createSaxParser() throws ParserConfigurationException, SAXException {
         SAXParserFactory factory = SAXParserFactory.newInstance();
         factory.setNamespaceAware(true);
@@ -150,18 +169,17 @@ public class DocViewParser {
      * @param rootNodePath the path of the root node of the given docview xml
      * @param inputSource the source of the docview xml
      * @param handler the callback handler which gets the deserialized node information
-     * @param session optional session used for namespace resolution
      * @throws IOException 
      * @throws XmlParseException 
      */
-    public void parse(String rootNodePath, InputSource inputSource, DocViewParserHandler handler, @Nullable Session session) throws IOException, XmlParseException {
+    public void parse(String rootNodePath, InputSource inputSource, DocViewParserHandler handler) throws IOException, XmlParseException {
         final SAXParser parser;
         try {
             parser = createSaxParser();
         } catch (ParserConfigurationException|SAXException e) {
             throw new IllegalStateException("Could not create SAX parser" + e.getMessage(), e);
         }
-        DocViewSAXHandler docViewSaxHandler = new DocViewSAXHandler(handler, rootNodePath, session);
+        DocViewSAXHandler docViewSaxHandler = new DocViewSAXHandler(handler, rootNodePath, resolver);
         try {
             parser.parse(inputSource, docViewSaxHandler);
         } catch (SAXException|IllegalArgumentException e) {
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
index faaceba..8779993 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
@@ -261,6 +261,19 @@ public class DocViewProperty2 {
      * @throws IllegalNameException 
      */
     public static @NotNull DocViewProperty2 parse(String name, String value, NameResolver nameResolver) throws IllegalNameException, NamespaceException {
+        return parse(nameResolver.getQName(name), value);
+    }
+
+    /**
+     * Parses a enhanced docview property string and returns the property.
+     * @param name name of the property
+     * @param value (attribute) value
+     * @throws IllegalArgumentException in case the given value does not follow the doc view property grammar
+     * @return a property
+     * @throws NamespaceException 
+     * @throws IllegalNameException 
+     */
+    public static @NotNull DocViewProperty2 parse(Name name, String value) throws IllegalNameException, NamespaceException {
         boolean isMulti = false;
         boolean isBinaryRef = false;
         int type = PropertyType.UNDEFINED;
@@ -371,7 +384,7 @@ public class DocViewProperty2 {
         } else {
             vals = Collections.singletonList(tmp.toString());
         }
-        return new DocViewProperty2(nameResolver.getQName(name), vals, isMulti, type, isBinaryRef);
+        return new DocViewProperty2(name, vals, isMulti, type, isBinaryRef);
     }
     /**
      * Formats (serializes) the given JCR property value according to the enhanced docview syntax.
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportTest.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportIT.java
similarity index 63%
rename from vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportTest.java
rename to vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportIT.java
index c247c66..2225b47 100644
--- a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportTest.java
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NamespaceImportIT.java
@@ -16,16 +16,23 @@
  */
 package org.apache.jackrabbit.vault.packaging.integration;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Properties;
 
+import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
 import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 
+import org.apache.jackrabbit.api.JackrabbitRepository;
 import org.apache.jackrabbit.oak.jcr.Jcr;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
@@ -36,16 +43,14 @@ import org.apache.jackrabbit.vault.packaging.ExportOptions;
 import org.apache.jackrabbit.vault.packaging.PackageException;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.jackrabbit.vault.packaging.impl.JcrPackageManagerImpl;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
 /**
- * Is rather an IT but not relying on {@link IntegrationTestBase}
+ * Tests namespace aware node/property imports
  */
-public class NamespaceImportTest {
+public class NamespaceImportIT extends IntegrationTestBase {
 
     private final static String PREFIX = "prefix";
 
@@ -53,27 +58,41 @@ public class NamespaceImportTest {
 
     private final static String URI2 = "http://two.namespace.io";
 
-    private Instance i1;
-
-    private Instance i2;
+    private Instance sourceOakRepository;
 
     @Before
-    public void setup() throws RepositoryException {
-        i1 = new Instance();
-        i2 = new Instance();
+    public void setUp() throws Exception {
+        sourceOakRepository = new Instance(); // source instance
 
         // Register namespaces with same prefix but different URIs
-        // on different instances, i1, i2
-        i1.registerNamespace(PREFIX, URI1);
-        i2.registerNamespace(PREFIX, URI2);
+        // on different instances
+        sourceOakRepository.registerNamespace(PREFIX, URI1);
+        super.setUp();
+        NamespaceRegistry nsRegistry = admin.getWorkspace().getNamespaceRegistry();
+        try {
+            if (URI1.equals(nsRegistry.getURI(PREFIX))) {
+                throw new IllegalStateException("prefix already registered for a different uri");
+            }
+        } catch (NamespaceException e) {
+            nsRegistry.registerNamespace(PREFIX, URI2);
+        }
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        sourceOakRepository.admin.logout();
+        if (sourceOakRepository.repository instanceof JackrabbitRepository) {
+            JackrabbitRepository.class.cast(sourceOakRepository.repository).shutdown();
+        }
+        super.tearDown();
     }
 
     @Test
     public void importClashingNamespace() throws RepositoryException, IOException, PackageException {
 
         // Set a property with the namespace prefix on instance i1
-        i1.getRootNode().addNode("tmp").setProperty("{" + URI1 + "}prop1", "value1");
-        i1.admin.save();
+        sourceOakRepository.getRootNode().addNode("tmp").setProperty("{" + URI1 + "}prop1", "value1");
+        sourceOakRepository.admin.save();
 
         // Export the property from instance i1 in a content package archive
 
@@ -89,16 +108,15 @@ public class NamespaceImportTest {
         opts.setMetaInf(inf);
 
         File tmpFile = File.createTempFile("vaulttest", "zip");
-        try (VaultPackage pkg = i1.packMgr.assemble(i1.admin, opts, tmpFile)) {
+        try (VaultPackage pkg = sourceOakRepository.packMgr.assemble(sourceOakRepository.admin, opts, tmpFile)) {
             Archive archive = pkg.getArchive();
 
-            // Import the archive in the instance i2, with strict mode enabled
-
+            // Import the archive in the target repo, with strict mode enabled
             ImportOptions io = new ImportOptions();
             io.setStrict(true);
-            i2.packMgr.extract(archive, io, true);
+            packMgr.extract(archive, io, true);
 
-            assertEquals(i2.getRootNode().getNode("tmp").getProperty("{" + URI1 + "}prop1").getString(), "value1");
+            assertEquals(admin.getRootNode().getNode("tmp").getProperty("{" + URI1 + "}prop1").getString(), "value1");
         } finally {
             tmpFile.delete();
         }
@@ -108,8 +126,8 @@ public class NamespaceImportTest {
     public void importClashingNamespaceOnPath() throws RepositoryException, IOException, PackageException {
 
         // Set a property with the namespace prefix on instance i1
-        i1.getRootNode().addNode("tmp").addNode("{" + URI1 + "}node1").setProperty("test", "value1");
-        i1.admin.save();
+        sourceOakRepository.getRootNode().addNode("tmp").addNode("{" + URI1 + "}node1").setProperty("test", "value1");
+        sourceOakRepository.admin.save();
 
         // Export the property from instance i1 in a content package archive
 
@@ -125,24 +143,33 @@ public class NamespaceImportTest {
         opts.setMetaInf(inf);
 
         File tmpFile = File.createTempFile("vaulttest", "zip");
-        try (VaultPackage pkg = i1.packMgr.assemble(i1.admin, opts, tmpFile)) {
+        try (VaultPackage pkg = sourceOakRepository.packMgr.assemble(sourceOakRepository.admin, opts, tmpFile)) {
             Archive archive = pkg.getArchive();
 
-            // Import the archive in the instance i2, with strict mode enabled
-
+            // Import the archive in another instance with strict mode enabled
             ImportOptions io = new ImportOptions();
             io.setStrict(true);
-            i2.packMgr.extract(archive, io, true);
+            packMgr.extract(archive, io, true);
 
-            assertEquals(i2.getRootNode().getProperty("tmp/{" + URI1 + "}node1/test").getString(), "value1");
+            assertEquals(admin.getRootNode().getProperty("tmp/{" + URI1 + "}node1/test").getString(), "value1");
 
-            i2.relogin();
-            assertNotEquals(PREFIX, i2.admin.getNamespacePrefix(URI1));
+            Session admin2 = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+            assertNotEquals(PREFIX, admin2.getNamespacePrefix(URI1));
+            admin2.logout();
         } finally {
             tmpFile.delete();
         }
     }
 
+    @Test
+    public void importUndeclaredNamespaceOnDocViewPath() throws IOException, PackageException, RepositoryException {
+        // namespace declared in package but not in affected docview file
+        try (VaultPackage pkg = extractVaultPackageStrict("/test-packages/namespace.zip")) {
+            assertNotNull(pkg);
+        }
+    }
+
+    /** Simple Oak repository wrapper */
     private static final class Instance {
 
         final Repository repository;
@@ -168,11 +195,6 @@ public class NamespaceImportTest {
             admin.getWorkspace().getNamespaceRegistry().registerNamespace(prefix, uri);
         }
 
-        void relogin() throws RepositoryException {
-            admin.logout();
-            admin = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
-
-        }
     }
 
 }
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/filter.xml b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/filter.xml
new file mode 100644
index 0000000..bbbd616
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/filter.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workspaceFilter version="1.0">
+    <filter root="/testroot"/>
+</workspaceFilter>
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/nodetypes.cnd b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/nodetypes.cnd
new file mode 100644
index 0000000..3771ba5
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/nodetypes.cnd
@@ -0,0 +1,9 @@
+<'sling'='http://sling.apache.org/jcr/sling/1.0'>
+<'nt'='http://www.jcp.org/jcr/nt/1.0'>
+<'cq'='http://www.day.com/jcr/cq/1.0'>
+
+[sling:Folder] > nt:folder
+  - * (undefined)
+  - * (undefined) multiple
+  + * (nt:base) = sling:Folder version
+
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/properties.xml b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/properties.xml
new file mode 100644
index 0000000..c606e19
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/META-INF/vault/properties.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+<comment>FileVault Package Properties</comment>
+<entry key="createdBy">admin</entry>
+<entry key="name">import-modes-test</entry>
+<entry key="lastModified">2011-11-15T09:45:14.664+01:00</entry>
+<entry key="lastModifiedBy">admin</entry>
+<entry key="created">2011-11-15T09:45:14.685+01:00</entry>
+<entry key="buildCount">1</entry>
+<entry key="version"/>
+<entry key="dependencies"/>
+<entry key="packageFormatVersion">2</entry>
+<entry key="description"/>
+<entry key="lastWrapped">2011-11-15T09:45:14.664+01:00</entry>
+<entry key="group"/>
+<entry key="lastWrappedBy">admin</entry>
+</properties>
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/.content.xml b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/.content.xml
new file mode 100644
index 0000000..e546f29
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/.content.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+    jcr:mixinTypes="[rep:AccessControllable]"
+    jcr:primaryType="rep:root"
+    sling:resourceType="sling:redirect"
+    sling:target="/index.html">
+    <rep:policy/>
+    <jcr:system/>
+    <var/>
+    <libs/>
+    <etc/>
+    <apps/>
+    <content/>
+    <tmp/>
+    <home/>
+    <testroot/>
+</jcr:root>
\ No newline at end of file
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/.content.xml b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/.content.xml
new file mode 100644
index 0000000..c5cf582
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/.content.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:my="http://jackrabbit.apache.org/filevault/testing"
+    jcr:primaryType="sling:Folder">
+</jcr:root>
diff --git a/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/_cq_content.xml b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/_cq_content.xml
new file mode 100644
index 0000000..531bf71
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/namespace.zip/jcr_root/testroot/_cq_content.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
+    jcr:primaryType="nt:unstructured">
+</jcr:root>
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java
index 9a0fa92..7b66d33 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java
@@ -29,7 +29,10 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import javax.jcr.NamespaceException;
+
 import org.apache.commons.io.input.CloseShieldInputStream;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
 import org.apache.jackrabbit.vault.fs.io.DocViewParser;
 import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException;
 import org.apache.jackrabbit.vault.util.Constants;
@@ -51,10 +54,25 @@ public class DocumentViewParserValidator implements GenericJcrDataValidator {
     private final DocViewParser docViewParser;
     private final @NotNull ValidationMessageSeverity severity;
     
-    public DocumentViewParserValidator(@NotNull ValidationMessageSeverity severity) {
+    public DocumentViewParserValidator(@NotNull ValidationMessageSeverity severity, boolean allowUndeclaredPrefixInFileName) {
         super();
         this.docViewValidators = new HashMap<>();
-        this.docViewParser = new DocViewParser();
+        if (allowUndeclaredPrefixInFileName) {
+            NamespaceResolver nsResolver = new NamespaceResolver() {
+
+                @Override
+                public String getURI(String prefix) throws NamespaceException {
+                    return "http://undeclared.uri";
+                }
+                @Override
+                public String getPrefix(String uri) throws NamespaceException {
+                    return "undeclared prefix";
+                }
+            };
+            this.docViewParser = new DocViewParser(nsResolver);
+        } else {
+            this.docViewParser = new DocViewParser();
+        }
         this.severity = severity;
     }
 
@@ -146,10 +164,10 @@ public class DocumentViewParserValidator implements GenericJcrDataValidator {
         enrichedMessages.add(new ValidationMessage(ValidationMessageSeverity.DEBUG, "Detected DocView..."));
         ValidatorDocViewParserHandler handler = new ValidatorDocViewParserHandler(docViewValidators, filePath, basePath);
         try {
-            docViewParser.parse(rootNodePath, new InputSource(new CloseShieldInputStream(input)), handler, null);
+            docViewParser.parse(rootNodePath, new InputSource(new CloseShieldInputStream(input)), handler);
             enrichedMessages.addAll(ValidationViolation.wrapMessages(null, handler.getViolations(), filePath, basePath, rootNodePath, 0, 0));
         } catch (XmlParseException e) {
-            enrichedMessages.add(new ValidationViolation(severity, "Could not parse FileVault Document View XML: " + e.getMessage(), filePath, basePath, e.getNodePath(), e.getLineNumber(), e.getColumnNumber(), e));
+            enrichedMessages.add(new ValidationViolation(DocumentViewParserValidatorFactory.ID, severity, "Could not parse FileVault Document View XML: " + e.getMessage(), filePath, basePath, e.getNodePath(), e.getLineNumber(), e.getColumnNumber(), e));
         }
         nodePathsAndLineNumbers.putAll(handler.getNodePaths());
         return enrichedMessages;
diff --git a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidatorFactory.java b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidatorFactory.java
index dbce9b0..6006805 100644
--- a/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidatorFactory.java
+++ b/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidatorFactory.java
@@ -28,9 +28,17 @@ public class DocumentViewParserValidatorFactory implements ValidatorFactory {
 
     public static final String ID = ValidatorFactory.ID_PREFIX_JACKRABBIT + "docviewparser";
 
+    public static final String OPTION_ALLOW_UNDECLARED_PREFIX_IN_FILE_NAME = "allowUndeclaredPrefixInFileName";
+
     @Override
     public Validator createValidator(@NotNull ValidationContext context, @NotNull ValidatorSettings settings) {
-        return new DocumentViewParserValidator(settings.getDefaultSeverity());
+        final boolean allowUndeclaredPrefixInFileName;
+        if (settings.getOptions().containsKey(OPTION_ALLOW_UNDECLARED_PREFIX_IN_FILE_NAME)) {
+            allowUndeclaredPrefixInFileName = Boolean.valueOf(settings.getOptions().get(OPTION_ALLOW_UNDECLARED_PREFIX_IN_FILE_NAME));
+        } else {
+            allowUndeclaredPrefixInFileName = false;
+        }
+        return new DocumentViewParserValidator(settings.getDefaultSeverity(), allowUndeclaredPrefixInFileName);
     }
 
     @Override
diff --git a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/DocumentViewParserValidatorTest.java b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/DocumentViewParserValidatorTest.java
index c8113c0..02e5939 100644
--- a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/DocumentViewParserValidatorTest.java
+++ b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/DocumentViewParserValidatorTest.java
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.vault.validation;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -34,6 +35,7 @@ import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.NameFactory;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.vault.fs.io.DocViewParser;
 import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException;
 import org.apache.jackrabbit.vault.util.DocViewNode2;
 import org.apache.jackrabbit.vault.util.DocViewProperty2;
@@ -42,6 +44,7 @@ import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessage;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
 import org.apache.jackrabbit.vault.validation.spi.impl.DocumentViewParserValidator;
+import org.apache.jackrabbit.vault.validation.spi.impl.DocumentViewParserValidatorFactory;
 import org.apache.jackrabbit.vault.validation.spi.util.NodeContextImpl;
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.jcr.resource.JcrResourceConstants;
@@ -69,7 +72,7 @@ public class DocumentViewParserValidatorTest {
 
     @Before
     public void setUp() throws ParserConfigurationException, SAXException, IOException {
-        validator = new DocumentViewParserValidator(ValidationMessageSeverity.ERROR);
+        validator = new DocumentViewParserValidator(ValidationMessageSeverity.ERROR, false);
         nodePathsAndLineNumbers = new HashMap<>();
         validator.setDocumentViewXmlValidators(Collections.singletonMap("docviewid", docViewXmlValidator));
     }
@@ -154,7 +157,31 @@ public class DocumentViewParserValidatorTest {
             Mockito.verify(docViewXmlValidator).validate(node, new NodeContextImpl("/", Paths.get(".content.xml"), Paths.get("")), true);
         }
     }
-    
+
+    @Test
+    public void testDocViewWithNamespacedFilename()
+            throws ParserConfigurationException, SAXException, URISyntaxException, IOException, NamespaceException {
+        Path filePath = Paths.get("apps", "_cq_content.xml");
+        String nodePath = "/apps/cq:content";
+        String message = "Unknown namespace prefix used in file name 'cq:content'";
+        // fail during parsing due to unknown namespace in filename 
+        try (InputStream input = this.getClass().getResourceAsStream("/simple-package/jcr_root/apps/_cq_content.xml")) {
+            Collection<ValidationMessage> messages = validator.validateJcrData(input, filePath, Paths.get(""), nodePathsAndLineNumbers);
+            ValidationExecutorTest.assertViolation(messages,
+                    new ValidationViolation(DocumentViewParserValidatorFactory.ID, ValidationMessageSeverity.ERROR, 
+                            "Could not parse FileVault Document View XML: " + message,
+                            filePath, Paths.get(""), nodePath, 19, 36, new DocViewParser.XmlParseException(message, nodePath, 19, 36)
+            ));
+        }
+        validator = new DocumentViewParserValidator(ValidationMessageSeverity.ERROR, true);
+        Mockito.when(docViewXmlValidator.validate(Mockito.any(DocViewNode2.class), Mockito.any(), Mockito.anyBoolean())).thenReturn(Collections.singleton(new ValidationMessage(ValidationMessageSeverity.ERROR, "startDocView")));
+        try (InputStream input = this.getClass().getResourceAsStream("/simple-package/jcr_root/apps/_cq_content.xml")) {
+            Collection<ValidationMessage> messages = validator.validateJcrData(input, filePath, Paths.get(""), nodePathsAndLineNumbers);
+            // filter
+            MatcherAssert.assertThat(messages, AnyValidationViolationMessageMatcher.noValidationViolationMessageInCollection());
+        }
+    }
+
     @Test
     public void testDocViewWithEmptyElements() throws IOException {
         try (InputStream input = this.getClass().getResourceAsStream("/simple-package/jcr_root/apps/emptyelements/.content.xml")) {
@@ -205,7 +232,7 @@ public class DocumentViewParserValidatorTest {
             Collection<ValidationMessage> messages = validator.validateJcrData(input, Paths.get("apps", "_cq_child1.xml"), Paths.get(""), nodePathsAndLineNumbers);
            
             ValidationExecutorTest.assertViolation(messages, 
-                    new ValidationViolation(ValidationMessageSeverity.ERROR, 
+                    new ValidationViolation(DocumentViewParserValidatorFactory.ID, ValidationMessageSeverity.ERROR, 
                     "Could not parse FileVault Document View XML: Unknown namespace prefix used in file name 'cq:child1'",
                     Paths.get("apps", "_cq_child1.xml"), Paths.get(""), "/apps/cq:child1", 20, 36, 
                     new XmlParseException("Unknown namespace prefix used in file name 'cq:child1'", "/apps/cq:child1", 20, 36)));
@@ -261,8 +288,9 @@ public class DocumentViewParserValidatorTest {
             Collection<ValidationMessage> messages = validator.validateJcrData(input, Paths.get("apps", "invalid","wrongtype.xml"), Paths.get(""), nodePathsAndLineNumbers);
 
            ValidationExecutorTest.assertViolation(messages,
-                    new ValidationViolation(ValidationMessageSeverity.ERROR,
-                    		"Could not parse FileVault Document View XML: unknown type: Invalid", Paths.get("apps/invalid/wrongtype.xml"), Paths.get(""), "/apps/invalid/wrongtype/somepath", 24, 6,
+                    new ValidationViolation(DocumentViewParserValidatorFactory.ID,
+                            ValidationMessageSeverity.ERROR,
+                            "Could not parse FileVault Document View XML: unknown type: Invalid", Paths.get("apps/invalid/wrongtype.xml"), Paths.get(""), "/apps/invalid/wrongtype/somepath", 24, 6,
                             new XmlParseException(new IllegalArgumentException("unknown type: Invalid"), "/apps/invalid/wrongtype/somepath", 24, 6)));
         }
     }
diff --git a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationExecutorTest.java b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationExecutorTest.java
index 02b5296..9e71119 100644
--- a/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationExecutorTest.java
+++ b/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationExecutorTest.java
@@ -295,6 +295,11 @@ public class ValidationExecutorTest {
         }
     }
 
+    /** 
+     * Assert that all messages (after ones with level < WARN are filtered out) are equal to the given violations
+     * @param messages the actual messages (to be filtered)
+     * @param violations the expected violations (in the right order)
+     */
     public static void assertViolation(Collection<? extends ValidationMessage> messages, ValidationMessage... violations) {
         ValidationExecutorTest.assertViolation(messages, ValidationMessageSeverity.WARN, violations);
     }
diff --git a/vault-validation/src/test/resources/simple-package/jcr_root/apps/_cq_content.xml b/vault-validation/src/test/resources/simple-package/jcr_root/apps/_cq_content.xml
new file mode 100644
index 0000000..fff1fdb
--- /dev/null
+++ b/vault-validation/src/test/resources/simple-package/jcr_root/apps/_cq_content.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
+    jcr:primaryType="sling:Folder">
+</jcr:root>