You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2021/08/24 21:41:21 UTC

[sling-org-apache-sling-testing-sling-mock] 01/01: SLING-5922 add ContentLoader.folderJson and ContentLoader.folderXmlJcr methods to mount content folders using fsresource

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

sseifert pushed a commit to branch feature/SLING-5922-load-folder
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 008ac166035cced99dc52340798e3ffe302ed681
Author: Stefan Seifert <st...@users.noreply.github.com>
AuthorDate: Tue Aug 24 23:35:36 2021 +0200

    SLING-5922 add ContentLoader.folderJson and ContentLoader.folderXmlJcr methods to mount content folders using fsresource
---
 core/pom.xml                                       |  18 +-
 .../testing/mock/sling/loader/ContentLoader.java   | 103 ++++++++++-
 .../testing/mock/sling/loader/package-info.java    |   2 +-
 .../loader/ContentLoaderFolderJsonTest.java}       |  18 +-
 .../loader/ContentLoaderFolderXmlJcrTest.java}     |  18 +-
 .../loader/AbstractContentLoaderBinaryTest.java    |  13 +-
 .../AbstractContentLoaderFolderJsonTest.java       |  90 ++++++++++
 .../AbstractContentLoaderFolderXmlJcrTest.java     |  81 +++++++++
 .../json-import-samples/binary/sample-image.gif    | Bin 0 -> 62 bytes
 .../resources/xml-jcr-import-samples/.content.xml  |  24 +++
 .../xml-jcr-import-samples/content/.content.xml    |  28 +++
 .../content/dam/.content.xml                       |  24 +++
 .../content/dam/talk.png/.content.xml              |  44 +++++
 .../dam/talk.png/_jcr_content/renditions/original  | Bin 0 -> 8668 bytes
 .../renditions/original.dir/.content.xml           |  25 +++
 .../_jcr_content/renditions/web.1280.1280.png      | Bin 0 -> 5252 bytes
 .../content/samples/.content.xml                   |  23 +++
 .../content/samples/en/.content.xml                | 195 +++++++++++++++++++++
 parent/pom.xml                                     |  31 ++++
 19 files changed, 716 insertions(+), 21 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index fd2e111..7226a24 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -195,19 +195,31 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.contentparser.api</artifactId>
-            <version>2.0.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.contentparser.json</artifactId>
-            <version>2.0.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.xml-jcr</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit.vault</groupId>
+            <artifactId>org.apache.jackrabbit.vault</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.fsresource</artifactId>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>commons-beanutils</groupId>
             <artifactId>commons-beanutils</artifactId>
-            <version>1.8.3</version>
             <scope>compile</scope>
         </dependency>
 
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java b/core/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java
index d0f0c6a..e8a107f 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java
@@ -18,8 +18,10 @@
  */
 package org.apache.sling.testing.mock.sling.loader;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Dictionary;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
@@ -39,6 +41,10 @@ import org.apache.sling.contentparser.api.ParserOptions;
 import org.apache.sling.contentparser.json.JSONParserFeature;
 import org.apache.sling.contentparser.json.JSONParserOptions;
 import org.apache.sling.contentparser.json.internal.JSONContentParser;
+import org.apache.sling.fsprovider.internal.FsResourceProvider;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.apache.sling.testing.mock.osgi.MapUtil;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.builder.ImmutableValueMap;
 import org.jetbrains.annotations.NotNull;
