SLING-9406: Add bundled script support to the servlets resolver
diff --git a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledRenderUnit.java b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledRenderUnit.java
new file mode 100644
index 0000000..5cd95b5
--- /dev/null
+++ b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledRenderUnit.java
@@ -0,0 +1,122 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.servlets.resolver.bundle.tracker;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.framework.Bundle;
+
+/**
+ * <p>
+ * A {@code BundledRenderUnit} represents a pre-packaged script or precompiled script that will be executed in order to render a
+ * {@link org.apache.sling.api.SlingHttpServletRequest}.
+ * </p>
+ * <p>
+ * If the current {@link org.apache.sling.api.SlingHttpServletRequest} is served by a {@code BundledRenderUnit}, the
+ * {@code org.apache.sling.scripting.bundle.tracker} will set the {@code BundledRenderUnit} in the {@link javax.script.Bindings} map associated to the request,
+ * under the {@link #VARIABLE} key.
+ * </p>
+ */
+@ProviderType
+public interface BundledRenderUnit {
+
+ /**
+ * The variable available in the {@link javax.script.Bindings} associated to a {@link org.apache.sling.api.SlingHttpServletRequest}
+ * if that request is served by a {@code BundledRenderUnit}.
+ */
+ String VARIABLE = BundledRenderUnit.class.getName();
+
+ /**
+ * In case this {@code BundledRenderUnit} wraps a precompiled script, this method will return an instance of that object.
+ *
+ * @return a precompiled unit, if {@code this} unit wraps a precompiled script; {@code null} otherwise
+ */
+ @Nullable
+ default Object getUnit() {
+ return null;
+ }
+
+ /**
+ * Returns the name of {@code this BundledRenderUnit}. This can be the name of the wrapped script or precompiled script.
+ *
+ * @return the name {@code this BundledRenderUnit}
+ */
+ @NotNull String getName();
+
+ /**
+ * Returns the {@link Bundle} in which the script or precompiled script is packaged. This method can be useful for getting an
+ * instance of the bundle's classloader, when needed to load dependencies at run time. To do so the following code example can help:
+ *
+ * <pre>
+ * Bundle bundle = bundledRenderUnit.getBundle();
+ * Classloader bundleClassloader = bundle.adapt(BundleWiring.class).getClassLoader();
+ * </pre>
+ */
+ @NotNull Bundle getBundle();
+
+ /**
+ * Returns the {@code Set} of {@link TypeProvider}s which are related to this unit.
+ *
+ * @return the set of providers; if the unit doesn't have any inheritance chains, then the set will contain only one {@link
+ * TypeProvider}
+ */
+ @NotNull Set<TypeProvider> getTypeProviders();
+
+ /**
+ * Retrieves an OSGi runtime dependency of the wrapped script identified by the passed {@code className} parameter.
+ *
+ * @param className the fully qualified class name
+ * @param <T> the expected service type
+ * @return an instance of the {@link T} or {@code null}
+ */
+ @Nullable <T> T getService(@NotNull String className);
+
+ /**
+ * Retrieves multiple instances of an OSGi runtime dependency of the wrapped script identified by the passed {@code className}
+ * parameter, filtered according to the passed {@code filter}.
+ *
+ * @param className the fully qualified class name
+ * @param filter a filter expression or {@code null} if all the instances should be returned; for more details about the {@code
+ * filter}'s syntax check {@link org.osgi.framework.BundleContext#getServiceReferences(String, String)}
+ * @param <T> the expected service type
+ * @return an instance of the {@link T} or {@code null}
+ */
+ @Nullable <T> T[] getServices(@NotNull String className, @Nullable String filter);
+
+ /**
+ * Returns the path of this executable in the resource type hierarchy. The path can be relative to the search paths or absolute.
+ *
+ * @return the path of this executable in the resource type hierarchy
+ */
+ @NotNull
+ String getPath();
+
+ /**
+ * This method will execute / evaluate the wrapped script or precompiled script with the given request.
+ *
+ * @throws Exception if the execution leads to an error
+ */
+ void eval(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws Exception;
+}
diff --git a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledScriptFinder.java b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledScriptFinder.java
index 17f11fa..1715481 100644
--- a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledScriptFinder.java
+++ b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/BundledScriptFinder.java
@@ -25,8 +25,8 @@
public interface BundledScriptFinder {
- Executable getScript(Set<TypeProvider> providers, Set<TypeProvider> allProviders);
+ BundledRenderUnit getScript(Set<TypeProvider> providers, Set<TypeProvider> allProviders);
- Executable getScript(@NotNull Bundle bundle, @NotNull String path, @NotNull String scriptEngineName,
+ BundledRenderUnit getScript(@NotNull Bundle bundle, @NotNull String path, @NotNull String scriptEngineName,
@NotNull Set<TypeProvider> providers);
}
diff --git a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/Executable.java b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/Executable.java
deleted file mode 100644
index 207bff4..0000000
--- a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/Executable.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ~ Licensed to the Apache Software Foundation (ASF) under one
- ~ or more contributor license agreements. See the NOTICE file
- ~ distributed with this work for additional information
- ~ regarding copyright ownership. The ASF licenses this file
- ~ to you under the Apache License, Version 2.0 (the
- ~ "License"); you may not use this file except in compliance
- ~ with the License. You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing,
- ~ software distributed under the License is distributed on an
- ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- ~ KIND, either express or implied. See the License for the
- ~ specific language governing permissions and limitations
- ~ under the License.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.servlets.resolver.bundle.tracker;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.jetbrains.annotations.NotNull;
-
-public interface Executable {
-
- /**
- * Returns the path of this executable in the resource type hierarchy. The path can be relative to the search paths or absolute.
- *
- * @return the path of this executable in the resource type hierarchy
- */
- @NotNull
- String getPath();
-
- /**
- * This method will execute / evaluate the wrapped script or precompiled script with the given request.
- *
- * @throws Exception if the execution leads to an error
- */
- void eval(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws Exception;
-}
diff --git a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptServlet.java b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptServlet.java
index f012634..026184b 100644
--- a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptServlet.java
+++ b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptServlet.java
@@ -31,7 +31,7 @@
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.servlets.resolver.bundle.tracker.Executable;
+import org.apache.sling.servlets.resolver.bundle.tracker.BundledRenderUnit;
import org.apache.sling.servlets.resolver.bundle.tracker.TypeProvider;
import org.apache.sling.servlets.resolver.bundle.tracker.internal.request.RequestWrapper;
import org.jetbrains.annotations.NotNull;
@@ -39,11 +39,11 @@
class BundledScriptServlet extends GenericServlet {
private final LinkedHashSet<TypeProvider> wiredTypeProviders;
- private final Executable executable;
+ private final BundledRenderUnit executable;
BundledScriptServlet(@NotNull LinkedHashSet<TypeProvider> wiredTypeProviders,
- @NotNull Executable executable) {
+ @NotNull BundledRenderUnit executable) {
this.wiredTypeProviders = wiredTypeProviders;
this.executable = executable;
}
diff --git a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptTracker.java b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptTracker.java
index 318262d..58bd6ac 100644
--- a/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptTracker.java
+++ b/src/main/java/org/apache/sling/servlets/resolver/bundle/tracker/internal/BundledScriptTracker.java
@@ -48,8 +48,8 @@
import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.servlets.resolver.bundle.tracker.BundledRenderUnit;
import org.apache.sling.servlets.resolver.bundle.tracker.BundledScriptFinder;
-import org.apache.sling.servlets.resolver.bundle.tracker.Executable;
import org.apache.sling.servlets.resolver.bundle.tracker.ResourceType;
import org.apache.sling.servlets.resolver.bundle.tracker.BundledRenderUnitCapability;
import org.apache.sling.servlets.resolver.bundle.tracker.TypeProvider;
@@ -131,7 +131,7 @@
properties.put(ServletResolverConstants.SLING_SERVLET_NAME, BundledScriptServlet.class.getName());
properties.put(Constants.SERVICE_DESCRIPTION, BundledScriptServlet.class.getName() + cap.getAttributes());
BundledRenderUnitCapability bundledRenderUnitCapability = BundledRenderUnitCapabilityImpl.fromBundleCapability(cap);
- Executable executable = null;
+ BundledRenderUnit executable = null;
TypeProvider baseTypeProvider = new TypeProviderImpl(bundledRenderUnitCapability, bundle);
LinkedHashSet<TypeProvider> inheritanceChain = new LinkedHashSet<>();
inheritanceChain.add(baseTypeProvider);
@@ -183,7 +183,7 @@
List<ServiceRegistration<Servlet>> regs = new ArrayList<>();
if (executable != null) {
- Executable finalExecutable = executable;
+ BundledRenderUnit finalExecutable = executable;
bundledRenderUnitCapability.getResourceTypes().forEach(resourceType -> {
if (finalExecutable.getPath().startsWith(resourceType.toString() + "/")) {
properties.put(ServletResolverConstants.SLING_SERVLET_PATHS, finalExecutable.getPath());
diff --git a/src/main/java/org/apache/sling/servlets/resolver/internal/resource/ServletMounter.java b/src/main/java/org/apache/sling/servlets/resolver/internal/resource/ServletMounter.java
index bc772ab..6a112d7 100644
--- a/src/main/java/org/apache/sling/servlets/resolver/internal/resource/ServletMounter.java
+++ b/src/main/java/org/apache/sling/servlets/resolver/internal/resource/ServletMounter.java
@@ -143,16 +143,20 @@
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
target="(|(" + ServletResolverConstants.SLING_SERVLET_PATHS + "=*)(" + ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES + "=*))")
- protected void bindServlet(final Servlet servlet, final ServiceReference<Servlet> reference) {
+ public void bindServlet(final Servlet servlet, final ServiceReference<Servlet> reference) {
if (this.active) {
createServlet(servlet, reference);
}
}
- protected void unbindServlet(final ServiceReference<Servlet> reference) {
+ public void unbindServlet(final ServiceReference<Servlet> reference) {
destroyServlet(reference);
}
+ public boolean mountProviders() {
+ return provider == null;
+ }
+
@Reference(
name = REF_CACHE,
service = ResolutionCache.class,