refactoring
* made cache entries reflect the number of protected resource type
* optimised cache queries
diff --git a/pom.xml b/pom.xml
index 521b55f..2ab24de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,6 +46,7 @@
<properties>
<site.jira.version.id>12314287</site.jira.version.id>
<site.javadoc.exclude>**.impl.**</site.javadoc.exclude>
+ <sling.java.version>8</sling.java.version>
</properties>
<build>
diff --git a/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypeExecutionCache.java b/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypeExecutionCache.java
index 4aa6472..290c8ee 100644
--- a/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypeExecutionCache.java
+++ b/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypeExecutionCache.java
@@ -18,9 +18,12 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.engine.impl.request.permissions;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -37,24 +40,47 @@
)
public class ResourceTypeExecutionCache implements ResourceChangeListener, ExternalResourceChangeListener {
- private Map<String, Boolean> preEvaluatedPermissions = new CachingMap(65536);
+ private Map<String, CacheEntry> preEvaluatedPermissions = new CachingMap(65536);
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock readLock = rwl.readLock();
private final Lock writeLock = rwl.writeLock();
+ private static final Set<String> EMPTY = Collections.emptySet();
- public Boolean getCachedPermission(String key) {
+ Set<String> getAllowedUsers(String permission) {
readLock.lock();
try {
- return preEvaluatedPermissions.get(key);
+ CacheEntry entry = preEvaluatedPermissions.get(permission);
+ if (entry != null) {
+ return entry.allowedUsers;
+ }
+ return EMPTY;
} finally {
readLock.unlock();
}
}
- public void setCachedPermission(String key, Boolean value) {
+ Set<String> getDisallowedUsers(String permission) {
+ readLock.lock();
+ try {
+ CacheEntry entry = preEvaluatedPermissions.get(permission);
+ if (entry != null) {
+ return entry.disallowedUsers;
+ }
+ return EMPTY;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ void updateResourceType(String permission, String user, boolean allow) {
writeLock.lock();
try {
- preEvaluatedPermissions.put(key, value);
+ CacheEntry entry = preEvaluatedPermissions.computeIfAbsent(permission, k -> new CacheEntry());
+ if (allow) {
+ entry.allowedUsers.add(user);
+ } else {
+ entry.disallowedUsers.add(user);
+ }
} finally {
writeLock.unlock();
}
@@ -70,7 +96,7 @@
}
}
- private class CachingMap extends LinkedHashMap<String, Boolean> {
+ private class CachingMap extends LinkedHashMap<String, CacheEntry> {
private final int capacity;
@@ -79,8 +105,13 @@
}
@Override
- protected boolean removeEldestEntry(Map.Entry<String, Boolean> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<String, CacheEntry> eldest) {
return size() > capacity;
}
}
+
+ private class CacheEntry {
+ private Set<String> allowedUsers = new HashSet<>();
+ private Set<String> disallowedUsers = new HashSet<>();
+ }
}
diff --git a/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypePermissionEvaluator.java b/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypePermissionEvaluator.java
index 9b33783..9a66fa9 100644
--- a/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypePermissionEvaluator.java
+++ b/src/main/java/org/apache/sling/engine/impl/request/permissions/ResourceTypePermissionEvaluator.java
@@ -18,6 +18,8 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.engine.impl.request.permissions;
+import java.util.Set;
+
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.SlingRequestEvent;
import org.apache.sling.api.request.SlingRequestListener;
@@ -55,32 +57,56 @@
final String userId = request.getResourceResolver().getUserID();
if (userId != null) {
String permissionPath = resourceType.startsWith("/") ? RESOURCE_TYPE_PERMISSIONS + resourceType :
- RESOURCE_TYPE_PERMISSIONS + "/" + resourceType + "/http." + request.getMethod();
- while (!RESOURCE_TYPE_PERMISSIONS.equals(permissionPath)) {
- String cacheKey = userId + ":" + permissionPath;
- Boolean cached = resourceTypeExecutionCache.getCachedPermission(cacheKey);
- if (cached != null) {
- return cached;
- }
- Resource permission = accessedResource.getResourceResolver().getResource(permissionPath);
- if (permission != null) {
- resourceTypeExecutionCache.setCachedPermission(cacheKey, true);
+ RESOURCE_TYPE_PERMISSIONS + "/" + resourceType;
+ String permissionPathWithHttpMethod = permissionPath + "/http." + request.getMethod();
+ while (permissionPath != null && !RESOURCE_TYPE_PERMISSIONS.equals(permissionPath)) {
+
+ Set<String> allowedUsers = resourceTypeExecutionCache.getAllowedUsers(permissionPathWithHttpMethod);
+ if (allowedUsers.contains(userId)) {
return true;
- } else {
- ResourceResolver elevatedResourceResolver = threadLocalResourceResolver.get();
- if (elevatedResourceResolver != null) {
- permission = elevatedResourceResolver.getResource(permissionPath);
- if (permission != null) {
- resourceTypeExecutionCache.setCachedPermission(cacheKey, false);
- return false;
- }
+ }
+ allowedUsers = resourceTypeExecutionCache.getAllowedUsers(permissionPath);
+ if (allowedUsers.contains(userId)) {
+ return true;
+ }
+
+ Set<String> disallowedUsers = resourceTypeExecutionCache.getDisallowedUsers(permissionPathWithHttpMethod);
+ if (disallowedUsers.contains(userId)) {
+ return false;
+ }
+ disallowedUsers = resourceTypeExecutionCache.getDisallowedUsers(permissionPath);
+ if (disallowedUsers.contains(userId)) {
+ return false;
+ }
+
+ Resource permission = accessedResource.getResourceResolver().getResource(permissionPathWithHttpMethod);
+ if (permission != null) {
+ resourceTypeExecutionCache.updateResourceType(permissionPathWithHttpMethod, userId, true);
+ return true;
+ }
+
+ permission = accessedResource.getResourceResolver().getResource(permissionPath);
+ if (permission != null) {
+ resourceTypeExecutionCache.updateResourceType(permissionPath, userId, true);
+ return true;
+ }
+
+ ResourceResolver elevatedResourceResolver = threadLocalResourceResolver.get();
+ if (elevatedResourceResolver != null) {
+ permission = elevatedResourceResolver.getResource(permissionPathWithHttpMethod);
+ if (permission != null) {
+ resourceTypeExecutionCache.updateResourceType(permissionPathWithHttpMethod, userId, false);
+ return false;
+ }
+ permission = elevatedResourceResolver.getResource(permissionPath);
+ if (permission != null) {
+ resourceTypeExecutionCache.updateResourceType(permissionPath, userId, false);
+ return false;
}
}
permissionPath = ResourceUtil.getParent(permissionPath);
}
- resourceTypeExecutionCache.setCachedPermission(userId + ":" + (resourceType.startsWith("/") ?
- RESOURCE_TYPE_PERMISSIONS + resourceType :
- RESOURCE_TYPE_PERMISSIONS + "/" + resourceType + "/http." + request.getMethod()), true);
+ resourceTypeExecutionCache.updateResourceType(permissionPathWithHttpMethod, userId, true);
return true;
}
}