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();