@@ -510,7 +516,7 @@ public final class ContentLoader {
             if (bundleContext != null && StringUtils.isNotEmpty(fileExtension)) {
                 ServiceReference<MimeTypeService> ref = bundleContext.getServiceReference(MimeTypeService.class);
                 if (ref != null) {
-                    MimeTypeService mimeTypeService = (MimeTypeService)bundleContext.getService(ref);
+                    MimeTypeService mimeTypeService = bundleContext.getService(ref);
                     mimeType = mimeTypeService.getMimeType(fileExtension);
                     break;
                 }
@@ -519,4 +525,99 @@ public final class ContentLoader {
         return StringUtils.defaultString(mimeType, CONTENTTYPE_OCTET_STREAM);
     }
 
+    /**
+     * Mount a folder containing Content in JSON (Sling-Inital-Content) format in repository.
+     * @param mountFolderPath Root folder path to mount
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to mount folder into
+     */
+    public void folderJson(@NotNull String mountFolderPath, @NotNull Resource parentResource, @NotNull String childName) {
+        folderJson(new File(mountFolderPath), parentResource, childName);
+    }
+
+    /**
+     * Mount a folder containing Content in JSON (Sling-Inital-Content) format in repository.
+     * @param mountFolder Root folder path to mount
+     * @param destPath Path to mount folder into
+     */
+    public void folderJson(@NotNull String mountFolderPath, @NotNull String destPath) {
+        folderJson(new File(mountFolderPath), destPath);
+    }
+
+    /**
+     * Mount a folder containing Content in JSON (Sling-Inital-Content) format in repository.
+     * @param mountFolderPath Root folder to mount
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to mount folder into
+     */
+    public void folderJson(@NotNull File mountFolder, @NotNull Resource parentResource, @NotNull String childName) {
+        folderJson(mountFolder, parentResource.getPath() + "/" + childName);
+    }
+
+    /**
+     * Mount a folder containing Content in JSON (Sling-Inital-Content) format in repository.
+     * @param mountFolder Root folder to mount
+     * @param destPath Path to mount folder into
+     */
+    @SuppressWarnings("null")
+    public void folderJson(@NotNull File mountFolder, @NotNull String destPath) {
+        if (bundleContext == null) {
+            throw new IllegalArgumentException("No bundle context given for content loader.");
+        }
+        Dictionary<String, Object> serviceProperties = MapUtil.toDictionary(
+                "provider.file", mountFolder.getAbsolutePath(),
+                "provider.root", destPath,
+                "provider.fs.mode", "INITIAL_CONTENT",
+                "provider.initial.content.import.options", "overwrite:=true;ignoreImportProviders:=\"xml\"");
+        FsResourceProvider service = MockOsgi.activateInjectServices(FsResourceProvider.class, bundleContext, serviceProperties);
+        bundleContext.registerService(ResourceProvider.class, service, serviceProperties);
+    }
+
+    /**
+     * Mount a folder containing Content in FileVault XML format in repository.
+     * @param mountFolderPath Root folder path to mount. Path needs to point to the root folder of the content package structure.
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to mount folder into
+     */
+    public void folderXmlJcr(@NotNull String mountFolderPath, @NotNull Resource parentResource, @NotNull String childName) {
+        folderXmlJcr(new File(mountFolderPath), parentResource, childName);
+    }
+
+    /**
+     * Mount a folder containing Content in FileVault XML format in repository.
+     * @param mountFolder Root folder path to mount. Path needs to point to the root folder of the content package structure.
+     * @param destPath Path to mount folder into
+     */
+    public void folderXmlJcr(@NotNull String mountFolderPath, @NotNull String destPath) {
+        folderXmlJcr(new File(mountFolderPath), destPath);
+    }
+
+    /**
+     * Mount a folder containing Content in FileVault XML format in repository.
+     * @param mountFolderPath Root folder to mount. Path needs to point to the root folder of the content package structure.
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to mount folder into
+     */
+    public void folderXmlJcr(@NotNull File mountFolder, @NotNull Resource parentResource, @NotNull String childName) {
+        folderXmlJcr(mountFolder, parentResource.getPath() + "/" + childName);
+    }
+
+    /**
+     * Mount a folder containing Content in FileVault XML format in repository.
+     * @param mountFolder Root folder to mount. Path needs to point to the root folder of the content package structure.
+     * @param destPath Path to mount folder into
+     */
+    @SuppressWarnings("null")
+    public void folderXmlJcr(@NotNull File mountFolder, @NotNull String destPath) {
+        if (bundleContext == null) {
+            throw new IllegalArgumentException("No bundle context given for content loader.");
+        }
+        Dictionary<String, Object> serviceProperties = MapUtil.toDictionary(
+                "provider.file", mountFolder.getAbsolutePath(),
+                "provider.root", destPath,
+                "provider.fs.mode", "FILEVAULT_XML");
+        FsResourceProvider service = MockOsgi.activateInjectServices(FsResourceProvider.class, bundleContext, serviceProperties);
+        bundleContext.registerService(ResourceProvider.class, service, serviceProperties);
+    }
+
 }
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java b/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
index 39c717a..59b9a8b 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Helpers for importing test content into the mocked repositories / resource hierarchies.
  */
-@org.osgi.annotation.versioning.Version("1.2.0")
+@org.osgi.annotation.versioning.Version("1.3.0")
 package org.apache.sling.testing.mock.sling.loader;
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java b/core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderJsonTest.java
similarity index 65%
copy from core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
copy to core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderJsonTest.java
index 39c717a..4aaa87c 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderJsonTest.java
@@ -16,8 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * Helpers for importing test content into the mocked repositories / resource hierarchies.
- */
-@org.osgi.annotation.versioning.Version("1.2.0")
-package org.apache.sling.testing.mock.sling.loader;
+package org.apache.sling.testing.mock.sling.jcrmock.loader;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderFolderJsonTest;
+
+public class ContentLoaderFolderJsonTest extends AbstractContentLoaderFolderJsonTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java b/core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderXmlJcrTest.java
similarity index 64%
copy from core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
copy to core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderXmlJcrTest.java
index 39c717a..0697e88 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderFolderXmlJcrTest.java
@@ -16,8 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * Helpers for importing test content into the mocked repositories / resource hierarchies.
- */
-@org.osgi.annotation.versioning.Version("1.2.0")
-package org.apache.sling.testing.mock.sling.loader;
+package org.apache.sling.testing.mock.sling.jcrmock.loader;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderFolderXmlJcrTest;
+
+public class ContentLoaderFolderXmlJcrTest extends AbstractContentLoaderFolderXmlJcrTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java
index d6babba..d2ca3df 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java
@@ -98,14 +98,15 @@ public abstract class AbstractContentLoaderBinaryTest {
         assertMimeType(fileResource, "mime/test");
     }
 
-    private void assertSampleImageFileSize(Resource resource) throws IOException {
-        InputStream is = resource.adaptTo(InputStream.class);
-        assertNotNull("InputSteam is null for " + resource.getPath(), is);
-        byte[] binaryData = IOUtils.toByteArray(is);
-        assertEquals(SAMPLE_IMAGE_FILESIZE, binaryData.length);
+    static void assertSampleImageFileSize(Resource resource) throws IOException {
+        try (InputStream is = resource.adaptTo(InputStream.class)) {
+            assertNotNull("InputSteam is null for " + resource.getPath(), is);
+            byte[] binaryData = IOUtils.toByteArray(is);
+            assertEquals(SAMPLE_IMAGE_FILESIZE, binaryData.length);
+        }
     }
 
-    private void assertMimeType(Resource resource, String mimeType) {
+    static void assertMimeType(Resource resource, String mimeType) {
         assertNotNull(resource);
         assertEquals(mimeType, ResourceUtil.getValueMap(resource).get(JcrConstants.JCR_MIMETYPE, String.class));
     }
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderJsonTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderJsonTest.java
new file mode 100644
index 0000000..e247041
--- /dev/null
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderJsonTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.sling.loader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.testing.mock.sling.NodeTypeDefinitionScanner;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+@SuppressWarnings("null")
+public abstract class AbstractContentLoaderFolderJsonTest {
+
+    @Rule
+    public SlingContext context = new SlingContext(getResourceResolverType());
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected String path;
+
+    @Before
+    public void setUp() {
+        path = context.uniqueRoot().content();
+
+        try {
+            NodeTypeDefinitionScanner.get().register(context.resourceResolver().adaptTo(Session.class),
+                    ImmutableList.of("SLING-INF/nodetypes/app.cnd"),
+                    getResourceResolverType().getNodeTypeMode());
+        }
+        catch (RepositoryException ex) {
+            throw new RuntimeException("Unable to register namespaces.", ex);
+        }
+
+        context.load().folderJson("src/test/resources/json-import-samples", path + "/mount");
+    }
+
+    @After
+    public final void tearDown() throws Exception {
+        // make sure all changes from ContentLoader are committed
+        assertFalse(context.resourceResolver().hasChanges());
+    }
+
+    @Test
+    public void testContentResourceType() {
+        Resource resource = context.resourceResolver().getResource(path + "/mount/content/jcr:content");
+        assertEquals("sample/components/homepage", resource.getResourceType());
+    }
+
+    @Test
+    public void testDamResourceType() {
+        Resource resource = context.resourceResolver().getResource(path + "/mount/dam/portraits/scott_reynolds.jpg");
+        assertEquals("dam:Asset", resource.getResourceType());
+    }
+
+    @Test
+    public void testBinaryResource() throws IOException {
+        Resource fileResource = context.resourceResolver().getResource(path + "/mount/binary/sample-image.gif");
+        AbstractContentLoaderBinaryTest.assertSampleImageFileSize(fileResource);
+    }
+
+}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderXmlJcrTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderXmlJcrTest.java
new file mode 100644
index 0000000..89f4c84
--- /dev/null
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderXmlJcrTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.sling.loader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@SuppressWarnings("null")
+public abstract class AbstractContentLoaderFolderXmlJcrTest {
+
+    @Rule
+    public SlingContext context = new SlingContext(getResourceResolverType());
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected String path;
+
+    @Before
+    public void setUp() {
+        path = "/content";
+        context.load().folderXmlJcr("src/test/resources/xml-jcr-import-samples", path);
+    }
+
+    @After
+    public final void tearDown() throws Exception {
+        // make sure all changes from ContentLoader are committed
+        assertFalse(context.resourceResolver().hasChanges());
+    }
+
+    @Test
+    public void testContentResourceType() {
+        Resource resource = context.resourceResolver().getResource(path + "/samples/en/jcr:content");
+        assertEquals("samples/sample-app/components/content/page/homepage", resource.getResourceType());
+    }
+
+    @Test
+    public void testDamResourceType() {
+        Resource resource = context.resourceResolver().getResource(path + "/dam/talk.png/jcr:content");
+        assertEquals("app:AssetContent", resource.getResourceType());
+    }
+
+    @Test
+    public void testBinaryResource() throws IOException {
+        Resource fileResource = context.resourceResolver().getResource(path + "/dam/talk.png/jcr:content/renditions/original");
+        try (InputStream is = fileResource.adaptTo(InputStream.class)) {
+            assertNotNull("InputSteam is null for " + fileResource.getPath(), is);
+            byte[] binaryData = IOUtils.toByteArray(is);
+            assertEquals(8668, binaryData.length);
+        }
+    }
+
+}
diff --git a/core/src/test/resources/json-import-samples/binary/sample-image.gif b/core/src/test/resources/json-import-samples/binary/sample-image.gif
new file mode 100644
index 0000000..8b310f6
Binary files /dev/null and b/core/src/test/resources/json-import-samples/binary/sample-image.gif differ
diff --git a/core/src/test/resources/xml-jcr-import-samples/.content.xml b/core/src/test/resources/xml-jcr-import-samples/.content.xml
new file mode 100644
index 0000000..b264022
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/.content.xml
@@ -0,0 +1,24 @@
+<?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" xmlns:rep="internal" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
+    jcr:mixinTypes="[rep:AccessControllable,rep:RepoAccessControllable]"
+    jcr:primaryType="rep:root"
+    sling:resourceType="sling:redirect"
+    sling:target="/index.html" />
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/.content.xml
new file mode 100644
index 0000000..115c72c
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/.content.xml
@@ -0,0 +1,28 @@
+<?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" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:rep="internal" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
+    jcr:mixinTypes="[mix:lockable,rep:AccessControllable,sling:Redirect]"
+    jcr:primaryType="sling:OrderedFolder"
+    jcr:title="Content Root"
+    sling:resourceType="sling:redirect"
+    sling:target="/geohome">
+  <dam />
+  <samples />
+</jcr:root>
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/dam/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/dam/.content.xml
new file mode 100644
index 0000000..64f25b1
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/dam/.content.xml
@@ -0,0 +1,24 @@
+<?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" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:rep="internal" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
+    jcr:mixinTypes="[mix:lockable,rep:AccessControllable]"
+    jcr:primaryType="sling:OrderedFolder">
+  <talk.png />
+</jcr:root>
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/.content.xml
new file mode 100644
index 0000000..e207a1e
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/.content.xml
@@ -0,0 +1,44 @@
+<?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" xmlns:app="http://sample.com/app/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
+    jcr:primaryType="app:Asset">
+  <jcr:content
+      jcr:primaryType="app:AssetContent">
+    <metadata
+        app:Bitsperpixel="{Long}4"
+        app:extracted="{Date}2015-09-19T14:33:36.078+02:00"
+        app:Fileformat="PNG"
+        app:MIMEtype="image/png"
+        app:Numberofimages="{Long}1"
+        app:Numberoftextualcomments="{Long}3"
+        app:Physicalheightindpi="{Long}72"
+        app:Physicalheightininches="{Decimal}3.750854253768921"
+        app:Physicalwidthindpi="{Long}72"
+        app:Physicalwidthininches="{Decimal}6.668185710906982"
+        app:Progressive="no"
+        app:sha1="29e02b493473c2beaf851002b67b6f1b700be978"
+        app:size="{Long}6652"
+        app:writebackEnable="False"
+        dc:format="image/png"
+        dc:modified="{Date}2014-09-19T21:20:26.812+02:00"
+        jcr:primaryType="nt:unstructured"
+        writebackEnable="{Boolean}true" />
+  </jcr:content>
+</jcr:root>
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original
new file mode 100644
index 0000000..0d42760
Binary files /dev/null and b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original differ
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original.dir/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original.dir/.content.xml
new file mode 100644
index 0000000..1813b25
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/original.dir/.content.xml
@@ -0,0 +1,25 @@
+<?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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
+    jcr:primaryType="nt:file">
+  <jcr:content
+      jcr:mimeType="image/png"
+      jcr:primaryType="nt:resource" />
+</jcr:root>
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/web.1280.1280.png b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/web.1280.1280.png
new file mode 100644
index 0000000..27b0374
Binary files /dev/null and b/core/src/test/resources/xml-jcr-import-samples/content/dam/talk.png/_jcr_content/renditions/web.1280.1280.png differ
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/samples/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/samples/.content.xml
new file mode 100644
index 0000000..c96141e
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/samples/.content.xml
@@ -0,0 +1,23 @@
+<?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" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
+    jcr:primaryType="sling:OrderedFolder">
+  <en />
+</jcr:root>
diff --git a/core/src/test/resources/xml-jcr-import-samples/content/samples/en/.content.xml b/core/src/test/resources/xml-jcr-import-samples/content/samples/en/.content.xml
new file mode 100644
index 0000000..c394cf9
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/content/samples/en/.content.xml
@@ -0,0 +1,195 @@
+<?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" xmlns:app="http://sample.com/jcr/app/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
+    jcr:primaryType="app:Page">
+  <jcr:content
+      app:cloudserviceconfigs="[[]]"
+      app:deviceGroups="[/etc/mobile/groups/responsive]"
+      app:template="samples/sample-app/templates/content/homepage"
+      jcr:primaryType="app:PageContent"
+      jcr:title="en"
+      sling:resourceType="samples/sample-app/components/content/page/homepage"
+      includeAside="{Boolean}true"
+      includeAsideBar="{Boolean}true"
+      includeTeaserBar="{Boolean}true"
+      includeTeaserbar="{Boolean}true"
+      inheritAside="{Boolean}false"
+      inheritTeaserbar="{Boolean}false"
+      navTitle="HOME"
+      pageTitle="Sample Site">
+    <teaserbar
+        jcr:primaryType="nt:unstructured"
+        sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarParsys">
+      <teaserbaritem
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarItem"
+          linkContentRef="/content/samples/en/conference"
+          linkMediaDownload="{Boolean}false"
+          linkTitle="This should help you with your decision"
+          linkType="internal"
+          linkWindowFeatures="default"
+          linkWindowTarget="_self"
+          mediaRef="/content/dam/samples/content/user.png"
+          teaserContent="Still not convinced to attend? Need persuasion? Facts for your boss?"
+          title="Why to attend" />
+      <teaserbaritem_0
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarItem"
+          linkContentRef="/content/samples/en/venue"
+          linkMediaDownload="{Boolean}false"
+          linkTitle="More information"
+          linkType="internal"
+          linkWindowFeatures="default"
+          linkWindowTarget="_self"
+          mediaRef="/content/dam/samples/content/location.png"
+          teaserContent="Take a look at the new venue for 2013. The Kulturbrauerei in the Prenzlauer Berg district."
+          title="Location" />
+      <teaserbaritem_1
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarItem"
+          linkContentRef="/content/samples/en/conference/call-for-papers"
+          linkMediaDownload="{Boolean}false"
+          linkTitle="Submit your proposal here"
+          linkType="internal"
+          linkWindowFeatures="default"
+          linkWindowTarget="_self"
+          mediaRef="/content/dam/samples/content/talk.png"
+          teaserContent="If you have insight and experiences with Apache Sling and want to share them? We are actually asking for your participation!"
+          title="Want to share?" />
+      <teaserbaritem_2
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarItem"
+          linkContentRef="/content/samples/en/archive"
+          linkMediaDownload="{Boolean}false"
+          linkTitle="Dive into the archive"
+          linkType="internal"
+          linkWindowFeatures="default"
+          linkWindowTarget="_self"
+          mediaRef="/content/dam/samples/content/archive.png"
+          teaserContent="adaptTo() is not a new event. Take a look at what was said and done previously."
+          title="Take a look back" />
+    </teaserbar>
+    <aside
+        jcr:primaryType="nt:unstructured"
+        sling:resourceType="samples/sample-app/components/content/aside/asideParsys">
+      <asidesponsorteaser
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/aside/asideSponsorTeaser"
+          title="Sponsors">
+        <images
+            jcr:primaryType="nt:unstructured"
+            sling:resourceType="samples/sample-app/components/content/aside/asideSponsorTeaserParsys">
+          <asidesponsorteaserit_0
+              jcr:primaryType="nt:unstructured"
+              sling:resourceType="samples/sample-app/components/content/aside/asideSponsorTeaserItem"
+              imageHeight="41"
+              imageWidth="200"
+              linkExternalRef="http://www.pro-vision.de"
+              linkType="external"
+              linkWindowFeatures="default"
+              linkWindowTarget="_blank"
+              mediaRef="/content/dam/samples/content/provision-logo.png" />
+        </images>
+      </asidesponsorteaser>
+      <asidesocialteaser
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/aside/asideSocialTeaser"
+          title="Follow us">
+        <images
+            jcr:primaryType="nt:unstructured"
+            sling:resourceType="samples/sample-app/components/content/aside/asideSponsorTeaserParsys">
+          <asidesocialteaserite
+              jcr:primaryType="nt:unstructured"
+              sling:resourceType="samples/sample-app/components/content/aside/asideSocialTeaserItem"
+              linkExternalRef="http://twitter.com/adaptto"
+              linkMediaDownload="{Boolean}false"
+              linkTitle="@adaptTo"
+              linkType="external"
+              linkWindowFeatures="default"
+              linkWindowTarget="_blank"
+              mediaRef="/content/dam/samples/content/twitter-icon.png"
+              title="on twitter" />
+        </images>
+      </asidesocialteaser>
+    </aside>
+    <content
+        jcr:primaryType="nt:unstructured"
+        sling:resourceType="sample/wcm/parsys/components/parsys">
+      <contentrichtext
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/common/contentRichText"
+          text="&lt;p&gt;adaptTo() is a meetup in Berlin focused on Apache Sling including Apache Jackrabbit and Apache Felix and is addressed to all using this stack or parts of it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a data=&quot;{&amp;quot;linkType&amp;quot;:&amp;quot;internal&amp;quot;,&amp;quot;linkContentRef&amp;quot;:&amp;quot;/content/samples/handler/en/conference&amp;quot;,&amp;quot;linkWindowTarget&amp;quot;:&amp;quot;_self&amp;quot;,&amp;quot;linkWindowFeatures&amp;quot;:&amp;quot;defa [...]
+      <contentheadline
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/common/contentHeadline"
+          headline="Extended Call for Papers"
+          smaller="{Boolean}true" />
+      <contentrichtext_0
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/common/contentRichText"
+          text="&lt;p&gt;Although we got some great submissions for adaptTo() 2013, we still have some slots for further sessions. Therefore we extend the timeslot for submissions to the call for papers and for feedback by two weeks. This means you still can submit you submissions till 06.05.2013. We're looking forward to get more of your great talks.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a data=&quot;{&amp;quot;linkType&amp;quot;:&amp;quot;internal&amp;quot;,&amp;quot;linkContentRef&amp;quot;:&amp [...]
+    </content>
+    <stage
+        jcr:primaryType="nt:unstructured"
+        sling:resourceType="sample/wcm/parsys/components/parsys">
+      <stageheader
+          jcr:primaryType="nt:unstructured"
+          sling:resourceType="samples/sample-app/components/content/stage/stageheader"
+          linkMediaDownload="{Boolean}false"
+          linkType="internal"
+          linkWindowFeatures="default"
+          linkWindowTarget="_self"
+          mediaRef="/content/dam/samples/content/stageheader-outside2.jpg"
+          subtitle="23.–25. September 2013&#xA;Kulturbrauerei Berlin"
+          title="adaptTo() 2013">
+        <links
+            jcr:primaryType="nt:unstructured"
+            sling:resourceType="samples/sample-app/components/content/stage/stageheaderParsys">
+          <stageheaderlinkitem
+              jcr:primaryType="nt:unstructured"
+              sling:resourceType="samples/sample-app/components/content/stage/stageheaderLinkItem"
+              linkContentRef="/content/samples/en/tickets"
+              linkMediaDownload="{Boolean}false"
+              linkTitle="Get tickets now"
+              linkType="internal"
+              linkWindowFeatures="default"
+              linkWindowTarget="_self" />
+          <stageheaderlinkitem_0
+              jcr:primaryType="nt:unstructured"
+              sling:resourceType="samples/sample-app/components/content/stage/stageheaderLinkItem"
+              linkContentRef="/content/samples/en/conference/call-for-papers"
+              linkMediaDownload="{Boolean}false"
+              linkTitle="Submit paper"
+              linkType="internal"
+              linkWindowFeatures="default"
+              linkWindowTarget="_self" />
+        </links>
+      </stageheader>
+    </stage>
+    <image
+        jcr:primaryType="nt:unstructured" />
+  </jcr:content>
+  <tools />
+  <conference />
+  <extra jcr:primaryType="nt:unstructured">
+    <extracontent/>
+    <binaryfile.xml/>
+  </extra>
+</jcr:root>
diff --git a/parent/pom.xml b/parent/pom.xml
index 49a7e71..eb76d90 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -215,6 +215,37 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.api</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.json</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.xml-jcr</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit.vault</groupId>
+            <artifactId>org.apache.jackrabbit.vault</artifactId>
+            <version>3.1.44</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.fsresource</artifactId>
+            <version>2.1.17-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.8.3</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <version>3.7.0</version>