SLING-9671 - Allow non-bundled inheriting resource types to override Use-API templates

* attempt to rely on the resource tree to derive template files; when a file is not
found but the request driver is a BundledRenderUnit do a fallback to the unit's
type providers
diff --git a/src/main/java/org/apache/sling/scripting/sightly/engine/ResourceResolution.java b/src/main/java/org/apache/sling/scripting/sightly/engine/ResourceResolution.java
index 30d6664..41f359c 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/engine/ResourceResolution.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/engine/ResourceResolution.java
@@ -17,11 +17,14 @@
 
 package org.apache.sling.scripting.sightly.engine;
 
+import javax.servlet.Servlet;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.SlingHttpServletRequest;
 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;
 
 /**
  * Utility class which is used by the HTL engine & extensions to resolve resources.
@@ -54,20 +57,20 @@
      * @see ResourceResolver#getSearchPath()
      */
     public static Resource getResourceFromSearchPath(Resource base, String path) {
+        if (base == null || path == null) {
+            return null;
+        }
         if (path.startsWith("/")) {
-            Resource resource = base.getResourceResolver().getResource(path);
+            Resource resource = getScriptResource(base.getResourceResolver(), path);
             if (resource != null) {
                 return searchPathChecked(resource);
             }
-            return null;
         }
-        Resource internalBase = null;
-        if (base != null) {
-            if ("nt:file".equals(base.getResourceType()) || "true".equalsIgnoreCase((String) base.getResourceMetadata().get("sling.servlet.resource"))) {
-                internalBase = retrieveParent(base);
-            } else {
-                internalBase = base;
-            }
+        Resource internalBase;
+        if ("nt:file".equals(base.getResourceType()) || base.adaptTo(Servlet.class) != null) {
+            internalBase = base.getParent();
+        } else {
+            internalBase = base;
         }
         return resolveComponentInternal(internalBase, path);
     }
@@ -83,20 +86,12 @@
      * @return the resource identified by the {@code request} or {@code null} if no resource was found
      */
     public static Resource getResourceForRequest(ResourceResolver resolver, SlingHttpServletRequest request) {
+        if (resolver == null || request == null) {
+            return null;
+        }
         String resourceType = request.getResource().getResourceType();
         if (StringUtils.isNotEmpty(resourceType)) {
-            if (resourceType.startsWith("/")) {
-                return resolver.getResource(resourceType);
-            }
-            for (String searchPath : resolver.getSearchPath()) {
-                String componentPath = ResourceUtil.normalize(searchPath + "/" + resourceType);
-                if (componentPath != null) {
-                    Resource componentResource = resolver.getResource(componentPath);
-                    if (componentResource != null) {
-                        return componentResource;
-                    }
-                }
-            }
+            return getScriptResource(resolver, resourceType);
         }
         return null;
     }
@@ -125,7 +120,15 @@
     private static Resource recursiveResolution(Resource base, String path) {
         ResourceResolver resolver = base.getResourceResolver();
         for (int iteration = 0; iteration < RECURSION_LIMIT; iteration++) {
-            Resource resource = resolver.getResource(base, path);
+            Resource resource = null;
+            if (path.startsWith("/")) {
+                resource = getScriptResource(resolver, path);
+            } else {
+                String normalizedPath = ResourceUtil.normalize(base.getPath() + "/" + path);
+                if (normalizedPath != null) {
+                    resource = getScriptResource(resolver, normalizedPath);
+                }
+            }
             if (resource != null) {
                 return resource;
             }
@@ -167,7 +170,7 @@
         if (superType == null) {
             return null;
         }
-        return resolver.getResource(superType);
+        return getScriptResource(resolver, superType);
     }
 
     private static Resource searchPathChecked(Resource resource) {
@@ -178,11 +181,21 @@
         return resource;
     }
 
-    private static Resource retrieveParent(Resource resource) {
-        String parentPath = ResourceUtil.getParent(resource.getPath());
-        if (parentPath == null) {
-            return null;
-        }
-        return resource.getResourceResolver().getResource(parentPath);
+    private static Resource getScriptResource(@NotNull ResourceResolver resourceResolver, @NotNull String path) {
+         if (path.startsWith("/")) {
+             Resource resource = resourceResolver.resolve(path);
+             if (ResourceUtil.isNonExistingResource(resource)) {
+                 return null;
+             }
+             return resource;
+         } else {
+             for (String searchPath : resourceResolver.getSearchPath()) {
+                 Resource resource = resourceResolver.resolve(searchPath + path);
+                 if (!ResourceUtil.isNonExistingResource(resource)) {
+                     return resource;
+                 }
+             }
+         }
+         return null;
     }
 }
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
index 180cd4c..fe3de7e 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
@@ -49,8 +49,6 @@
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 
 /**
@@ -91,15 +89,16 @@
     public ProviderOutcome provide(String identifier, RenderContext renderContext, Bindings arguments) {
         if (identifier.endsWith("." + SightlyScriptEngineFactory.EXTENSION)) {
             Bindings globalBindings = renderContext.getBindings();
-            RenderUnit renderUnit = bundledUnitManager.getRenderUnit(globalBindings, identifier);
-            if (renderUnit != null) {
-                return ProviderOutcome.success(renderUnit);
-            }
             SlingScriptHelper sling = BindingsUtils.getHelper(globalBindings);
             SlingHttpServletRequest request = BindingsUtils.getRequest(globalBindings);
             final Resource renderUnitResource = ScriptUtils.resolveScript(scriptingResourceResolverProvider
                     .getRequestScopedResourceResolver(), renderContext, identifier);
             if (renderUnitResource == null) {
+                // attempt to find a bundled render unit that does not expose a servlet resource via the search paths
+                RenderUnit renderUnit = bundledUnitManager.getRenderUnit(globalBindings, identifier);
+                if (renderUnit != null) {
+                    return ProviderOutcome.success(renderUnit);
+                }
                 Resource caller = ResourceResolution.getResourceForRequest(request.getResourceResolver(), request);
                 if (caller != null) {
                     String resourceSuperType = caller.getResourceSuperType();
@@ -116,6 +115,13 @@
                 }
             }
             try {
+                if ("true".equalsIgnoreCase((String) renderUnitResource.getResourceMetadata().get("sling.servlet.resource"))) {
+                    // bundled dependency
+                    RenderUnit renderUnit = bundledUnitManager.getRenderUnit(globalBindings, identifier);
+                    if (renderUnit != null) {
+                        return ProviderOutcome.success(renderUnit);
+                    }
+                }
                 CachedScript cachedScript = scriptCache.getScript(renderUnitResource.getPath());
                 final SightlyCompiledScript compiledScript;
                 if (cachedScript != null) {
@@ -146,8 +152,7 @@
                         }
                     });
                 }
-                renderUnit = compiledScript.getRenderUnit();
-                return ProviderOutcome.success(renderUnit);
+                return ProviderOutcome.success(compiledScript.getRenderUnit());
             } catch (Exception e) {
                 return ProviderOutcome.failure(e);
             }
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/utils/ScriptUtils.java b/src/main/java/org/apache/sling/scripting/sightly/impl/utils/ScriptUtils.java
index 49e888c..b6e66a1 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/utils/ScriptUtils.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/utils/ScriptUtils.java
@@ -31,10 +31,8 @@
         Resource result = ResourceResolution.getResourceFromSearchPath(caller, scriptIdentifier);
         if (result == null) {
             SlingScriptHelper sling = BindingsUtils.getHelper(renderContext.getBindings());
-            if (sling.getScript() != null) {
-                caller = resolver.getResource(sling.getScript().getScriptResource().getPath());
-                result = ResourceResolution.getResourceFromSearchPath(caller, scriptIdentifier);
-            }
+            caller = sling.getScript().getScriptResource();
+            result = ResourceResolution.getResourceFromSearchPath(caller, scriptIdentifier);
         }
         return result;
     }