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

joerghoh pushed a commit to branch feature/SLING-10269-improve-isResourceType
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git


The following commit(s) were added to 
refs/heads/feature/SLING-10269-improve-isResourceType by this push:
     new 5cf22af  SLING-10269 cache the result of isResourceType()
5cf22af is described below

commit 5cf22afc7e47ba9ce218d7aff3d123146d63a001
Author: Joerg Hoh <[email protected]>
AuthorDate: Wed Mar 31 09:39:08 2021 +0200

    SLING-10269 cache the result of isResourceType()
---
 .../impl/ResourceResolverImpl.java                 | 116 +++++++++++++++++----
 .../impl/ResourceResolverImplTest.java             |  19 ++++
 2 files changed, 116 insertions(+), 19 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
index 2e47747..8653c5a 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
@@ -92,6 +92,9 @@ public class ResourceResolverImpl extends SlingAdaptable 
implements ResourceReso
     /** Resource resolver context. */
     private final ResourceResolverContext context;
 
+    private final Map<StringTupel,Boolean> resourceTypeLookupCache;
+
+
     private volatile Exception closedResolverException;
 
     public ResourceResolverImpl(final CommonResourceResolverFactoryImpl 
factory, final boolean isAdmin, final Map<String, Object> authenticationInfo) 
throws LoginException {
@@ -103,6 +106,7 @@ public class ResourceResolverImpl extends SlingAdaptable 
implements ResourceReso
         this.context = new ResourceResolverContext(this, 
factory.getResourceAccessSecurityTracker());
         this.control = createControl(resourceProviderTracker, 
authenticationInfo, isAdmin);
         this.factory.register(this, control);
+        this.resourceTypeLookupCache = new HashMap<>();
     }
 
     /**
@@ -124,6 +128,7 @@ public class ResourceResolverImpl extends SlingAdaptable 
implements ResourceReso
         this.context = new ResourceResolverContext(this, 
factory.getResourceAccessSecurityTracker());
         this.control = createControl(factory.getResourceProviderTracker(), 
authInfo, resolver.control.isAdmin());
         this.factory.register(this, control);
+        this.resourceTypeLookupCache = new HashMap<>();
     }
 
     /**
@@ -1046,37 +1051,57 @@ public class ResourceResolverImpl extends 
SlingAdaptable implements ResourceReso
     public boolean isResourceType(final Resource resource, final String 
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(), factory.getSearchPath())) {
-                 result = true;
-             } else {
-                 Set<String> superTypesChecked = new HashSet<>();
-                 String superType = this.getParentResourceType(resource);
-                 while (!result && superType != null) {
-                     if (ResourceTypeUtil.areResourceTypesEqual(resourceType, 
superType, factory.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(), null);
-                         }
-                     }
-                 }
+
+             // Check if the result is already available from cache
+             StringTupel key = new 
StringTupel(resource.getResourceType(),resourceType);
+             if (resourceTypeLookupCache.containsKey(key)) {
+                 return resourceTypeLookupCache.get(key);
              }
 
+             // Perform the resolution and store the result in the cache
+             result = isResourceTypeInternal(resource, resourceType);
+             resourceTypeLookupCache.put(key, result);
         }
         return result;
     }
 
     /**
+     * Perform the actual check of the resourceType
+     * @param resource the resource
+     * @param resourceType the resource type to compare to
+     * @return
+     */
+    boolean isResourceTypeInternal(final Resource resource, final String 
resourceType) {
+        boolean result = false;
+        if (ResourceTypeUtil.areResourceTypesEqual(resourceType, 
resource.getResourceType(), factory.getSearchPath())) {
+             // direct match
+             result = true;
+         } else {
+             // iterate the resourcetype hierarchy
+             Set<String> superTypesChecked = new HashSet<>();
+             String superType = this.getParentResourceType(resource);
+             while (!result && superType != null) {
+                 if (ResourceTypeUtil.areResourceTypesEqual(resourceType, 
superType, factory.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(), null);
+                     }
+                 }
+             }
+         }
+        return result;
+    }
+
+    /**
      * @see org.apache.sling.api.resource.ResourceResolver#refresh()
      */
     @Override
     public void refresh() {
         this.control.refresh(this.context);
+        resourceTypeLookupCache.clear();
     }
 
     @Override
@@ -1117,4 +1142,57 @@ public class ResourceResolverImpl extends SlingAdaptable 
implements ResourceReso
         }
         return rsrc;
     }
+
+
+
+    public class StringTupel {
+
+        String resourceType;
+        String resourceSuperType;
+
+        public StringTupel (String rt, String rst) {
+            this.resourceType = rt;
+            this.resourceSuperType = rst;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + getEnclosingInstance().hashCode();
+            result = prime * result + ((resourceSuperType == null) ? 0 : 
resourceSuperType.hashCode());
+            result = prime * result + ((resourceType == null) ? 0 : 
resourceType.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            StringTupel other = (StringTupel) obj;
+            if (!getEnclosingInstance().equals(other.getEnclosingInstance()))
+                return false;
+            if (resourceSuperType == null) {
+                if (other.resourceSuperType != null)
+                    return false;
+            } else if (!resourceSuperType.equals(other.resourceSuperType))
+                return false;
+            if (resourceType == null) {
+                if (other.resourceType != null)
+                    return false;
+            } else if (!resourceType.equals(other.resourceType))
+                return false;
+            return true;
+        }
+
+        private ResourceResolverImpl getEnclosingInstance() {
+            return ResourceResolverImpl.this;
+        }
+    }
+
+
 }
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
index 3eee2cf..933758f 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
@@ -29,6 +29,9 @@ import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import static org.mockito.Mockito.eq;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -57,6 +60,7 @@ import org.apache.sling.spi.resource.provider.ResourceContext;
 import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.mockito.internal.util.reflection.Whitebox;
 import org.osgi.framework.Bundle;
 
@@ -521,6 +525,21 @@ public class ResourceResolverImplTest {
         assertFalse(resolver.isResourceType(r, "h:p"));
     }
 
+    @Test public void testIsResourceTypeCached() {
+        final PathBasedResourceResolverImpl resolver = 
Mockito.spy(getPathBasedResourceResolver());
+        final Resource r1 = resolver.add(new SyntheticResource(resolver, "/a", 
"a:b"));
+
+        // 1st lookup needs to get through, 2nd will be taken from cache
+        assertTrue(resolver.isResourceType(r1, "a:b"));
+        Mockito.verify(resolver, 
Mockito.times(1)).isResourceTypeInternal(eq(r1), eq("a:b"));
+        assertTrue(resolver.isResourceType(r1, "a:b"));
+        Mockito.verify(resolver, 
Mockito.times(1)).isResourceTypeInternal(eq(r1), eq("a:b"));
+
+        resolver.refresh();
+        assertTrue(resolver.isResourceType(r1, "a:b"));
+        Mockito.verify(resolver, 
Mockito.times(2)).isResourceTypeInternal(eq(r1), eq("a:b"));
+    }
+
     @Test public void testIsResourceTypeWithPaths() {
         final PathBasedResourceResolverImpl resolver = 
getPathBasedResourceResolver();
 

Reply via email to