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

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


The following commit(s) were added to refs/heads/SLING-11558-return-resources 
by this push:
     new dcf9d93  Use the cacheMap
dcf9d93 is described below

commit dcf9d93bbc98e391fd322e5b6d81b5c7b8722c69
Author: Jörg Hoh <[email protected]>
AuthorDate: Sat Jun 10 17:54:17 2023 +0200

    Use the cacheMap
    
    before resolving a resource check if it has not yet done before. This
    map shares the lifetime of the ResourceResolver, so a single instance
    can be used on many servlet resolutions.
---
 pom.xml                                            |   8 +-
 .../internal/helper/LocationCollector.java         | 110 +++++++++++++++------
 .../internal/helper/LocationCollectorTest.java     |  90 +++++++++++++----
 3 files changed, 157 insertions(+), 51 deletions(-)

diff --git a/pom.xml b/pom.xml
index b77ab75..0989ffb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -316,10 +316,16 @@
             <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.4.2</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/helper/LocationCollector.java
 
b/src/main/java/org/apache/sling/servlets/resolver/internal/helper/LocationCollector.java
index ebf2478..284ba38 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,8 +19,10 @@
 package org.apache.sling.servlets.resolver.internal.helper;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
@@ -54,29 +56,13 @@ import org.slf4j.LoggerFactory;
 
 class LocationCollector {
 
-    static @NotNull List<Resource> getLocations(String resourceType, String 
resourceSuperType, String baseResourceType,
-                                                     ResourceResolver 
resolver) {
-        LocationCollector collector = new LocationCollector(resourceType, 
resourceSuperType, baseResourceType, resolver);
-        List<Resource> result = new ArrayList<>();
-        collector.getResolvedLocations().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);
-               result.add(locationRes);
-        });
-        return result;
-    }
+       private 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;
@@ -88,12 +74,13 @@ class LocationCollector {
     private final List<String> result = new ArrayList<>();
 
     private LocationCollector(String resourceType, String resourceSuperType, 
String baseResourceType,
-                              ResourceResolver resolver) {
+                              ResourceResolver resolver, Map<String,Resource> 
cacheMap) {
 
         this.resourceType = resourceType;
         this.resourceSuperType = resourceSuperType;
         this.baseResourceType = baseResourceType;
         this.resolver = resolver;
+        this.cacheMap = cacheMap;
 
         String[] tmpPath = resolver.getSearchPath();
         if (tmpPath.length == 0) {
@@ -182,7 +169,7 @@ class LocationCollector {
                 && this.resourceSuperType != null ) {
             superType = this.resourceSuperType;
         } else {
-            superType = getResourceSuperType(resolver, resourceType);
+            superType = getResourceSuperTypeInternal(resourceType);
         }
 
         // detect circular dependency
@@ -198,15 +185,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();
             }
@@ -214,7 +200,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;
@@ -224,14 +210,74 @@ class LocationCollector {
         return rst;
     }
     
-       protected static @NotNull Resource getResource(final ResourceResolver 
resolver, String path) {
-               Resource res = resolver.getResource(path);
-
-               if (res == null) {
-                       res = new SyntheticResource(resolver, path, 
"$synthetic$");
+    /**
+     * 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 (cacheMap.containsKey(path)) {
+               return cacheMap.get(path);
+       } else {
+               Resource r = resolver.getResource(path);
+               cacheMap.put(path, r);
+               return r;
+       }
+    }
+    
+    
+    
+    // ---- static helpers ---
+    
+       static @NotNull List<Resource> getLocations(String resourceType, String 
resourceSuperType, String baseResourceType,
+                       ResourceResolver resolver) {
+               
+               @SuppressWarnings("unchecked")
+               Map<String,Resource> m = (Map<String,Resource>) 
resolver.getPropertyMap().get(CACHE_KEY);
+               if (m == null) {
+                       m = new HashMap<>();
+                       resolver.getPropertyMap().put(CACHE_KEY, m);
+               }
+               final Map<String,Resource> cacheMap = m;
+               
+               LocationCollector collector = new 
LocationCollector(resourceType, resourceSuperType, baseResourceType,
+                               resolver, cacheMap);
+               List<Resource> result = new ArrayList<>();
+               collector.getResolvedLocations().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, cacheMap);
+                       result.add(locationRes);
+               });
+               return result;
+       }
+    
+    /**
+     * Resolve a path to a resource
+     * @param resolver
+     * @param path
+     * @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;
                }
-
-               return res;
        }
     
 }
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 39962ee..0512793 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
@@ -86,21 +86,6 @@ public class LocationCollectorTest {
         request.setResource(resource);
                
        }
-
-    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);
-    }
     
     @Test
     public void testSearchPathEmpty() {
@@ -134,6 +119,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2Elements() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -175,6 +161,7 @@ public class LocationCollectorTest {
         request.setResource(r);
     }
 
+    @Test
     public void testSearchPathEmptyAbsoluteType() {
         // expect path gets { "/" }
         searchPathOptions.setSearchPaths(null);
@@ -194,6 +181,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementAbsoluteType() {
         String root0 = "/apps/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -216,6 +204,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsAbsoluteType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -240,6 +229,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPathEmptyWithSuper() {
         // expect path gets { "/" }
         searchPathOptions.setSearchPaths(null);
@@ -260,6 +250,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementWithSuper() {
         String root0 = "/apps/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -282,6 +273,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsWithSuper() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -309,6 +301,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPathEmptyAbsoluteTypeWithSuper() {
         // expect path gets { "/" }
         searchPathOptions.setSearchPaths(null);
@@ -333,6 +326,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath1ElementAbsoluteTypeWithSuper() {
         String root0 = "/apps/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -359,6 +353,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testSearchPath2ElementsAbsoluteTypeWithSuper() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -389,6 +384,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithoutResourceType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -405,6 +401,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithResourceType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -422,6 +419,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testScriptNameWithResourceTypeAndSuperType() {
         String root0 = "/apps/";
         String root1 = "/libs/";
@@ -442,6 +440,7 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
+    @Test
     public void testCircularResourceTypeHierarchy() {
         final String root1 = "/libs/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -487,9 +486,14 @@ public class LocationCollectorTest {
         assertThat(loc,isSameResourceList(expected));
     }
     
-    
+    @Test
     public void testResolveDefaultResourceType() {
        
+       searchPathOptions.setSearchPaths(new String[] {
+                "/apps/",
+                "/libs/"
+        });
+       
        List<Resource> loc = getLocations(DEFAULT_RESOURCE_TYPE, 
resourceSuperType);
        
        List<Resource> expected = Arrays.asList(
@@ -500,7 +504,7 @@ public class LocationCollectorTest {
        assertThat(loc,isSameResourceList(expected));
     }
  
-    
+    @Test
     public void testAbsoluteResourceSuperType() throws Exception {
         final String root = "/apps/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -533,7 +537,7 @@ public class LocationCollectorTest {
        assertThat(loc,isSameResourceList(expected));
     }
     
-    
+    @Test
     public void testNoSuperType() throws Exception {
         final String root = "/apps/";
         searchPathOptions.setSearchPaths(new String[] {
@@ -559,11 +563,61 @@ public class LocationCollectorTest {
        assertThat(loc,isSameResourceList(expected));
     }
     
+
+    @Test
+    public void checkThatTheCacheIsUsed() {
+
+       // 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());
+    }
+    
+    
+    // --- 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);
+    }
+    
     // Mimic the searchpath semantic of the ResourceResolverFactory
     public class SearchPathOptions {
        

Reply via email to