SLING-10804 respect search path when mounting JSON/FileVault XML folders
also ensure getParentResourceType and isResourceType are working in combination with resource providers from mounted folders
diff --git a/core/src/main/java/org/apache/sling/testing/mock/sling/RRMockResourceResolverWrapper.java b/core/src/main/java/org/apache/sling/testing/mock/sling/RRMockResourceResolverWrapper.java
index 6689e5d..895fa09 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/sling/RRMockResourceResolverWrapper.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/sling/RRMockResourceResolverWrapper.java
@@ -18,15 +18,21 @@
*/
package org.apache.sling.testing.mock.sling;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.wrappers.ResourceResolverWrapper;
+import org.apache.sling.resourceresolver.impl.ResourceTypeUtil;
import org.apache.sling.spi.resource.provider.ResolveContext;
import org.apache.sling.spi.resource.provider.ResourceContext;
import org.apache.sling.spi.resource.provider.ResourceProvider;
@@ -50,16 +56,26 @@
@Override
@SuppressWarnings("unchecked")
public Resource getResource(@NotNull String path) {
- ResourceProvider resourceProvider = getMatchingResourceProvider(path);
- if (resourceProvider != null) {
- return resourceProvider.getResource(this, path, ResourceContext.EMPTY_CONTEXT, null);
+ if (resourceProviders.isEmpty()) {
+ return super.getResource(path);
}
- return super.getResource(path);
+ List<String> normalizedPaths = getNormalizedPaths(path);
+ for (String normalizedPath : normalizedPaths) {
+ ResourceProvider resourceProvider = getMatchingResourceProvider(normalizedPath);
+ if (resourceProvider != null) {
+ return resourceProvider.getResource(this, normalizedPath, ResourceContext.EMPTY_CONTEXT, null);
+ }
+ return super.getResource(path);
+ }
+ return null;
}
@Override
@SuppressWarnings("unchecked")
public @NotNull Iterator<Resource> listChildren(@NotNull Resource parent) {
+ if (resourceProviders.isEmpty()) {
+ return super.listChildren(parent);
+ }
ResourceProvider resourceProvider = getMatchingResourceProvider(parent.getPath());
if (resourceProvider != null) {
Iterator<Resource> result = resourceProvider.listChildren(this, parent);
@@ -74,24 +90,13 @@
}
private ResourceProvider getMatchingResourceProvider(String path) {
- if (resourceProviders.isEmpty()) {
- return null;
- }
- String normalizedPath = ResourceUtil.normalize(path);
- if (!StringUtils.startsWith(normalizedPath, "/")) {
- return null;
- }
- return getMatchingResourceProviderRecursively(normalizedPath);
- }
-
- private ResourceProvider getMatchingResourceProviderRecursively(String path) {
ResourceProvider provider = resourceProviders.get(path);
if (provider != null) {
return provider;
}
String parentPath = ResourceUtil.getParent(path);
if (parentPath != null) {
- return getMatchingResourceProviderRecursively(parentPath);
+ return getMatchingResourceProvider(parentPath);
}
else {
return null;
@@ -118,4 +123,89 @@
return null;
}
+ private List<String> getNormalizedPaths(String path) {
+ List<String> result = new ArrayList<>();
+ if (StringUtils.startsWith(path, "/")) {
+ result.add(ResourceUtil.normalize(path));
+ }
+ else {
+ for (String searchPath : getSearchPath()) {
+ String combinedPath = StringUtils.removeEnd(searchPath, "/") + "/" + path;
+ result.add(ResourceUtil.normalize(combinedPath));
+ }
+ }
+ return result;
+ }
+
+ // duplicated method from MockResourceResolver to ensure resources from resource providers are respected as well
+ @Override
+ public boolean isResourceType(Resource resource, String resourceType) {
+ if (resourceProviders.isEmpty()) {
+ return super.isResourceType(resource, resourceType);
+ }
+ boolean result = false;
+ if ( resource != null && resourceType != null ) {
+ // Check if the resource is of the given type. This method first checks the
+ // resource type of the resource, then its super resource type and continues
+ // to go up the resource super type hierarchy.
+ if (ResourceTypeUtil.areResourceTypesEqual(resourceType, resource.getResourceType(), getSearchPath())) {
+ result = true;
+ } else {
+ Set<String> superTypesChecked = new HashSet<>();
+ String superType = this.getParentResourceType(resource);
+ while (!result && superType != null) {
+ if (ResourceTypeUtil.areResourceTypesEqual(resourceType, superType, getSearchPath())) {
+ result = true;
+ } else {
+ superTypesChecked.add(superType);
+ superType = this.getParentResourceType(superType);
+ if (superType != null && superTypesChecked.contains(superType)) {
+ throw new SlingException("Cyclic dependency for resourceSuperType hierarchy detected on resource " + resource.getPath()) {
+ // anonymous class to avoid problem with null cause
+ private static final long serialVersionUID = 1L;
+ };
+ }
+ }
+ }
+ }
+
+ }
+ return result;
+ }
+
+ // duplicated method from MockResourceResolver to ensure resources from resource providers are respected as well
+ @Override
+ public String getParentResourceType(Resource resource) {
+ if (resourceProviders.isEmpty()) {
+ return super.getParentResourceType(resource);
+ }
+ String resourceSuperType = null;
+ if ( resource != null ) {
+ resourceSuperType = resource.getResourceSuperType();
+ if (resourceSuperType == null) {
+ resourceSuperType = this.getParentResourceType(resource.getResourceType());
+ }
+ }
+ return resourceSuperType;
+ }
+
+ // duplicated method from MockResourceResolver to ensure resources from resource providers are respected as well
+ @Override
+ public String getParentResourceType(String resourceType) {
+ if (resourceProviders.isEmpty()) {
+ return super.getParentResourceType(resourceType);
+ }
+ // normalize resource type to a path string
+ final String rtPath = (resourceType == null ? null : ResourceUtil.resourceTypeToPath(resourceType));
+ // get the resource type resource and check its super type
+ String resourceSuperType = null;
+ if ( rtPath != null ) {
+ final Resource rtResource = getResource(rtPath);
+ if (rtResource != null) {
+ resourceSuperType = rtResource.getResourceSuperType();
+ }
+ }
+ return resourceSuperType;
+ }
+
}
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 108892a..de0badf 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
@@ -567,7 +567,7 @@
* Mount a folder (file system) 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
+ * @param childName Name of child resource of subtree path that should be mounted from FileVault XML structure
*/
public void folderFileVaultXml(@NotNull String mountFolderPath, @NotNull Resource parentResource, @NotNull String childName) {
folderFileVaultXml(new File(mountFolderPath), parentResource, childName);
@@ -576,7 +576,7 @@
/**
* Mount a folder (file system) 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 destPath Path to mount folder into
+ * @param destPath Subtree path that should be mounted from FileVault XML structure
*/
public void folderFileVaultXml(@NotNull String mountFolderPath, @NotNull String destPath) {
folderFileVaultXml(new File(mountFolderPath), destPath);
@@ -586,7 +586,7 @@
* 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 parentResource Parent resource
- * @param childName Name of child resource to mount folder into
+ * @param childName Name of child resource of subtree path that should be mounted from FileVault XML structure
*/
public void folderFileVaultXml(@NotNull File mountFolder, @NotNull Resource parentResource, @NotNull String childName) {
folderFileVaultXml(mountFolder, parentResource.getPath() + "/" + childName);
@@ -595,7 +595,7 @@
/**
* 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
+ * @param destPath Subtree path that should be mounted from FileVault XML structure
*/
@SuppressWarnings("null")
public void folderFileVaultXml(@NotNull File mountFolder, @NotNull String destPath) {
diff --git a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderFileVaultXmlTest.java b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderFileVaultXmlTest.java
index 473ecbf..7942f8b 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderFileVaultXmlTest.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderFolderFileVaultXmlTest.java
@@ -21,12 +21,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -45,12 +47,10 @@
protected abstract ResourceResolverType getResourceResolverType();
- protected String path;
-
@Before
public void setUp() {
- path = "/content";
- context.load().folderFileVaultXml("src/test/resources/xml-jcr-import-samples", path);
+ context.load().folderFileVaultXml("src/test/resources/xml-jcr-import-samples", "/apps");
+ context.load().folderFileVaultXml("src/test/resources/xml-jcr-import-samples", "/content");
}
@After
@@ -61,13 +61,13 @@
@Test
public void testContentResourceType() {
- Resource resource = context.resourceResolver().getResource(path + "/samples/en/jcr:content");
+ Resource resource = context.resourceResolver().getResource("/content/samples/en/jcr:content");
assertEquals("samples/sample-app/components/content/page/homepage", resource.getResourceType());
}
@Test
public void testContentListChildren() {
- Resource resource = context.resourceResolver().getResource(path + "/samples/en");
+ Resource resource = context.resourceResolver().getResource("/content/samples/en");
List<Resource> result = ImmutableList.copyOf(resource.listChildren());
assertEquals("jcr:content", result.get(0).getName());
assertEquals("tools", result.get(1).getName());
@@ -75,13 +75,13 @@
@Test
public void testDamResourceType() {
- Resource resource = context.resourceResolver().getResource(path + "/dam/talk.png/jcr:content");
+ Resource resource = context.resourceResolver().getResource("/content/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");
+ Resource fileResource = context.resourceResolver().getResource("/content/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);
@@ -89,4 +89,29 @@
}
}
+ @Test
+ public void testAppsResource() {
+ Resource resource = context.resourceResolver().getResource("/apps/app1/components/comp1");
+ assertNotNull(resource);
+ assertEquals("Component #1", resource.getValueMap().get(JcrConstants.JCR_TITLE, String.class));
+ }
+
+ @Test
+ public void testAppsResource_SearchPath() {
+ Resource resource = context.resourceResolver().getResource("app1/components/comp1");
+ assertNotNull(resource);
+ assertEquals("Component #1", resource.getValueMap().get(JcrConstants.JCR_TITLE, String.class));
+ }
+
+ @Test
+ public void testAppsResource_ParentResourceType() {
+ Resource resource = context.resourceResolver().getResource("/content/samples/en/jcr:content/comp1-resource");
+ assertNotNull(resource);
+ assertEquals("app1/components/base", context.resourceResolver().getParentResourceType(resource));
+ assertTrue(context.resourceResolver().isResourceType(resource, "app1/components/comp1"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "/apps/app1/components/comp1"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "app1/components/base"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "core/components/superResource"));
+ }
+
}
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
index 712309c..f70549d 100644
--- 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
@@ -20,10 +20,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
+import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -42,12 +45,10 @@
protected abstract ResourceResolverType getResourceResolverType();
- protected String path;
-
@Before
public void setUp() {
- path = context.uniqueRoot().content();
- context.load().folderJson("src/test/resources/json-import-samples", path + "/mount");
+ context.load().folderJson("src/test/resources/json-import-samples", "/mount");
+ context.load().folderJson("src/test/resources/json-import-samples/apps", "/apps");
}
@After
@@ -58,13 +59,13 @@
@Test
public void testContentResourceType() {
- Resource resource = context.resourceResolver().getResource(path + "/mount/content/jcr:content");
+ Resource resource = context.resourceResolver().getResource("/mount/content/jcr:content");
assertEquals("sample/components/homepage", resource.getResourceType());
}
@Test
public void testContentListChildren() {
- Resource resource = context.resourceResolver().getResource(path + "/mount/content");
+ Resource resource = context.resourceResolver().getResource("/mount/content");
List<Resource> result = ImmutableList.copyOf(resource.listChildren());
assertEquals("jcr:content", result.get(0).getName());
assertEquals("toolbar", result.get(1).getName());
@@ -72,14 +73,39 @@
@Test
public void testDamResourceType() {
- Resource resource = context.resourceResolver().getResource(path + "/mount/dam/portraits/scott_reynolds.jpg");
+ Resource resource = context.resourceResolver().getResource("/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");
+ Resource fileResource = context.resourceResolver().getResource("/mount/binary/sample-image.gif");
AbstractContentLoaderBinaryTest.assertSampleImageFileSize(fileResource);
}
+ @Test
+ public void testAppsResource() {
+ Resource resource = context.resourceResolver().getResource("/apps/app1/components/comp1");
+ assertNotNull(resource);
+ assertEquals("Component #1", resource.getValueMap().get(JcrConstants.JCR_TITLE, String.class));
+ }
+
+ @Test
+ public void testAppsResource_SearchPath() {
+ Resource resource = context.resourceResolver().getResource("app1/components/comp1");
+ assertNotNull(resource);
+ assertEquals("Component #1", resource.getValueMap().get(JcrConstants.JCR_TITLE, String.class));
+ }
+
+ @Test
+ public void testAppsResource_ParentResourceType() {
+ Resource resource = context.resourceResolver().getResource("/mount/content/jcr:content/comp1-resource");
+ assertNotNull(resource);
+ assertEquals("app1/components/base", context.resourceResolver().getParentResourceType(resource));
+ assertTrue(context.resourceResolver().isResourceType(resource, "app1/components/comp1"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "/apps/app1/components/comp1"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "app1/components/base"));
+ assertTrue(context.resourceResolver().isResourceType(resource, "core/components/superResource"));
+ }
+
}
diff --git a/core/src/test/resources/json-import-samples/apps/app1/components/base.json b/core/src/test/resources/json-import-samples/apps/app1/components/base.json
new file mode 100644
index 0000000..19742d2
--- /dev/null
+++ b/core/src/test/resources/json-import-samples/apps/app1/components/base.json
@@ -0,0 +1,5 @@
+{
+ "jcr:primaryType": "app:Component",
+ "jcr:title": "Base Component",
+ "sling:resourceSuperType": "core/components/superResource"
+}
diff --git a/core/src/test/resources/json-import-samples/apps/app1/components/comp1.json b/core/src/test/resources/json-import-samples/apps/app1/components/comp1.json
new file mode 100644
index 0000000..99705fc
--- /dev/null
+++ b/core/src/test/resources/json-import-samples/apps/app1/components/comp1.json
@@ -0,0 +1,5 @@
+{
+ "jcr:primaryType": "app:Component",
+ "jcr:title": "Component #1",
+ "sling:resourceSuperType": "app1/components/base"
+}
diff --git a/core/src/test/resources/json-import-samples/content.json b/core/src/test/resources/json-import-samples/content.json
index 1c8bccd..c1fa7de 100644
--- a/core/src/test/resources/json-import-samples/content.json
+++ b/core/src/test/resources/json-import-samples/content.json
@@ -15,6 +15,10 @@
"app:designPath": "/etc/designs/sample",
"app:lastModifiedBy": "admin",
"utf8Property": "äöü߀",
+ "comp1-resource": {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType": "app1/components/comp1"
+ },
"par": {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "foundation/components/parsys",
diff --git a/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/base/.content.xml b/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/base/.content.xml
new file mode 100644
index 0000000..ab92315
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/base/.content.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:app="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
+ jcr:primaryType="app:Component"
+ jcr:title="Base Component"
+ sling:resourceSuperType="core/components/superResource" />
diff --git a/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/comp1/.content.xml b/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/comp1/.content.xml
new file mode 100644
index 0000000..7ad0240
--- /dev/null
+++ b/core/src/test/resources/xml-jcr-import-samples/apps/app1/components/comp1/.content.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:app="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
+ jcr:primaryType="app:Component"
+ jcr:title="Component #1"
+ sling:resourceSuperType="app1/components/base" />
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
index c394cf9..09748dc 100644
--- 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
@@ -34,6 +34,9 @@
inheritTeaserbar="{Boolean}false"
navTitle="HOME"
pageTitle="Sample Site">
+ <comp1-resource
+ jcr:primaryType="nt:unstructured"
+ sling:resourceType="app1/components/comp1" />
<teaserbar
jcr:primaryType="nt:unstructured"
sling:resourceType="samples/sample-app/components/content/teaserbar/teaserbarParsys">