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

joerghoh pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new e015d48  SLING-11558 cache already resolved resources (#37)
e015d48 is described below

commit e015d4879d176199b3f0c533af148e658fd77f1f
Author: Jörg Hoh <[email protected]>
AuthorDate: Fri Jul 21 13:53:39 2023 +0200

    SLING-11558 cache already resolved resources (#37)
    
    The resolution process caches already resolved resources to avoid repeated 
(and unnecessary) repository access
---
 pom.xml                                            |   4 +-
 .../servlets/resolver/internal/ResolverConfig.java |   8 +
 .../resolver/internal/SlingServletResolver.java    |  14 +-
 .../internal/console/WebConsolePlugin.java         |   2 +-
 .../internal/helper/AbstractResourceCollector.java |  23 +-
 .../internal/helper/LocationCollector.java         | 136 +++++-
 .../helper/NamedScriptResourceCollector.java       |  11 +-
 .../internal/helper/ResourceCollector.java         |  21 +-
 .../internal/helper/IsSameResourceList.java        |  71 +++
 .../internal/helper/LocationCollectorTest.java     | 527 ++++++++++++++-------
 .../internal/helper/ResourceCollectorTest.java     |   2 +-
 .../internal/helper/ScriptSelection2Test.java      |   2 +-
 .../internal/helper/ScriptSelectionTest.java       |   2 +-
 13 files changed, 593 insertions(+), 230 deletions(-)

diff --git a/pom.xml b/pom.xml
index e5cd351..994f00e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -313,13 +313,13 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.sling-mock.junit4</artifactId>
-            <version>2.5.0</version>
+            <version>3.4.10</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             
<artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>1.2.2</version>
+            <version>1.4.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/ResolverConfig.java 
b/src/main/java/org/apache/sling/servlets/resolver/internal/ResolverConfig.java
index 9cefe49..1808518 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/ResolverConfig.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/ResolverConfig.java
@@ -68,4 +68,12 @@ public @interface ResolverConfig {
             " If false (the default), servlets will be represented in the 
content tree using individual resource providers -" +
             " otherwise, servlets will be mounted into the content tree using 
one resource provider per search path entry. This effectively overrides mount 
providers.")
     boolean servletresolver_mountPathProviders() default false; // NOSONAR
+    
+    
+    @AttributeDefinition(name="use resource caching", description = "Use an 
optimized version of the servlet resolution which "
+               + "uses caching within the ResourceResolver.")
+    boolean enable_resource_caching() default true;
+    
+    
+    
 }
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java
index 81a99c9..18b3bfa 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java
@@ -132,6 +132,9 @@ public class SlingServletResolver
      * The default extensions
      */
     private AtomicReference<String[]> defaultExtensions = new 
AtomicReference<>();
+    
+    private boolean useResourceCaching;
+    
 
     private final PathBasedServletAcceptor pathBasedServletAcceptor = new 
PathBasedServletAcceptor();
 
@@ -295,7 +298,7 @@ public class SlingServletResolver
             String extension = request.getRequestPathInfo().getExtension();
             ResourceCollector locationUtil = new 
ResourceCollector(String.valueOf(status),
                     DEFAULT_ERROR_HANDLER_RESOURCE_TYPE, resource,
-                    extension, this.executionPaths.get());
+                    extension, this.executionPaths.get(), 
this.useResourceCaching);
             Servlet servlet = getServletInternal(locationUtil, request, 
scriptResolver);
 
             // fall back to default servlet if none
@@ -353,7 +356,7 @@ public class SlingServletResolver
                 String extension = request.getRequestPathInfo().getExtension();
                 ResourceCollector locationUtil = new 
ResourceCollector(tClass.getSimpleName(),
                         DEFAULT_ERROR_HANDLER_RESOURCE_TYPE, resource,
-                        extension, this.executionPaths.get());
+                        extension, this.executionPaths.get(), 
this.useResourceCaching);
                 servlet = getServletInternal(locationUtil, request, 
scriptResolver);
 
                 // go to the base class
@@ -470,9 +473,9 @@ public class SlingServletResolver
             // the resource type is not absolute, so lets go for the deep 
search
             final AbstractResourceCollector locationUtil;
             if ( request != null ) {
-                locationUtil = ResourceCollector.create(request, 
this.executionPaths.get(), this.defaultExtensions.get());
+                locationUtil = ResourceCollector.create(request, 
this.executionPaths.get(), this.defaultExtensions.get(), 
this.useResourceCaching);
             } else {
-                locationUtil = 
NamedScriptResourceCollector.create(scriptNameOrResourceType, resource, 
this.executionPaths.get());
+                locationUtil = 
NamedScriptResourceCollector.create(scriptNameOrResourceType, resource, 
this.executionPaths.get(), this.useResourceCaching);
             }
             servlet = getServletInternal(locationUtil, request, resolver);
 
