You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by jo...@apache.org on 2022/09/24 17:42:16 UTC
[sling-org-apache-sling-servlets-resolver] 04/05: Reimplement the LocationIterator logic
This is an automated email from the ASF dual-hosted git repository.
joerghoh pushed a commit to branch SLING-11558-remove-iterator
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git
commit 4dc385b1b7d62e65d55b6760db7f238cdda21146
Author: Jörg Hoh <jo...@joerghoh.de>
AuthorDate: Sat Sep 24 19:32:27 2022 +0200
Reimplement the LocationIterator logic
This new logic in the LocationCollector reimplements the logic of the
LocationIterator, but instead of a iterator it returns a simple list;
this makes the whole logic much easier to understand.
Code from the LocationIterator has been re-used 1:1, most notably the
methods "getResourceSuperType". Only some minor renamings have been made
to reflect the changed field names.
---
.../internal/helper/LocationCollector.java | 192 ++++++++++++++++++++-
1 file changed, 183 insertions(+), 9 deletions(-)
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 578137e..a67679a 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,26 +19,200 @@
package org.apache.sling.servlets.resolver.internal.helper;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
+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.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.sling.api.servlets.ServletResolverConstants.DEFAULT_RESOURCE_TYPE;
+
+/**
+ * The <code>LocationCollector</code> provides access to an ordered collection
+ * of absolute paths containing potential request handling. The primary order of
+ * the collection is the resource type hierarchy with the base resource type at
+ * the top. The secondary order is the search path retrieved from the resource
+ * resolver.
+ * <p>
+ * Example: For a node type hierarchy "sample" > "super" > "default" and a
+ * search path of [ "/apps", "/libs" ], the iterator would provide access to the
+ * following list of paths:
+ * <ol>
+ * <li><code>/apps/sample</code></li>
+ * <li><code>/libs/sample</code></li>
+ * <li><code>/apps/super</code></li>
+ * <li><code>/libs/super</code></li>
+ * <li><code>/apps/default</code></li>
+ * <li><code>/libs/default</code></li>
+ * </ol>
+ */
public class LocationCollector {
-
-
+
public static List<String> getLocations(String resourceType, String resourceSuperType, String baseResourceType,
ResourceResolver resolver) {
+ LocationCollector collector = new LocationCollector(resourceType, resourceSuperType, baseResourceType,
+ resolver);
+ return collector.getResolvedLocations();
+ }
+
+ // The search path of the resource resolver
+ private final String[] searchPath;
+
+ private final ResourceResolver resolver;
+ private final String baseResourceType;
+ private final String resourceType;
+ private final String resourceSuperType;
+
+ /** Set of used resource types to detect a circular resource type hierarchy. */
+ private final Set<String> usedResourceTypes = new HashSet<>();
+
+ private List<String> result = new ArrayList<>();
+
+ private LocationCollector(String resourceType, String resourceSuperType, String baseResourceType,
+ ResourceResolver resolver) {
+
+ this.resourceType = resourceType;
+ this.resourceSuperType = resourceSuperType;
+ this.baseResourceType = baseResourceType;
+ this.resolver = resolver;
+
+ String[] tmpPath = resolver.getSearchPath();
+ if (tmpPath.length == 0) {
+ tmpPath = new String[] { "/" };
+ }
+ searchPath = tmpPath;
+ this.usedResourceTypes.add(this.resourceType);
+ collectPaths();
+ }
+
+ private List<String> getResolvedLocations() {
+ return result;
+ }
+
+ /**
+ * Collect all resource types
+ */
+ private void collectPaths() {
- List<String> result = new ArrayList<>();
-
- final Iterator<String> locations = new LocationIterator(resourceType, resourceSuperType,
- baseResourceType, resolver);
+ String rt = this.resourceType;
+ do {
+ String superType = handleResourceType(rt);
+ rt = superType;
+ } while (rt != null);
- while (locations.hasNext()) {
- result.add(locations.next());
+ // add default resourceTypes
+ final String defaultResourceTypeSuffix;
+ boolean blankResourceType = StringUtils.isBlank(resourceType);
+ if (blankResourceType) {
+ defaultResourceTypeSuffix = "";
+ } else {
+ defaultResourceTypeSuffix = this.baseResourceType;
}
- return result;
+ for (String spath : searchPath) {
+ result.add(spath + defaultResourceTypeSuffix);
+ }
+ }
+
+ /**
+ * Add all necessary path entries to the result list, and return the resourceSuperType
+ * for the given resourceType
+ * @param resourceType the resourceType
+ * @return the resourceSuperType or null if the given resourceType does not have a resourceSuperType
+ */
+ @Nullable String handleResourceType (String resourceType) {
+ boolean isBlank = StringUtils.isBlank(resourceType);
+ boolean isAbsoluteResourceType = resourceType.startsWith("/");
+ String resourceSuperType = null;
+ if (!isBlank) {
+ if (isAbsoluteResourceType) {
+ result.add(ResourceUtil.resourceTypeToPath(resourceType));
+ } else {
+ for (String spath : searchPath) {
+ result.add(spath + ResourceUtil.resourceTypeToPath(resourceType));
+ }
+
+ }
+ resourceSuperType = getResourceSuperType(resourceType);
+ }
+ return resourceSuperType;
+ }
+
+
+ /**
+ * Returns the resource super type of the given resource type:
+ * <ol>
+ * <li>If the resource type is the base resource type <code>null</code>
+ * is returned.</li>
+ * <li>If the resource type is the resource type of the resource the
+ * resource super type from the resource is returned.</li>
+ * <li>Otherwise the resource super type is tried to be found in the
+ * resource tree. If one is found, it is returned.</li>
+ * <li>Otherwise the base resource type is returned.</li>
+ * </ol>
+ */
+ private String getResourceSuperType(String resourceType) {
+
+ // if the current resource type is the default value, there are no more
+ if (resourceType.equals(baseResourceType)) {
+ return null;
+ }
+
+ // get the super type of the current resource type
+ String superType = null;
+ if (resourceType.equals(this.resourceType)
+ && this.resourceSuperType != null ) {
+ superType = this.resourceSuperType;
+ } else {
+ superType = getResourceSuperType(resolver, resourceType);
+ }
+
+ // detect circular dependency
+ if ( superType != null ) {
+ if ( this.usedResourceTypes.contains(superType) ) {
+ LoggerFactory.getLogger(this.getClass()).error("Circular dependency in resource type hierarchy detected! Check super types of {}", superType);
+ superType = null;
+ } else {
+ this.usedResourceTypes.add(superType);
+ }
+ }
+ return superType;
}
+ // this method is largely duplicated from ResourceUtil
+ private String getResourceSuperType(final ResourceResolver resourceResolver,
+ final 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 resourceSuperType = null;
+ // if the path is absolute, use it directly
+ if ( rtPath.startsWith("/") ) {
+ final String candidatePath = rtPath;
+
+ final Resource rtResource = resourceResolver.getResource(candidatePath);
+ if ( rtResource != null ) {
+ resourceSuperType = rtResource.getResourceSuperType();
+ }
+
+ } else {
+ // 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);
+ if ( rtResource != null && rtResource.getResourceSuperType() != null ) {
+ resourceSuperType = rtResource.getResourceSuperType();
+ break;
+ }
+ }
+ }
+ return resourceSuperType;
+ }
}