@@ -598,7 +601,7 @@ public class SlingServletResolver
         final ResourceCollector locationUtil = new ResourceCollector(
             ServletResolverConstants.DEFAULT_ERROR_HANDLER_METHOD,
             DEFAULT_ERROR_HANDLER_RESOURCE_TYPE, resource,
-            extension, this.executionPaths.get());
+            extension, this.executionPaths.get(), this.useResourceCaching);
         final Servlet servlet = getServletInternal(locationUtil, request, 
resolver);
         if (servlet != null) {
             return servlet;
@@ -677,6 +680,7 @@ public class SlingServletResolver
 
         
this.executionPaths.set(getExecutionPaths(config.servletresolver_paths()));
         this.defaultExtensions.set(config.servletresolver_defaultExtensions());
+        this.useResourceCaching = config.enable_resource_caching();
 
         // setup default servlet
         this.getDefaultServlet();
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/console/WebConsolePlugin.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/console/WebConsolePlugin.java
index 7882aa5..d725ffd 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/console/WebConsolePlugin.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/console/WebConsolePlugin.java
@@ -353,7 +353,7 @@ public class WebConsolePlugin extends HttpServlet {
                     executionPaths.get(),
                     defaultExtensions.get(),
                     method,
-                    requestPathInfo.getSelectors());
+                    requestPathInfo.getSelectors(),true);
             servlets = locationUtil.getServlets(resourceResolver, 
resolutionCache.getScriptEngineExtensions());
         }
 
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java
index 9a09dbd..4f90c97 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java
@@ -53,17 +53,21 @@ public abstract class AbstractResourceCollector {
     protected final String resourceSuperType;
 
     protected final String[] executionPaths;
+    
+    protected boolean useResourceCaching;
 
     protected AbstractResourceCollector(final String baseResourceType,
             final String resourceType,
             final String resourceSuperType,
             final String extension,
-            final String[] executionPaths) {
+            final String[] executionPaths,
+            final boolean useResourceCaching) {
         this.baseResourceType = baseResourceType;
         this.resourceType = resourceType;
         this.resourceSuperType = resourceSuperType;
         this.extension = extension;
         this.executionPaths = executionPaths;
+        this.useResourceCaching = useResourceCaching;
     }
 
     public final Collection<Resource> getServlets(final ResourceResolver 
resolver, final List<String> scriptExtensions) {
@@ -96,20 +100,9 @@ public abstract class AbstractResourceCollector {
         });
         
         
-        List<String> locations = LocationCollector.getLocations(resourceType, 
resourceSuperType, baseResourceType, resolver);
-        locations.forEach(location -> {
-            // get the location resource, use a synthetic resource if there
-            // is no real location. There may still be children at this
-            // location
-            final String path;
-            if ( location.endsWith("/") ) {
-                path = location.substring(0, location.length() - 1);
-            } else {
-                path = location;
-            }
-            final Resource locationRes = getResource(resolver, path);
-            getWeightedResources(resources, locationRes);
-        });
+        List<Resource> locations = 
LocationCollector.getLocations(resourceType, resourceSuperType, 
+                       baseResourceType, resolver, this.useResourceCaching);
+        locations.forEach(locationRes -> getWeightedResources(resources, 
locationRes));
 
         List<Resource> result = new ArrayList<>(resources.size());
         result.addAll(resources);
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollector.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollector.java
index 60b3ff3..2059c39 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollector.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollector.java
@@ -19,14 +19,19 @@
 package org.apache.sling.servlets.resolver.internal.helper;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
 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.resource.SyntheticResource;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.LoggerFactory;
@@ -53,32 +58,36 @@ import org.slf4j.LoggerFactory;
 
 class LocationCollector {
 
-    static @NotNull List<String> getLocations(String resourceType, String 
resourceSuperType, String baseResourceType,
-                                                     ResourceResolver 
resolver) {
-        LocationCollector collector = new LocationCollector(resourceType, 
resourceSuperType, baseResourceType, resolver);
-        return collector.getResolvedLocations();
-    }
+       protected static final String CACHE_KEY = 
LocationCollector.class.getName() + ".CacheKey";
 
     // The search path of the resource resolver
     private final String[] searchPath;
 
+    private Map<String,Resource> cacheMap;
+    
     private final ResourceResolver resolver;
     private final String baseResourceType;
     private final String resourceType;
     private final String resourceSuperType;
+    private final boolean useResourceCaching;
 
     /** Set of used resource types to detect a circular resource type 
hierarchy. */
     private final Set<String> usedResourceTypes = new HashSet<>();
     
     private final List<String> result = new ArrayList<>();
 
-    private LocationCollector(String resourceType, String resourceSuperType, 
String baseResourceType,
-                              ResourceResolver resolver) {
+    private LocationCollector(@NotNull String resourceType, @NotNull String 
resourceSuperType, 
+               @NotNull String baseResourceType,
+            @NotNull ResourceResolver resolver, 
+            @NotNull Map<String,Resource> cacheMap,
+            final boolean useResourceCaching) {
 
         this.resourceType = resourceType;
         this.resourceSuperType = resourceSuperType;
         this.baseResourceType = baseResourceType;
         this.resolver = resolver;
+        this.cacheMap = cacheMap;
+        this.useResourceCaching = useResourceCaching;
 
         String[] tmpPath = resolver.getSearchPath();
         if (tmpPath.length == 0) {
@@ -167,7 +176,7 @@ class LocationCollector {
                 && this.resourceSuperType != null ) {
             superType = this.resourceSuperType;
         } else {
-            superType = getResourceSuperType(resolver, resourceType);
+            superType = getResourceSuperTypeInternal(resourceType);
         }
 
         // detect circular dependency
@@ -183,15 +192,14 @@ class LocationCollector {
     }
 
     // this method is largely duplicated from ResourceUtil
-    private @Nullable String getResourceSuperType(final @NotNull 
ResourceResolver resourceResolver,
-                                                  final @NotNull String 
resourceType) {
+    private @Nullable String getResourceSuperTypeInternal(final @NotNull 
String resourceType) {
         // normalize resource type to a path string
         final String rtPath = ResourceUtil.resourceTypeToPath(resourceType);
         // get the resource type resource and check its super type
         String rst = null;
         // if the path is absolute, use it directly
         if (rtPath.startsWith("/")) {
-            final Resource rtResource = resourceResolver.getResource(rtPath);
+            final Resource rtResource = resolveResource(rtPath);
             if (rtResource != null) {
                 rst = rtResource.getResourceSuperType();
             }
@@ -199,7 +207,7 @@ class LocationCollector {
             // if the path is relative we use the search paths
             for (final String path : this.searchPath) {
                 final String candidatePath = path + rtPath;
-                final Resource rtResource = 
resourceResolver.getResource(candidatePath);
+                final Resource rtResource = resolveResource(candidatePath);
                 if (rtResource != null && rtResource.getResourceSuperType() != 
null) {
                     rst = rtResource.getResourceSuperType();
                     break;
@@ -208,4 +216,108 @@ class LocationCollector {
         }
         return rst;
     }
+    
+    /**
+     * Resolve a path to a resource; the cacheMap is used for it.
+     * @param path the path
+     * @return the resource for it or null
+     */
+    private @Nullable Resource resolveResource(@NotNull String path) {
+       if (useResourceCaching && cacheMap.containsKey(path)) {
+               return cacheMap.get(path);
+       } else {
+               Resource r = resolver.getResource(path);
+               cacheMap.put(path, r);
+               return r;
+       }
+    }
+    
+    
+    
+    // ---- static helpers ---
+    
+    /**
+     * Return a list of resources, which represent potential matches for the 
given resourceType, resourceSuperType, 
+     * considering the constraints of the baseResourceType.
+     * @param resourceType 
+     * @param resourceSuperType
+     * @param baseResourceType
+     * @param resolver
+     * @return a list of non-null resources
+     */
+       static @NotNull List<Resource> getLocations(@NotNull String 
resourceType, 
+                       @NotNull String resourceSuperType, 
+                       @NotNull String baseResourceType,
+                       @NotNull ResourceResolver resolver,
+                       boolean useResourceCaching) {
+               
+               final Map<String,Resource> cacheMap = getCacheMap(resolver);
+               final LocationCollector collector = new 
LocationCollector(resourceType, resourceSuperType, baseResourceType,
+                               resolver, cacheMap, useResourceCaching);
+               
+               // get the location resource, use a synthetic resource if there
+               // is no real location. There may still be children at this
+               // location
+               return collector.getResolvedLocations().stream()
+                 .map(LocationCollector::removeTrailingSlash)
+                 .map(path -> getResource(resolver,path,cacheMap))
+                 .collect(Collectors.toList());
+       }
+
+       private static Map<String, Resource> getCacheMap(@NotNull 
ResourceResolver resolver) {
+               Map<String, Resource> cacheMap;
+               Object c = resolver.getPropertyMap().get(CACHE_KEY);
+               
+               if (c != null) {
+                       if (c instanceof Map<?,?>) {
+                               cacheMap = (Map<String,Resource>) 
resolver.getPropertyMap().get(CACHE_KEY);
+                       } else {
+                               // it's of an incorrect type, so probably 
somebody else is using it.
+                               // Just use the map for now, but do not store 
it as cache to the ResourceResolver
+                               cacheMap = new HashMap<>();
+                       }
+               } else {
+                       // this is good enough, as ResourceResolvers should be 
used only by a single thread anyway
+                       cacheMap = Collections.synchronizedMap(new 
HashMap<String,Resource>());
+                       resolver.getPropertyMap().put(CACHE_KEY, cacheMap);
+               }
+               return cacheMap;
+       }
+    
+    /**
+     * Resolve a path to a resource, either via the cache or the 
ResourceResolver
+     * @param resolver
+     * @param path
+     * @param cacheMap the cache map to use
+     * @return a synthetic or "real" resource
+     */
+       protected static @NotNull Resource getResource(final @NotNull 
ResourceResolver resolver, 
+                       @NotNull String path, @NotNull Map<String,Resource> 
cacheMap) {
+               
+               if (cacheMap.containsKey(path) && cacheMap.get(path) != null) {
+                       return cacheMap.get(path);
+               } else {
+                       Resource res = resolver.getResource(path);
+                       if (res == null) {
+                               res = new SyntheticResource(resolver, path, 
"$synthetic$");
+                       }
+                       cacheMap.put(path, res);
+                       return res;
+               }
+       }
+       
+       /**
+        * Remove the last character if it's a trailing "/"
+        * @param input
+        * @return if input ends with a "/", returns the input without the "/" 
character at its end; input otherwise
+        */
+       private static @NotNull String removeTrailingSlash (@NotNull String 
input) {
+               if (input.endsWith("/")) {
+                       return input.substring(0, input.length() - 1);
+               } else {
+                       return input;
+               }
+       }
+       
+    
 }
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java
index c39e86a..07c32b4 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java
@@ -39,7 +39,8 @@ public class NamedScriptResourceCollector extends 
AbstractResourceCollector {
 
     public static NamedScriptResourceCollector create(final String name,
             final Resource resource,
-            final String[] executionPaths) {
+            final String[] executionPaths,
+            final boolean useResourceCaching) {
         final String resourceType;
         final String resourceSuperType;
         final String baseResourceType;
@@ -66,7 +67,8 @@ public class NamedScriptResourceCollector extends 
AbstractResourceCollector {
                 resourceSuperType,
                 scriptName,
                 extension,
-                executionPaths);
+                executionPaths,
+                useResourceCaching);
     }
 
     public NamedScriptResourceCollector(final String baseResourceType,
@@ -74,8 +76,9 @@ public class NamedScriptResourceCollector extends 
AbstractResourceCollector {
                               final String resourceSuperType,
                               final String scriptName,
                               final String extension,
-                              final String[] executionPaths) {
-        super(baseResourceType, resourceType, resourceSuperType, extension, 
executionPaths);
+                              final String[] executionPaths,
+                              final boolean useResourceCaching) {
+        super(baseResourceType, resourceType, resourceSuperType, extension, 
executionPaths, useResourceCaching);
         this.scriptName = scriptName;
         // create the hash code once
         final String key = baseResourceType + ':' + this.scriptName + ':' +
diff --git 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java
index 6a10661..df70b15 100644
--- 
a/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java
+++ 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java
@@ -86,20 +86,21 @@ public class ResourceCollector extends 
AbstractResourceCollector {
      */
     public static ResourceCollector create(
             final SlingHttpServletRequest request,
-            final String[] executionPaths, final String[] defaultExtensions) {
+            final String[] executionPaths, final String[] defaultExtensions, 
boolean UseResourceCaching) {
         final RequestPathInfo requestPathInfo = request.getRequestPathInfo();
         final boolean isDefaultExtension = 
ArrayUtils.contains(defaultExtensions, requestPathInfo.getExtension());
         return new ResourceCollector(request.getResource(), 
requestPathInfo.getExtension(), executionPaths, isDefaultExtension,
-                request.getMethod(), requestPathInfo.getSelectors());
+                request.getMethod(), requestPathInfo.getSelectors(), 
UseResourceCaching);
     }
 
     public static ResourceCollector create(final Resource resource,
             final String extension,
             final String[] executionPaths, final String[] defaultExtensions,
-            final String methodName, final String[] selectors
+            final String methodName, final String[] selectors, boolean 
useResourceCaching
             ) {
         boolean isDefaultExtension = ArrayUtils.contains(defaultExtensions, 
extension);
-        return new ResourceCollector(resource, extension, executionPaths, 
isDefaultExtension, methodName, selectors);
+        return new ResourceCollector(resource, extension, executionPaths, 
isDefaultExtension, 
+                       methodName, selectors, useResourceCaching);
     }
 
     /**
@@ -122,7 +123,7 @@ public class ResourceCollector extends 
AbstractResourceCollector {
     public ResourceCollector(final String methodName,
             final String baseResourceType, final Resource resource,
             final String[] executionPaths) {
-       this(methodName, baseResourceType, resource, null, executionPaths);
+       this(methodName, baseResourceType, resource, null, 
executionPaths,false);
     }
 
     /**
@@ -144,12 +145,13 @@ public class ResourceCollector extends 
AbstractResourceCollector {
     public ResourceCollector(final String methodName,
             final String baseResourceType, final Resource resource,
             final String extension,
-            final String[] executionPaths) {
+            final String[] executionPaths,
+            final boolean useResourceCaching) {
         super((baseResourceType != null
                 ? baseResourceType
                 : ServletResolverConstants.DEFAULT_RESOURCE_TYPE),
             resource.getResourceType(), resource.getResourceSuperType(),
-            extension, executionPaths);
+            extension, executionPaths, useResourceCaching);
         this.methodName = methodName;
         this.requestSelectors = new String[0];
         this.numRequestSelectors = 0;
@@ -185,11 +187,12 @@ public class ResourceCollector extends 
AbstractResourceCollector {
             final String[] executionPaths,
             final boolean isDefaultExtension,
             final String methodName,
-            final String[] selectors) {
+            final String[] selectors,
+            final boolean useResourceCaching) {
         super(ServletResolverConstants.DEFAULT_RESOURCE_TYPE,
                 resource.getResourceType(),
                 resource.getResourceSuperType(),
-                extension, executionPaths);
+                extension, executionPaths, useResourceCaching);
             this.methodName = methodName;
 
             this.suffExt = "." + extension;
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/IsSameResourceList.java
 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/IsSameResourceList.java
new file mode 100644
index 0000000..e414dd3
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/IsSameResourceList.java
@@ -0,0 +1,71 @@
+/*
+ * 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.servlets.resolver.internal.helper;
+
+import java.util.List;
+
+import org.apache.sling.api.resource.Resource;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Custom matcher which compares the list of resources. For matching just the 
path
+ * of the resource is considered.
+ *
+ */
+public class IsSameResourceList extends TypeSafeMatcher<List<Resource>>{
+       
+       List<Resource> baseLine;
+       
+       private IsSameResourceList(List<Resource> baseline) {
+               this.baseLine = baseline;
+       }
+       
+       @Override
+       public boolean matchesSafely (List<Resource> item) {
+               
+               if (item.size() != baseLine.size()) {
+                       return false;
+               }
+               for (int i=0; i < item.size(); i++) {
+                       if (!sameResourcePath(item.get(i),baseLine.get(i))) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+       
+       @Override
+       public void describeTo(Description description) {
+               description.appendText("isSameListOfResources for " + baseLine);
+               
+       }
+       
+       
+       private boolean sameResourcePath (Resource a, Resource b) {
+               return a.getPath().equals(b.getPath());
+       }
+       
+       
+       public static Matcher<List<Resource>> isSameResourceList(List<Resource> 
baseline) {
+               return new IsSameResourceList(baseline);
+       }
+
+}
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollectorTest.java
 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollectorTest.java
index f640360..7b99501 100644
--- 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollectorTest.java
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollectorTest.java
@@ -19,84 +19,138 @@
 package org.apache.sling.servlets.resolver.internal.helper;
 
 import static 
org.apache.sling.api.servlets.ServletResolverConstants.DEFAULT_RESOURCE_TYPE;
+import static 
org.apache.sling.servlets.resolver.internal.helper.HelperTestBase.addOrReplaceResource;
+import static 
org.apache.sling.servlets.resolver.internal.helper.HelperTestBase.getOrCreateParentResource;
+import static 
org.apache.sling.servlets.resolver.internal.helper.IsSameResourceList.isSameResourceList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.hamcrest.CoreMatchers.*;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 import org.apache.sling.api.resource.PersistenceException;
 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.resource.SyntheticResource;
+import org.apache.sling.commons.testing.sling.MockSlingHttpServletRequest;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Mockito;
+
+@RunWith(Parameterized.class)
+public class LocationCollectorTest {
+       
+       // Run the test both with and without resource caching enabled
+       @Parameters
+       public static Iterable<Object> data() {
+               return Arrays.asList(true, false);
+       }
+       
+       @Parameter
+       public boolean useResourceCaching;
+       
+       @Rule
+       public final SlingContext context = new SlingContext();
+       
+       SearchPathOptions searchPathOptions = new SearchPathOptions();
+    protected String resourcePath;
+    protected String resourceType;
+    protected String resourceTypePath;
+    protected String resourceSuperType;
+    protected String resourceSuperTypePath;
+       
+       protected Resource resource;
+       protected MockSlingHttpServletRequest request;
+       
+       
+       protected ResourceResolver resolver; // required because of the spy
+       
+       @Before
+       public void setup() throws Exception {
+
+               searchPathOptions = new SearchPathOptions();
+               resolver = Mockito.spy(context.resourceResolver());
+               Mockito.when(resolver.getSearchPath()).thenAnswer( invocation 
-> {
+                       return searchPathOptions.getSearchPath();
+               });
+               
+        resourceType = "foo:bar";
+        resourceTypePath = ResourceUtil.resourceTypeToPath(resourceType);
 
-public class LocationCollectorTest extends HelperTestBase {
-
-    List<String> getLocations(final String resourceType,
-            final String resourceSuperType) {
-        return getLocations(resourceType, resourceSuperType, 
DEFAULT_RESOURCE_TYPE);
-    }
-    
-    List<String> getLocations( final String resourceType,
-            final String resourceSuperType,
-            final String baseResourceType) {
-        return LocationCollector.getLocations(resourceType,
-                resourceSuperType,
-                baseResourceType,
-                this.resourceResolver);
-    }
+        resourcePath = "/content/page";
+        context.build().resource("/content",Collections.emptyMap()).commit();
+        Resource parent = resolver.getResource("/content");
+        resource = resolver.create(parent, "page",
+                
Collections.singletonMap(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
resourceType));
+
+        request = new MockSlingHttpServletRequest(resourcePath, "print.A4", 
"html", null, null);
+        request.setMethod("GET");
+        request.setResourceResolver(resolver);
+        request.setResource(resource);
+               
+       }
     
+    @Test
     public void testSearchPathEmpty() {
         // expect path gets { "/" }
-        resourceResolverOptions.setSearchPaths(null);
+        searchPathOptions.setSearchPaths(null);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       "/" + resourceTypePath, // /foo/bar
-                "/" + DEFAULT_RESOURCE_TYPE); // /sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r("/" + resourceTypePath), // /foo/bar
+                r("/" + DEFAULT_RESOURCE_TYPE)); // /sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1Element() {
         String root0 = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0
         });
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       root0 + resourceTypePath, // /apps/foo/bar
-                root0 + DEFAULT_RESOURCE_TYPE); // /apps/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + resourceTypePath), // /apps/foo/bar
+                r(root0 + DEFAULT_RESOURCE_TYPE)); // 
/apps/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2Elements() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       root0 + resourceTypePath, // /apps/foo/bar
-                root1 + resourceTypePath, // /libs/foo/bar
-                root0 + DEFAULT_RESOURCE_TYPE, // /apps/sling/servlet/default
-                root1 + DEFAULT_RESOURCE_TYPE); // /libs/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + resourceTypePath), // /apps/foo/bar
+                r(root1 + resourceTypePath), // /libs/foo/bar
+                r(root0 + DEFAULT_RESOURCE_TYPE), // 
/apps/sling/servlet/default
+                r(root1 + DEFAULT_RESOURCE_TYPE)); // 
/libs/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
     /**
@@ -116,13 +170,14 @@ public class LocationCollectorTest extends HelperTestBase 
{
         if (newResourceSuperType != null) {
             props.put("sling:resourceSuperType", newResourceSuperType);
         }
-        Resource r = addOrReplaceResource(resourceResolver, 
resource.getPath(), props);
+        Resource r = addOrReplaceResource(resolver, resource.getPath(), props);
         request.setResource(r);
     }
 
+    @Test
     public void testSearchPathEmptyAbsoluteType() {
         // expect path gets { "/" }
-        resourceResolverOptions.setSearchPaths(null);
+        searchPathOptions.setSearchPaths(null);
 
         // absolute resource type
         resourceType = "/foo/bar";
@@ -130,18 +185,19 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, null);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                "/" + DEFAULT_RESOURCE_TYPE); // /sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                       r("/" + DEFAULT_RESOURCE_TYPE)); // 
/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementAbsoluteType() {
         String root0 = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0
         });
 
@@ -151,20 +207,21 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, null);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                root0 + DEFAULT_RESOURCE_TYPE); // /apps/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                r(root0 + DEFAULT_RESOURCE_TYPE)); // 
/apps/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsAbsoluteType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
@@ -175,19 +232,20 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, null);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                root0 + DEFAULT_RESOURCE_TYPE, // /apps/sling/servlet/default
-                root1 + DEFAULT_RESOURCE_TYPE); // /libs/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                r(root0 + DEFAULT_RESOURCE_TYPE), // 
/apps/sling/servlet/default
+                r(root1 + DEFAULT_RESOURCE_TYPE)); // 
/libs/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPathEmptyWithSuper() {
         // expect path gets { "/" }
-        resourceResolverOptions.setSearchPaths(null);
+        searchPathOptions.setSearchPaths(null);
 
         // set resource super type
         resourceSuperType = "foo:superBar";
@@ -195,19 +253,20 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(null, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       "/" + resourceTypePath, // /foo/bar
-                "/" + resourceSuperTypePath, // /foo/superBar
-                "/" + DEFAULT_RESOURCE_TYPE); // /sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r("/" + resourceTypePath), // /foo/bar
+                r("/" + resourceSuperTypePath), // /foo/superBar
+                r("/" + DEFAULT_RESOURCE_TYPE)); // /sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementWithSuper() {
         String root0 = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0
         });
 
@@ -217,20 +276,21 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(null, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       root0 + resourceTypePath, // /apps/foo/bar
-                root0 + resourceSuperTypePath, // /apps/foo/superBar
-                root0 + DEFAULT_RESOURCE_TYPE); // /apps/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + resourceTypePath), // /apps/foo/bar
+                r(root0 + resourceSuperTypePath), // /apps/foo/superBar
+                r(root0 + DEFAULT_RESOURCE_TYPE)); // 
/apps/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsWithSuper() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
@@ -241,22 +301,23 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(null, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       root0 + resourceTypePath, // /apps/foo/bar
-                root1 + resourceTypePath, // /libs/foo/bar
-                root0 + resourceSuperTypePath, // /apps/foo/superBar
-                root1 + resourceSuperTypePath, // /libs/foo/superBar
-                root0 + DEFAULT_RESOURCE_TYPE, // /apps/sling/servlet/default
-                root1 + DEFAULT_RESOURCE_TYPE); // /libs/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + resourceTypePath), // /apps/foo/bar
+                r(root1 + resourceTypePath), // /libs/foo/bar
+                r(root0 + resourceSuperTypePath), // /apps/foo/superBar
+                r(root1 + resourceSuperTypePath), // /libs/foo/superBar
+                r(root0 + DEFAULT_RESOURCE_TYPE), // 
/apps/sling/servlet/default
+                r(root1 + DEFAULT_RESOURCE_TYPE)); // 
/libs/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPathEmptyAbsoluteTypeWithSuper() {
         // expect path gets { "/" }
-        resourceResolverOptions.setSearchPaths(null);
+        searchPathOptions.setSearchPaths(null);
 
         // absolute resource type
         resourceType = "/foo/bar";
@@ -268,19 +329,20 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                "/" + resourceSuperTypePath, // /foo/superBar
-                "/" + DEFAULT_RESOURCE_TYPE); // /sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                r("/" + resourceSuperTypePath), // /foo/superBar
+                r("/" + DEFAULT_RESOURCE_TYPE)); // /sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementAbsoluteTypeWithSuper() {
         String root0 = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0
         });
 
@@ -294,20 +356,21 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                root0 + resourceSuperTypePath, // /apps/foo/superBar
-                root0 + DEFAULT_RESOURCE_TYPE); // /apps/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                r(root0 + resourceSuperTypePath), // /apps/foo/superBar
+                r(root0 + DEFAULT_RESOURCE_TYPE)); // 
/apps/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsAbsoluteTypeWithSuper() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
@@ -322,72 +385,78 @@ public class LocationCollectorTest extends HelperTestBase 
{
         replaceResource(resourceType, resourceSuperType);
 
         final Resource r = request.getResource();
-        List<String> loc = getLocations(r.getResourceType(),
+        List<Resource> loc = getLocations(r.getResourceType(),
                 r.getResourceSuperType());
         
-        List<String> expected = Arrays.asList(
-                       resourceTypePath, // /foo/bar
-                root0 + resourceSuperTypePath, // /apps/foo/superBar
-                root1 + resourceSuperTypePath, // /libs/foo/superBar
-                root0 + DEFAULT_RESOURCE_TYPE, // /apps/sling/servlet/default
-                root1 + DEFAULT_RESOURCE_TYPE); // /libs/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath), // /foo/bar
+                r(root0 + resourceSuperTypePath), // /apps/foo/superBar
+                r(root1 + resourceSuperTypePath), // /libs/foo/superBar
+                r(root0 + DEFAULT_RESOURCE_TYPE), // 
/apps/sling/servlet/default
+                r(root1 + DEFAULT_RESOURCE_TYPE)); // 
/libs/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithoutResourceType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
-        List<String> loc = getLocations("",
+        List<Resource> loc = getLocations("",
                 null,"");
         
-        List<String> expected = Arrays.asList("/apps/","/libs/");
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r("/apps"),
+                       r("/libs"));
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithResourceType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
-        List<String> loc = getLocations("a/b", null);
-        
-        List<String> expected = Arrays.asList(
-                       root0 + "a/b",
-                root1 + "a/b",
-                root0 + DEFAULT_RESOURCE_TYPE,
-                root1 + DEFAULT_RESOURCE_TYPE);
-        assertThat(loc,is(expected));
+        List<Resource> loc = getLocations("a/b", null);
+        
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + "a/b"),
+                r(root1 + "a/b"),
+                r(root0 + DEFAULT_RESOURCE_TYPE),
+                r(root1 + DEFAULT_RESOURCE_TYPE));
+        assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithResourceTypeAndSuperType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root0,
                 root1
         });
         
-        List<String> loc = getLocations("a/b", "c/d");
-
-        List<String> expected = Arrays.asList(
-                       root0 + "a/b",
-                root1 + "a/b",
-                root0 + "c/d",
-                root1 + "c/d",
-                root0 + DEFAULT_RESOURCE_TYPE,
-                root1 + DEFAULT_RESOURCE_TYPE);
-        assertThat(loc,is(expected));
+        List<Resource> loc = getLocations("a/b", "c/d");
+
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + "a/b"),
+                r(root1 + "a/b"),
+                r(root0 + "c/d"),
+                r(root1 + "c/d"),
+                r(root0 + DEFAULT_RESOURCE_TYPE),
+                r(root1 + DEFAULT_RESOURCE_TYPE));
+        assertThat(loc,isSameResourceList(expected));
     }
     
-    public void testCircularResourceTypeHierarchy() {
+    @Test
+    public void testCircularResourceTypeHierarchy() throws 
PersistenceException {
         final String root1 = "/libs/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root1
         });
 
@@ -400,54 +469,49 @@ public class LocationCollectorTest extends HelperTestBase 
{
         Map<String, Object> resource2Props = new HashMap<>();
         resource2Props.put(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
resourceType);
         resource2Props.put("sling:resourceSuperType", resourceSuperType2);
-        try {
-            
resourceResolver.create(getOrCreateParentResource(resourceResolver, 
resource2Path),
+        resolver.create(getOrCreateParentResource(resolver, resource2Path),
                     ResourceUtil.getName(resource2Path),
                     resource2Props);
-        } catch (PersistenceException e) {
-            fail("Did not expect a persistence exception: " + e.getMessage());
-        }
 
         String resource3Path = root1 + resourceSuperType2;
         Map<String, Object> resource3Props = new HashMap<>();
         resource3Props.put(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
resourceType);
-        resource3Props.put("sling:resourceSuperType", resourceType);
-        try {
-            
resourceResolver.create(getOrCreateParentResource(resourceResolver, 
resource3Path),
-                    ResourceUtil.getName(resource3Path),
-                    resource3Props);
-        } catch (PersistenceException e) {
-            fail("Did not expect a persistence exception: " + e.getMessage());
-        }
-        
-        List<String> loc = getLocations(resourceType, resourceSuperType);
+               resource3Props.put("sling:resourceSuperType", resourceType);
+               resolver.create(getOrCreateParentResource(resolver, 
resource3Path), ResourceUtil.getName(resource3Path),
+                               resource3Props);
+
+               List<Resource> loc = getLocations(resourceType, 
resourceSuperType);
         
-        List<String> expected = Arrays.asList(
-                       root1 + resourceType, // /libs/foo/bar
-                root1 + resourceSuperType, // /libs/foo/check1
-                root1 + resourceSuperType2, // /libs/foo/check2
-                root1 + DEFAULT_RESOURCE_TYPE); // /libs/sling/servlet/default
-        assertThat(loc,is(expected));
+        List<Resource> expected = Arrays.asList(
+                       r(root1 + resourceType), // /libs/foo/bar
+                r(root1 + resourceSuperType), // /libs/foo/check1
+                r(root1 + resourceSuperType2), // /libs/foo/check2
+                r(root1 + DEFAULT_RESOURCE_TYPE)); // 
/libs/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
     }
     
-    
+    @Test
     public void testResolveDefaultResourceType() {
        
-       List<String> loc = getLocations(DEFAULT_RESOURCE_TYPE, 
resourceSuperType);
+       searchPathOptions.setSearchPaths(new String[] {
+                "/apps/",
+                "/libs/"
+        });
        
-       List<String> expected = Arrays.asList(
-                       "/apps/sling/servlet/default",
-                       "/libs/sling/servlet/default",
-                       "/apps/sling/servlet/default",
-                       "/libs/sling/servlet/default"
-                       );
-       assertThat(loc,is(expected));
+       List<Resource> loc = getLocations(DEFAULT_RESOURCE_TYPE, 
resourceSuperType);
+       
+       List<Resource> expected = Arrays.asList(
+                       r("/apps/sling/servlet/default"),
+                       r("/libs/sling/servlet/default"),
+                       r("/apps/sling/servlet/default"),
+                       r("/libs/sling/servlet/default"));
+       assertThat(loc,isSameResourceList(expected));
     }
  
-    
+    @Test
     public void testAbsoluteResourceSuperType() throws Exception {
         final String root = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root
         });
         
@@ -461,26 +525,26 @@ public class LocationCollectorTest extends HelperTestBase 
{
         resourceTypeProps.put(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
resourceType);
         resourceTypeProps.put("sling:resourceSuperType", resourceSuperType);
         
-               
resourceResolver.create(getOrCreateParentResource(resourceResolver, 
resourceTypePath),
+        resolver.create(getOrCreateParentResource(resolver, resourceTypePath),
                                ResourceUtil.getName(resourceTypePath), 
resourceTypeProps);
-               
resourceResolver.create(getOrCreateParentResource(resourceResolver, 
resourceSuperTypePath),
+        resolver.create(getOrCreateParentResource(resolver, 
resourceSuperTypePath),
                                ResourceUtil.getName(resourceSuperTypePath), 
null);
         
         
-       List<String> loc = getLocations(resourceType, resourceSuperType);
+       List<Resource> loc = getLocations(resourceType, resourceSuperType);
        
-       List<String> expected = Arrays.asList(
-                       resourceTypePath,                       // /apps/a/b
-                       resourceSuperTypePath,                  // /apps/c/d
-                       root + DEFAULT_RESOURCE_TYPE    // 
/apps/sling/servlet/default
+       List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath),                            // 
/apps/a/b
+                       r(resourceSuperTypePath),                       // 
/apps/c/d
+                       r(root + DEFAULT_RESOURCE_TYPE)         // 
/apps/sling/servlet/default
                        );
-       assertThat(loc,is(expected));
+       assertThat(loc,isSameResourceList(expected));
     }
     
-    
+    @Test
     public void testNoSuperType() throws Exception {
         final String root = "/apps/";
-        resourceResolverOptions.setSearchPaths(new String[] {
+        searchPathOptions.setSearchPaths(new String[] {
                 root
         });
         
@@ -490,17 +554,122 @@ public class LocationCollectorTest extends 
HelperTestBase {
         Map<String, Object> resourceTypeProps = new HashMap<>();
         resourceTypeProps.put(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
resourceType);
         
-               
resourceResolver.create(getOrCreateParentResource(resourceResolver, 
resourceTypePath),
+        resolver.create(getOrCreateParentResource(resolver, resourceTypePath),
                                ResourceUtil.getName(resourceTypePath), 
resourceTypeProps);
         
         
-       List<String> loc = getLocations(resourceType, resourceSuperType);
+       List<Resource> loc = getLocations(resourceType, resourceSuperType);
        
-       List<String> expected = Arrays.asList(
-                       resourceTypePath,                       // /apps/a/b
-                       root + DEFAULT_RESOURCE_TYPE    // 
/apps/sling/servlet/default
+       List<Resource> expected = Arrays.asList(
+                       r(resourceTypePath),                            // 
/apps/a/b
+                       r(root + DEFAULT_RESOURCE_TYPE)         // 
/apps/sling/servlet/default
                        );
-       assertThat(loc,is(expected));
+       assertThat(loc,isSameResourceList(expected));
+    }
+    
+
+    @Test
+    public void checkThatTheCacheIsUsed() {
+
+       // skip if the test runs without caching
+       if (!useResourceCaching) {
+               return;
+       }
+       
+       // The basic test setup is copied from testSearchPath2ElementsWithSuper
+        String root0 = "/apps/";
+        String root1 = "/libs/";
+        searchPathOptions.setSearchPaths(new String[] {
+                root0,
+                root1
+        });
+
+        // set resource super type
+        resourceSuperType = "foo:superBar";
+        resourceSuperTypePath = 
ResourceUtil.resourceTypeToPath(resourceSuperType);
+        replaceResource(null, resourceSuperType);
+
+        final Resource r = request.getResource();
+        
+       // Execute the same call twice and expect that on 2nd time the 
ResourceResolver
+       // is never used, because all is taken from the cache
+        getLocations(r.getResourceType(),
+                r.getResourceSuperType());
+        
+        Mockito.clearInvocations(resolver);
+        
+        getLocations(r.getResourceType(),
+                r.getResourceSuperType());
+       
+        Mockito.verify(resolver, 
Mockito.never()).getResource(Mockito.anyString());
+    }
+    
+    @Test
+    public void testWithCacheMapKeyAlreadyUsed() {
+       // if the cacheKey in the ResourceResolverMap is already used, make 
sure that it's not overwritten
+       // this is an adapted copy of the testSearchPath1Element testcase
+       
+        String root0 = "/apps/";
+        searchPathOptions.setSearchPaths(new String[] {
+                root0
+        });
+
+        final Resource r = request.getResource();
+        final Object storedElement = "randomString";
+        
r.getResourceResolver().getPropertyMap().put(LocationCollector.CACHE_KEY, 
storedElement);
+        List<Resource> loc = getLocations(r.getResourceType(),
+                r.getResourceSuperType());
+        
+        List<Resource> expected = Arrays.asList(
+                       r(root0 + resourceTypePath), // /apps/foo/bar
+                r(root0 + DEFAULT_RESOURCE_TYPE)); // 
/apps/sling/servlet/default
+        assertThat(loc,isSameResourceList(expected));
+       
+        assertEquals(storedElement, 
r.getResourceResolver().getPropertyMap().get(LocationCollector.CACHE_KEY));
+       
     }
     
+    
+    // --- helper ---
+    
+    private Resource r (String path) {
+       return new SyntheticResource(resolver, path, "resourcetype");
+    }
+    
+    
+    List<Resource> getLocations(final String resourceType,
+            final String resourceSuperType) {
+        return getLocations(resourceType, resourceSuperType, 
DEFAULT_RESOURCE_TYPE);
+    }
+    
+    List<Resource> getLocations( final String resourceType,
+            final String resourceSuperType,
+            final String baseResourceType) {
+       
+        return LocationCollector.getLocations(resourceType,
+                resourceSuperType,
+                baseResourceType,
+                resolver, useResourceCaching);
+    }
+    
+    // Mimic the searchpath semantic of the ResourceResolverFactory
+    public class SearchPathOptions {
+       
+       String[] searchPath = new String[0];
+       
+       public void setSearchPaths(String[] searchpath) {
+               if (searchpath == null) {
+                       this.searchPath = new String[0];
+               } else {
+                       this.searchPath = searchpath;
+               }
+       }
+       
+       public String[] getSearchPath() {
+               return searchPath;
+       }
+    }
+    
+    
+    
 }
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollectorTest.java
 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollectorTest.java
index 7da2270..965bc6b 100644
--- 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollectorTest.java
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollectorTest.java
@@ -389,7 +389,7 @@ public class ResourceCollectorTest extends HelperTestBase {
             pathMap.put(name, path);
         }
 
-        ResourceCollector lu = ResourceCollector.create(request, null, new 
String[] {"html"});
+        ResourceCollector lu = ResourceCollector.create(request, null, new 
String[] {"html"}, true);
         Collection<Resource> res;
         if (scriptEngineExtensions != null) {
             res = lu.getServlets(request.getResourceResolver(), 
scriptEngineExtensions);
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelection2Test.java
 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelection2Test.java
index 674b41e..c2ee45a 100644
--- 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelection2Test.java
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelection2Test.java
@@ -171,7 +171,7 @@ public class ScriptSelection2Test {
                               List<String> scriptEngineFactoriesExtensions, 
String... expectedScripts) {
         SlingHttpServletRequest request = prepareRequest(method, 
contentResource, selectors, extension);
         final ResourceCollector collector =
-                ResourceCollector.create(request, 
context.resourceResolver().getSearchPath(), new String[]{"html"});
+                ResourceCollector.create(request, 
context.resourceResolver().getSearchPath(), new String[]{"html"}, true);
         final Collection<Resource> s = 
collector.getServlets(request.getResourceResolver(), 
scriptEngineFactoriesExtensions);
         if (expectedScripts == null || expectedScripts.length == 0) {
             assertFalse("No script must be found", s.iterator().hasNext());
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelectionTest.java
 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelectionTest.java
index 251231f..be28f2d 100644
--- 
a/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelectionTest.java
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/internal/helper/ScriptSelectionTest.java
@@ -67,7 +67,7 @@ public class ScriptSelectionTest extends HelperTestBase {
 
         // Create mock request and get scripts from ResourceCollector
         final MockSlingHttpServletRequest req = makeRequest(method, selectors, 
extension);
-        final ResourceCollector u = ResourceCollector.create(req, null, new 
String[] {"html"});
+        final ResourceCollector u = ResourceCollector.create(req, null, new 
String[] {"html"}, true);
         final Collection<Resource> s = 
u.getServlets(req.getResourceResolver(), Collections.emptyList());
 
         if(expectedScript == null) {

Reply via email to