You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2020/03/27 11:29:31 UTC
[sling-org-apache-sling-scripting-bundle-tracker] branch master
updated: SLING-9255 - Allow servlet resolution based on path
This is an automated email from the ASF dual-hosted git repository.
radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-bundle-tracker.git
The following commit(s) were added to refs/heads/master by this push:
new 2aba608 SLING-9255 - Allow servlet resolution based on path
2aba608 is described below
commit 2aba608350614b09eca65829af0ffbc077fabd73
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Fri Mar 27 12:28:12 2020 +0100
SLING-9255 - Allow servlet resolution based on path
* servlets are also registered by path to allow calls like
data-sly-include, sling:call
* refactored the way inheritance information is generated (n-level
inheritance)
---
.../bundle/tracker/BundledRenderUnit.java | 40 ++----
.../internal/AbstractBundledRenderUnit.java | 51 ++++---
.../tracker/internal/BundledScriptFinder.java | 152 +++++++--------------
.../tracker/internal/BundledScriptServlet.java | 66 +++------
.../tracker/internal/BundledScriptTracker.java | 125 ++++++++---------
.../bundle/tracker/internal/Executable.java | 33 +++++
.../bundle/tracker/internal/PrecompiledScript.java | 41 +++---
.../tracker/internal/ResourceTypeCapability.java | 74 ++++++----
.../scripting/bundle/tracker/internal/Script.java | 14 +-
.../tracker/internal/ScriptContextProvider.java | 43 +++++-
.../bundle/tracker/internal/TypeProvider.java | 37 +++--
11 files changed, 345 insertions(+), 331 deletions(-)
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/BundledRenderUnit.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/BundledRenderUnit.java
index 179a6e1..eda9d58 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/BundledRenderUnit.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/BundledRenderUnit.java
@@ -18,10 +18,6 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.scripting.bundle.tracker;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
@@ -65,14 +61,6 @@ public interface BundledRenderUnit {
@NotNull String getName();
/**
- * Returns an instance of the {@link ScriptEngine} that can execute the wrapped script or precompiled script, if the latter needs a
- * specific runtime.
- *
- * @return an instance of the script's or precompiled script's associated {@link ScriptEngine}
- */
- @NotNull ScriptEngine getScriptEngine();
-
- /**
* 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:
*
@@ -84,31 +72,23 @@ public interface BundledRenderUnit {
@NotNull Bundle getBundle();
/**
- * Provided a {@link ScriptContext}, this method will execute / evaluate the wrapped script or precompiled script.
- *
- * @param context the {@link ScriptContext}
- * @throws ScriptException if the execution leads to an error
- */
- void eval(@NotNull ScriptContext context) throws ScriptException;
-
- /**
* Retrieves an OSGi runtime dependency of the wrapped script identified by the passed {@code className} parameter.
*
- * @param className the fully qualified class name
- * @param <ServiceType> the expected service type
- * @return an instance of the {@link ServiceType} or {@code null}
+ * @param className the fully qualified class name
+ * @param <T> the expected service type
+ * @return an instance of the {@link T} or {@code null}
*/
- @Nullable <ServiceType> ServiceType getService(@NotNull String className);
+ @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 <ServiceType> the expected service type
- * @return an instance of the {@link ServiceType} or {@code null}
+ * @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 <ServiceType> ServiceType[] getServices(@NotNull String className, @Nullable String filter);
+ @Nullable <T> T[] getServices(@NotNull String className, @Nullable String filter);
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/AbstractBundledRenderUnit.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/AbstractBundledRenderUnit.java
index 192934d..b82a4f8 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/AbstractBundledRenderUnit.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/AbstractBundledRenderUnit.java
@@ -40,11 +40,16 @@ abstract class AbstractBundledRenderUnit implements Executable {
private final Bundle bundle;
private final BundleContext bundleContext;
- private List<ServiceReference> references;
+ private final String path;
+ private final String scriptEngineName;
+ private List<ServiceReference<?>> references;
private Map<String, Object> services;
- AbstractBundledRenderUnit(@NotNull Bundle bundle) {
+
+ AbstractBundledRenderUnit(@NotNull Bundle bundle, @NotNull String path, @NotNull String scriptEngineName) {
this.bundle = bundle;
+ this.path = path;
+ this.scriptEngineName = scriptEngineName;
bundleContext = bundle.getBundleContext();
}
@@ -55,15 +60,25 @@ abstract class AbstractBundledRenderUnit implements Executable {
}
@Override
+ public @NotNull String getPath() {
+ return path;
+ }
+
+ @Override
+ public @NotNull String getScriptEngineName() {
+ return scriptEngineName;
+ }
+
+ @Override
@Nullable
@SuppressWarnings("unchecked")
- public <ServiceType> ServiceType getService(@NotNull String className) {
+ public <T> T getService(@NotNull String className) {
LOG.debug("Attempting to load class {} as an OSGi service.", className);
- ServiceType result = (this.services == null ? null : (ServiceType) this.services.get(className));
+ T result = (this.services == null ? null : (T) this.services.get(className));
if (result == null) {
- final ServiceReference ref = this.bundleContext.getServiceReference(className);
+ final ServiceReference<?> ref = this.bundleContext.getServiceReference(className);
if (ref != null) {
- result = (ServiceType) this.bundleContext.getService(ref);
+ result = (T) this.bundleContext.getService(ref);
if (result != null) {
if (this.services == null) {
this.services = new HashMap<>();
@@ -83,21 +98,21 @@ abstract class AbstractBundledRenderUnit implements Executable {
@Override
@Nullable
@SuppressWarnings("unchecked")
- public <ServiceType> ServiceType[] getServices(@NotNull String className, @Nullable String filter) {
- ServiceType[] result = null;
+ public <T> T[] getServices(@NotNull String className, @Nullable String filter) {
+ T[] result = null;
try {
- final ServiceReference[] refs = this.bundleContext.getServiceReferences(className, filter);
+ final ServiceReference<?>[] refs = this.bundleContext.getServiceReferences(className, filter);
if (refs != null) {
// sort by service ranking (lowest first) (see ServiceReference#compareTo(Object))
- List<ServiceReference> references = Arrays.asList(refs);
- Collections.sort(references);
+ List<ServiceReference<?>> localReferences = Arrays.asList(refs);
+ Collections.sort(localReferences);
// get the highest ranking first
- Collections.reverse(references);
+ Collections.reverse(localReferences);
- final List<ServiceType> objects = new ArrayList<>();
- for (ServiceReference reference : references) {
- final ServiceType service = (ServiceType) this.bundleContext.getService(reference);
+ final List<T> objects = new ArrayList<>();
+ for (ServiceReference<?> reference : localReferences) {
+ final T service = (T) this.bundleContext.getService(reference);
if (service != null) {
if (this.references == null) {
this.references = new ArrayList<>();
@@ -106,8 +121,8 @@ abstract class AbstractBundledRenderUnit implements Executable {
objects.add(service);
}
}
- if (objects.size() > 0) {
- ServiceType[] srv = (ServiceType[]) Array.newInstance(bundle.loadClass(className), objects.size());
+ if (!objects.isEmpty()) {
+ T[] srv = (T[]) Array.newInstance(bundle.loadClass(className), objects.size());
result = objects.toArray(srv);
}
}
@@ -120,7 +135,7 @@ abstract class AbstractBundledRenderUnit implements Executable {
@Override
public void releaseDependencies() {
if (references != null) {
- for (ServiceReference reference : this.references) {
+ for (ServiceReference<?> reference : this.references) {
bundleContext.ungetService(reference);
}
references.clear();
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
index bbe9973..42f15e7 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptFinder.java
@@ -22,88 +22,68 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
-
import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.commons.compiler.source.JavaEscapeHelper;
import org.apache.sling.scripting.bundle.tracker.ResourceType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.osgi.framework.Bundle;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Component(
service = BundledScriptFinder.class
)
public class BundledScriptFinder {
- private static final Logger LOGGER = LoggerFactory.getLogger(BundledScriptFinder.class);
private static final String NS_JAVAX_SCRIPT_CAPABILITY = "javax.script";
private static final String SLASH = "/";
private static final String DOT = ".";
- @Reference
- private ScriptEngineManager scriptEngineManager;
-
- Executable getScript(SlingHttpServletRequest request, LinkedHashSet<TypeProvider> typeProviders, boolean precompiledScripts) {
- List<String> scriptMatches;
- for (TypeProvider provider : typeProviders) {
- scriptMatches = buildScriptMatches(request, provider.getResourceTypes());
- String scriptEngineName = getScriptEngineName(request, provider);
- if (StringUtils.isNotEmpty(scriptEngineName)) {
- ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(scriptEngineName);
- if (scriptEngine != null) {
- for (String match : scriptMatches) {
- URL bundledScriptURL;
- List<String> scriptEngineExtensions = getScriptEngineExtensions(scriptEngineName);
- for (String scriptEngineExtension : scriptEngineExtensions) {
- if (precompiledScripts) {
- String className = JavaEscapeHelper.makeJavaPackage(match + DOT + scriptEngineExtension);
- try {
- Class clazz = provider.getBundle().loadClass(className);
- return new PrecompiledScript(provider.getBundle(), scriptEngine,
- clazz.getDeclaredConstructor().newInstance());
- } catch (ClassNotFoundException e) {
- // do nothing here
- } catch (Exception e) {
- throw new IllegalStateException("Cannot correctly instantiate class " + className + ".");
- }
- } else {
- bundledScriptURL =
- provider.getBundle()
- .getEntry(NS_JAVAX_SCRIPT_CAPABILITY + (match.startsWith("/") ? "" : SLASH) + match + DOT + scriptEngineExtension);
- if (bundledScriptURL != null) {
- return new Script(provider.getBundle(), bundledScriptURL, scriptEngine);
- }
- }
- }
+ Executable getScript(Set<TypeProvider> providers) {
+ for (TypeProvider provider : providers) {
+ ResourceTypeCapability capability = provider.getResourceTypeCapability();
+ for (String match : buildScriptMatches(capability.getResourceTypes(),
+ capability.getSelectors().toArray(new String[0]), capability.getMethod(), capability.getExtension())) {
+ String scriptExtension = capability.getScriptExtension();
+ String scriptEngineName = capability.getScriptEngineName();
+ if (StringUtils.isNotEmpty(scriptExtension) && StringUtils.isNotEmpty(scriptEngineName)) {
+ Executable executable =
+ getExecutable(provider.getBundle(), provider.isPrecompiled(), match, scriptEngineName, scriptExtension);
+ if (executable != null) {
+ return executable;
}
- } else {
- LOGGER.error("Cannot find a script engine for short name {}.", scriptEngineName);
}
- } else {
- LOGGER.error("Cannot find a script engine name for {}.", provider);
}
}
return null;
}
- private List<String> buildScriptMatches(SlingHttpServletRequest request, Set<ResourceType> resourceTypes) {
+ @Nullable
+ private Executable getExecutable(@NotNull Bundle bundle, boolean precompiled, @NotNull String match,
+ @NotNull String scriptEngineName, @NotNull String scriptExtension) {
+ String path = match + DOT + scriptExtension;
+ if (precompiled) {
+ String className = JavaEscapeHelper.makeJavaPackage(path);
+ try {
+ Class<?> clazz = bundle.loadClass(className);
+ return new PrecompiledScript(bundle, path, clazz, scriptEngineName);
+ } catch (ClassNotFoundException ignored) {
+ // do nothing here
+ }
+ } else {
+ URL bundledScriptURL = bundle.getEntry(NS_JAVAX_SCRIPT_CAPABILITY + (match.startsWith("/") ? "" : SLASH) + path);
+ if (bundledScriptURL != null) {
+ return new Script(bundle, path, bundledScriptURL, scriptEngineName);
+ }
+ }
+ return null;
+ }
+
+ private List<String> buildScriptMatches(Set<ResourceType> resourceTypes, String[] selectors, String method, String extension) {
List<String> matches = new ArrayList<>();
- String method = request.getMethod();
- String extension = request.getRequestPathInfo().getExtension();
- String[] selectors = request.getRequestPathInfo().getSelectors();
for (ResourceType resourceType : resourceTypes) {
if (selectors.length > 0) {
for (int i = selectors.length - 1; i >= 0; i--) {
@@ -113,10 +93,14 @@ public class BundledScriptFinder {
SLASH) +
String.join(SLASH, Arrays.copyOf(selectors, i + 1));
if (StringUtils.isNotEmpty(extension)) {
- matches.add(base + DOT + extension + DOT + method);
+ if (StringUtils.isNotEmpty(method)) {
+ matches.add(base + DOT + extension + DOT + method);
+ }
matches.add(base + DOT + extension);
}
- matches.add(base + DOT + method);
+ if (StringUtils.isNotEmpty(method)) {
+ matches.add(base + DOT + method);
+ }
matches.add(base);
}
}
@@ -124,56 +108,22 @@ public class BundledScriptFinder {
(StringUtils.isNotEmpty(resourceType.getVersion()) ? SLASH + resourceType.getVersion() : StringUtils.EMPTY);
if (StringUtils.isNotEmpty(extension)) {
- matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + extension + DOT + method);
+ if (StringUtils.isNotEmpty(method)) {
+ matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + extension + DOT + method);
+ }
matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + extension);
}
- matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + method);
+ if (StringUtils.isNotEmpty(method)) {
+ matches.add(base + SLASH + resourceType.getResourceLabel() + DOT + method);
+ }
matches.add(base + SLASH + resourceType.getResourceLabel());
- matches.add(base + SLASH + method);
+ if (StringUtils.isNotEmpty(method)) {
+ matches.add(base + SLASH + method);
+ }
if (StringUtils.isNotEmpty(extension)) {
matches.add(base + SLASH + extension);
}
}
return Collections.unmodifiableList(matches);
}
-
- private String getScriptEngineName(SlingHttpServletRequest request, TypeProvider typeProvider) {
- String scriptEngineName = null;
- Bundle bundle = typeProvider.getBundle();
- BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
- List<BundleCapability> capabilities = bundleWiring.getCapabilities(BundledScriptTracker.NS_SLING_RESOURCE_TYPE);
- String[] selectors = request.getRequestPathInfo().getSelectors();
- String requestExtension = request.getRequestPathInfo().getExtension();
- String requestMethod = request.getMethod();
- for (BundleCapability capability : capabilities) {
- ResourceTypeCapability resourceTypeCapability = ResourceTypeCapability.fromBundleCapability(capability);
- for (ResourceType resourceType : typeProvider.getResourceTypes()) {
- if (
- resourceTypeCapability.getResourceTypes().contains(resourceType) &&
- Arrays.equals(selectors, resourceTypeCapability.getSelectors().toArray()) &&
- ((resourceTypeCapability.getExtensions().isEmpty() && "html".equals(requestExtension)) ||
- resourceTypeCapability.getExtensions().contains(requestExtension)) &&
- ((resourceTypeCapability.getMethods().isEmpty() &&
- ("GET".equals(requestMethod) || "HEAD".equals(requestMethod))) ||
- resourceTypeCapability.getMethods().contains(requestMethod))
- ) {
- scriptEngineName = resourceTypeCapability.getScriptEngineName();
- if (scriptEngineName != null) {
- break;
- }
- }
- }
- }
- return scriptEngineName;
- }
-
- private List<String> getScriptEngineExtensions(String scriptEngineName) {
- for (ScriptEngineFactory factory : scriptEngineManager.getEngineFactories()) {
- Set<String> factoryNames = new HashSet<>(factory.getNames());
- if (factoryNames.contains(scriptEngineName)) {
- return factory.getExtensions();
- }
- }
- return Collections.emptyList();
- }
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptServlet.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptServlet.java
index 0516ece..e053a58 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptServlet.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptServlet.java
@@ -21,46 +21,33 @@ package org.apache.sling.scripting.bundle.tracker.internal;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashSet;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
-import javax.script.Bindings;
-import javax.script.ScriptContext;
import javax.script.ScriptException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.request.RequestPathInfo;
-import org.apache.sling.api.scripting.ScriptEvaluationException;
-import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.scripting.core.ScriptHelper;
+import org.jetbrains.annotations.NotNull;
class BundledScriptServlet extends GenericServlet {
- private final BundledScriptFinder m_bundledScriptFinder;
- private final ScriptContextProvider m_scriptContextProvider;
- private final LinkedHashSet<TypeProvider> m_wiredTypeProviders;
- private final boolean m_precompiledScripts;
+ private final ScriptContextProvider scriptContextProvider;
+ private final LinkedHashSet<TypeProvider> wiredTypeProviders;
+ private final Executable executable;
- private ConcurrentMap<String, Optional<Executable>> scriptsMap = new ConcurrentHashMap<>();
-
-
- BundledScriptServlet(BundledScriptFinder bundledScriptFinder, ScriptContextProvider scriptContextProvider,
- LinkedHashSet<TypeProvider> wiredTypeProviders, boolean precompiledScripts) {
- m_bundledScriptFinder = bundledScriptFinder;
- m_scriptContextProvider = scriptContextProvider;
- m_wiredTypeProviders = wiredTypeProviders;
- m_precompiledScripts = precompiledScripts;
+ BundledScriptServlet(@NotNull ScriptContextProvider scriptContextProvider,
+ @NotNull LinkedHashSet<TypeProvider> wiredTypeProviders,
+ @NotNull Executable executable) {
+ this.scriptContextProvider = scriptContextProvider;
+ this.wiredTypeProviders = wiredTypeProviders;
+ this.executable = executable;
}
@Override
@@ -79,40 +66,21 @@ class BundledScriptServlet extends GenericServlet {
}
}
- String scriptsMapKey = getScriptsMapKey(request);
- Executable executable = scriptsMap.computeIfAbsent(scriptsMapKey,
- key -> Optional.ofNullable(m_bundledScriptFinder.getScript(request, m_wiredTypeProviders, m_precompiledScripts))
- ).orElseThrow(() -> new ServletException("Unable to locate a " + (m_precompiledScripts ? "class" : "script") + " for rendering."));
-
RequestWrapper requestWrapper = new RequestWrapper(request,
- m_wiredTypeProviders.stream().map(TypeProvider::getResourceTypes).flatMap(Collection::stream).collect(Collectors.toSet()));
- ScriptContext scriptContext = m_scriptContextProvider.prepareScriptContext(requestWrapper, response, executable);
+ wiredTypeProviders.stream().map(typeProvider -> typeProvider.getResourceTypeCapability().getResourceTypes()
+ ).flatMap(Collection::stream).collect(Collectors.toSet()));
+ ScriptContextProvider.ExecutableContext executableContext = scriptContextProvider
+ .prepareScriptContext(requestWrapper, response, executable);
try {
- executable.eval(scriptContext);
+ executableContext.eval();
} catch (ScriptException se) {
Throwable cause = (se.getCause() == null) ? se : se.getCause();
- throw new ScriptEvaluationException(executable.getName(), se.getMessage(), cause);
+ throw new ServletException(String.format("Failed executing script %s: %s", executable.getName(), se.getMessage()), cause);
} finally {
- Bindings engineBindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
- if (engineBindings != null && engineBindings.containsKey(SlingBindings.SLING)) {
- Object scriptHelper = engineBindings.get(SlingBindings.SLING);
- if (scriptHelper instanceof ScriptHelper) {
- ((ScriptHelper) scriptHelper).cleanup();
- }
- }
- executable.releaseDependencies();
+ executableContext.clean();
}
} else {
throw new ServletException("Not a Sling HTTP request/response");
}
}
-
- private String getScriptsMapKey(SlingHttpServletRequest request) {
- RequestPathInfo requestPathInfo = request.getRequestPathInfo();
- String selectorString = requestPathInfo.getSelectorString();
- String requestExtension = requestPathInfo.getExtension();
- return request.getMethod() + ":" + request.getResource().getResourceType() +
- (StringUtils.isNotEmpty(selectorString) ? ":" + selectorString : "") +
- (StringUtils.isNotEmpty(requestExtension) ? ":" + requestExtension : "");
- }
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
index 540efde..9006823 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
@@ -50,6 +50,7 @@ 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.scripting.bundle.tracker.ResourceType;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.bundle.Capability;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -88,6 +89,7 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
private static final String REGISTERING_BUNDLE = "org.apache.sling.scripting.bundle.tracker.internal.BundledScriptTracker.registering_bundle";
static final String AT_VERSION = "version";
static final String AT_SCRIPT_ENGINE = "scriptEngine";
+ static final String AT_SCRIPT_EXTENSION = "scriptExtension";
static final String AT_EXTENDS = "extends";
@Reference
@@ -121,7 +123,6 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
LOGGER.debug("Inspecting bundle {} for {} capability.", bundle.getSymbolicName(), NS_SLING_RESOURCE_TYPE);
List<BundleCapability> capabilities = bundleWiring.getCapabilities(NS_SLING_RESOURCE_TYPE);
if (!capabilities.isEmpty()) {
- boolean precompiled = Boolean.parseBoolean(bundle.getHeaders().get("Sling-ResourceType-Precompiled"));
List<ServiceRegistration<Servlet>> serviceRegistrations = capabilities.stream().flatMap(cap ->
{
Hashtable<String, Object> properties = new Hashtable<>();
@@ -135,55 +136,48 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
}
properties.put(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES, resourceTypesRegistrationValue);
- Set<String> extensions = new HashSet<>(resourceTypeCapability.getExtensions());
- if (extensions.isEmpty()) {
- extensions.add("html");
+ String extension = resourceTypeCapability.getExtension();
+ if (StringUtils.isEmpty(extension)) {
+ extension = "html";
}
- properties.put(ServletResolverConstants.SLING_SERVLET_EXTENSIONS, extensions.toArray());
+ properties.put(ServletResolverConstants.SLING_SERVLET_EXTENSIONS, extension);
if (!resourceTypeCapability.getSelectors().isEmpty()) {
properties.put(ServletResolverConstants.SLING_SERVLET_SELECTORS, resourceTypeCapability.getSelectors().toArray());
}
- if (!resourceTypeCapability.getMethods().isEmpty()) {
- properties.put(ServletResolverConstants.SLING_SERVLET_METHODS, resourceTypeCapability.getMethods().toArray());
+ if (StringUtils.isNotEmpty(resourceTypeCapability.getMethod())) {
+ properties.put(ServletResolverConstants.SLING_SERVLET_METHODS, resourceTypeCapability.getMethod());
}
List<ServiceRegistration<Servlet>> regs = new ArrayList<>();
LinkedHashSet<TypeProvider> wiredProviders = new LinkedHashSet<>();
- wiredProviders.add(new TypeProvider(resourceTypeCapability.getResourceTypes(), bundle));
+ wiredProviders.add(new TypeProvider(resourceTypeCapability, bundle));
String extendedResourceTypeString = resourceTypeCapability.getExtendedResourceType();
if (StringUtils.isNotEmpty(extendedResourceTypeString)) {
- Bundle providingBundle = null;
- ResourceType extendedResourceType = null;
- ResourceTypeCapability extendedCapability = null;
- for (BundleWire wire : bundleWiring.getRequiredWires(NS_SLING_RESOURCE_TYPE)) {
- ResourceTypeCapability wiredCapability =
- ResourceTypeCapability.fromBundleCapability(wire.getCapability());
- for (ResourceType resourceType : wiredCapability.getResourceTypes()) {
- if (extendedResourceTypeString.equals(resourceType.getType()) && wiredCapability.getSelectors().isEmpty()) {
- providingBundle = wire.getProvider().getBundle();
- extendedCapability = wiredCapability;
- extendedResourceType = resourceType;
- LOGGER.debug("Bundle {} extends resource type {} through {}.", bundle.getSymbolicName(),
- extendedResourceType.toString(), resourceTypesRegistrationValue);
- break;
+ collectProvidersChain(wiredProviders, bundleWiring, extendedResourceTypeString);
+ wiredProviders.stream().filter(typeProvider -> typeProvider.getResourceTypeCapability().getResourceTypes().stream().anyMatch(resourceType -> resourceType.getType().equals(extendedResourceTypeString))).findFirst().ifPresent(typeProvider -> {
+ for (ResourceType type : typeProvider.getResourceTypeCapability().getResourceTypes()) {
+ if (type.getType().equals(extendedResourceTypeString)) {
+ properties.put(ServletResolverConstants.SLING_SERVLET_RESOURCE_SUPER_TYPE, type.toString());
}
}
- }
- if (providingBundle != null) {
- wiredProviders.add(new TypeProvider(extendedCapability.getResourceTypes(), providingBundle));
- properties.put(ServletResolverConstants.SLING_SERVLET_RESOURCE_SUPER_TYPE, extendedResourceType.toString());
- }
+ });
+ }
+ Executable executable = bundledScriptFinder.getScript(wiredProviders);
+ if (executable != null) {
+ properties.put(ServletResolverConstants.SLING_SERVLET_PATHS, executable.getPath());
+ regs.add(
+ bundle.getBundleContext().registerService(
+ Servlet.class,
+ new BundledScriptServlet(scriptContextProvider, wiredProviders, executable),
+ properties
+ )
+ );
+ } else {
+ LOGGER.error(String.format("Unable to locate an executable for capability %s.", cap));
}
- populateWiredProviders(wiredProviders);
- regs.add(
- bundle.getBundleContext().registerService(
- Servlet.class,
- new BundledScriptServlet(bundledScriptFinder, scriptContextProvider, wiredProviders, precompiled),
- properties
- )
- );
+
return regs.stream();
}).collect(Collectors.toList());
refreshDispatcher(serviceRegistrations);
@@ -196,34 +190,6 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
}
}
-
- private void populateWiredProviders(LinkedHashSet<TypeProvider> initialProviders) {
- Set<ResourceType> initialResourceTypes = new HashSet<>();
- Set<Bundle> bundles = new HashSet<>(initialProviders.size());
- initialProviders.forEach(typeProvider -> {
- initialResourceTypes.addAll(typeProvider.getResourceTypes());
- bundles.add(typeProvider.getBundle());
- });
- for (Bundle bundle : bundles) {
- BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
- bundleWiring.getRequiredWires(BundledScriptTracker.NS_SLING_RESOURCE_TYPE).forEach(
- bundleWire ->
- {
- ResourceTypeCapability wiredCapability = ResourceTypeCapability.fromBundleCapability(bundleWire.getCapability());
- Set<ResourceType> wiredResourceTypes = new HashSet<>();
- for (ResourceType capabilityRT : wiredCapability.getResourceTypes()) {
- if (!initialResourceTypes.contains(capabilityRT)) {
- wiredResourceTypes.add(capabilityRT);
- }
- }
- if (!wiredResourceTypes.isEmpty()) {
- initialProviders.add(new TypeProvider(wiredResourceTypes, bundleWire.getProvider().getBundle()));
- }
- }
- );
- }
- }
-
private void refreshDispatcher(List<ServiceRegistration<Servlet>> regs) {
Map<Set<String>, ServiceRegistration<Servlet>> dispatchers = new HashMap<>();
Stream.concat(m_tracker.getTracked().values().stream(), Stream.of(regs)).flatMap(List::stream)
@@ -317,8 +283,7 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
Optional<ServiceRegistration<Servlet>> target = m_tracker.getTracked().values().stream().flatMap(List::stream)
.filter(
- ((Predicate<ServiceRegistration<Servlet>>) reg -> reg.getReference().getBundle().equals(m_context.getBundle()))
- .negate()
+ reg -> !reg.getReference().getBundle().equals(m_context.getBundle())
)
.filter(reg -> getResourceTypeVersion(reg.getReference()) != null)
.filter(reg ->
@@ -399,4 +364,34 @@ public class BundledScriptTracker implements BundleTrackerCustomizer<List<Servic
}
return resourceTypes;
}
+
+ private void collectProvidersChain(@NotNull Set<TypeProvider> providers, @NotNull BundleWiring wiring,
+ @NotNull String extendedResourceType) {
+ for (BundleWire wire : wiring.getRequiredWires(NS_SLING_RESOURCE_TYPE)) {
+ ResourceTypeCapability wiredCapability = ResourceTypeCapability.fromBundleCapability(wire.getCapability());
+ if (wiredCapability.getSelectors().isEmpty()) {
+ for (ResourceType resourceType : wiredCapability.getResourceTypes()) {
+ if (extendedResourceType.equals(resourceType.getType())) {
+ Bundle providingBundle = wire.getProvider().getBundle();
+ providers.add(new TypeProvider(wiredCapability, providingBundle));
+ for (BundleWire providedWire : wire.getProvider().getWiring().getRequiredWires(NS_SLING_RESOURCE_TYPE)) {
+ ResourceTypeCapability resourceTypeCapability =
+ ResourceTypeCapability.fromBundleCapability(providedWire.getCapability());
+ String capabilityExtends = resourceTypeCapability.getExtendedResourceType();
+ if (resourceTypeCapability.getSelectors().isEmpty() && StringUtils.isNotEmpty(capabilityExtends)) {
+ for (ResourceType providedResourceType : resourceTypeCapability.getResourceTypes()) {
+ if (providedResourceType.getType().equals(extendedResourceType)) {
+ collectProvidersChain(providers, providedWire.getProvider()
+ .getBundle().adapt(BundleWiring.class), capabilityExtends);
+ }
+ }
+ } else {
+ providers.add(new TypeProvider(resourceTypeCapability, providedWire.getProvider().getBundle()));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Executable.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Executable.java
index e9a1b79..8797103 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Executable.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Executable.java
@@ -18,10 +18,43 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.scripting.bundle.tracker.internal;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
import org.apache.sling.scripting.bundle.tracker.BundledRenderUnit;
+import org.jetbrains.annotations.NotNull;
interface Executable extends BundledRenderUnit {
+ /**
+ * Releases all acquired dependencies which were retrieved through {@link #getService(String)} or {@link #getServices(String, String)}.
+ */
void releaseDependencies();
+ /**
+ * 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();
+
+ /**
+ * Returns the short name of the {@link ScriptEngine} with which {@code this Executable} can be evaluated.
+ *
+ * @return the short name of the script engine
+ * @see #eval(ScriptEngine, ScriptContext)
+ */
+ @NotNull String getScriptEngineName();
+
+ /**
+ * Provided a {@link ScriptContext}, this method will execute / evaluate the wrapped script or precompiled script.
+ *
+ * @param scriptEngine a suitable script engine; see {@link #getScriptEngineName()} in order to see what {@link ScriptEngine}
+ * implementation is expected
+ * @param context the {@link ScriptContext}
+ * @throws ScriptException if the execution leads to an error
+ */
+ void eval(@NotNull ScriptEngine scriptEngine, @NotNull ScriptContext context) throws ScriptException;
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/PrecompiledScript.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/PrecompiledScript.java
index caec607..565e3ce 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/PrecompiledScript.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/PrecompiledScript.java
@@ -25,43 +25,48 @@ import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.api.scripting.SlingScriptConstants;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.osgi.framework.Bundle;
public class PrecompiledScript extends AbstractBundledRenderUnit {
private static final StringReader EMPTY_READER = new StringReader(StringUtils.EMPTY);
+ private final Class<?> clazz;
+ private volatile Object instance;
- private final ScriptEngine scriptEngine;
- private final Object precompiledScript;
-
- PrecompiledScript(@NotNull Bundle bundle, @NotNull ScriptEngine scriptEngine, @NotNull Object precompiledScript) {
- super(bundle);
- this.scriptEngine = scriptEngine;
- this.precompiledScript = precompiledScript;
+ PrecompiledScript(@NotNull Bundle bundle, @NotNull String path, @NotNull Class<?> clazz, @NotNull String scriptEngineName) {
+ super(bundle, path, scriptEngineName);
+ this.clazz = clazz;
}
@Override
@NotNull
public String getName() {
- return precompiledScript.getClass().getName();
- }
-
- @Override
- @NotNull
- public ScriptEngine getScriptEngine() {
- return scriptEngine;
+ return clazz.getName();
}
@Override
- public void eval(@NotNull ScriptContext context) throws ScriptException {
+ public void eval(@NotNull ScriptEngine scriptEngine, @NotNull ScriptContext context) throws ScriptException {
scriptEngine.eval(EMPTY_READER, context);
}
@Override
public @NotNull Object getUnit() {
- return precompiledScript;
+ Object localInstance = instance;
+ if (localInstance == null) {
+ synchronized (this) {
+ localInstance = instance;
+ if (localInstance == null) {
+ try {
+ localInstance = clazz.getDeclaredConstructor().newInstance();
+ instance = localInstance;
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot instantiate class " + clazz.getName(), e);
+ }
+ }
+ }
+ }
+ return localInstance;
}
+
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeCapability.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeCapability.java
index 9648dc1..756750c 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeCapability.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ResourceTypeCapability.java
@@ -21,7 +21,9 @@ package org.apache.sling.scripting.bundle.tracker.internal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import org.apache.sling.api.servlets.ServletResolverConstants;
@@ -35,21 +37,24 @@ import org.osgi.framework.wiring.BundleCapability;
class ResourceTypeCapability {
private final Set<ResourceType> resourceTypes;
- private final Set<String> selectors;
- private final Set<String> extensions;
- private final Set<String> methods;
+ private final List<String> selectors;
+ private final String extension;
+ private final String method;
private final String extendedResourceType;
private final String scriptEngineName;
+ private final String scriptExtension;
- private ResourceTypeCapability(@NotNull Set<ResourceType> resourceTypes, @NotNull Set<String> selectors,
- @NotNull Set<String> extensions, @NotNull Set<String> methods,
- @Nullable String extendedResourceType, @Nullable String scriptEngineName) {
+ private ResourceTypeCapability(@NotNull Set<ResourceType> resourceTypes, @NotNull List<String> selectors,
+ @Nullable String extension, @Nullable String method,
+ @Nullable String extendedResourceType, @Nullable String scriptEngineName,
+ @Nullable String scriptExtension) {
this.resourceTypes = resourceTypes;
this.selectors = selectors;
- this.extensions = extensions;
- this.methods = methods;
+ this.extension = extension;
+ this.method = method;
this.extendedResourceType = extendedResourceType;
this.scriptEngineName = scriptEngineName;
+ this.scriptExtension = scriptExtension;
}
@NotNull
@@ -58,13 +63,13 @@ class ResourceTypeCapability {
}
@NotNull
- Set<String> getSelectors() {
- return Collections.unmodifiableSet(selectors);
+ List<String> getSelectors() {
+ return Collections.unmodifiableList(selectors);
}
- @NotNull
- Set<String> getExtensions() {
- return Collections.unmodifiableSet(extensions);
+ @Nullable
+ String getExtension() {
+ return extension;
}
@Nullable
@@ -72,9 +77,9 @@ class ResourceTypeCapability {
return extendedResourceType;
}
- @NotNull
- Set<String> getMethods() {
- return Collections.unmodifiableSet(methods);
+ @Nullable
+ String getMethod() {
+ return method;
}
@Nullable
@@ -82,6 +87,31 @@ class ResourceTypeCapability {
return scriptEngineName;
}
+ @Nullable
+ String getScriptExtension() {
+ return scriptExtension;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(resourceTypes, selectors, extension, method, extendedResourceType, scriptEngineName, scriptExtension);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ResourceTypeCapability) {
+ ResourceTypeCapability other = (ResourceTypeCapability) obj;
+ return Objects.equals(resourceTypes, other.resourceTypes) && Objects.equals(selectors, other.selectors) &&
+ Objects.equals(extension, other.extension) && Objects.equals(method, other.method) &&
+ Objects.equals(extendedResourceType, other.extendedResourceType) &&
+ Objects.equals(scriptEngineName, other.scriptEngineName) && Objects.equals(scriptExtension, other.scriptExtension);
+ }
+ return false;
+ }
+
static ResourceTypeCapability fromBundleCapability(@NotNull BundleCapability capability) {
Map<String, Object> attributes = capability.getAttributes();
Set<ResourceType> resourceTypes = new HashSet<>();
@@ -97,14 +127,12 @@ class ResourceTypeCapability {
}
return new ResourceTypeCapability(
resourceTypes,
- new HashSet<>(Arrays.asList(
- PropertiesUtil.toStringArray(attributes.get(BundledScriptTracker.AT_SLING_SELECTORS), new String[0]))),
- new HashSet<>(Arrays.asList(PropertiesUtil.toStringArray(attributes.get(BundledScriptTracker.AT_SLING_EXTENSIONS),
- new String[0]))),
- new HashSet<>(Arrays.asList(
- PropertiesUtil.toStringArray(attributes.get(ServletResolverConstants.SLING_SERVLET_METHODS), new String[0]))),
+ Arrays.asList(PropertiesUtil.toStringArray(attributes.get(BundledScriptTracker.AT_SLING_SELECTORS), new String[0])),
+ (String) attributes.get(BundledScriptTracker.AT_SLING_EXTENSIONS),
+ (String) attributes.get(ServletResolverConstants.SLING_SERVLET_METHODS),
(String) attributes.get(BundledScriptTracker.AT_EXTENDS),
- (String) attributes.get(BundledScriptTracker.AT_SCRIPT_ENGINE)
+ (String) attributes.get(BundledScriptTracker.AT_SCRIPT_ENGINE),
+ (String) attributes.get(BundledScriptTracker.AT_SCRIPT_EXTENSION)
);
}
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Script.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Script.java
index b752f49..ed20fbc 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Script.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/Script.java
@@ -39,17 +39,15 @@ import org.osgi.framework.Bundle;
class Script extends AbstractBundledRenderUnit {
private final URL url;
- private final ScriptEngine scriptEngine;
private String sourceCode;
private CompiledScript compiledScript = null;
private Lock compilationLock = new ReentrantLock();
private Lock readLock = new ReentrantLock();
- Script(Bundle bundle, URL url, ScriptEngine scriptEngine) {
- super(bundle);
+ Script(@NotNull Bundle bundle, @NotNull String path, @NotNull URL url, @NotNull String scriptEngineName) {
+ super(bundle, path, scriptEngineName);
this.url = url;
- this.scriptEngine = scriptEngine;
}
private String getSourceCode() throws IOException {
@@ -72,14 +70,8 @@ class Script extends AbstractBundledRenderUnit {
return url.getPath();
}
- @NotNull
- @Override
- public ScriptEngine getScriptEngine() {
- return scriptEngine;
- }
-
@Override
- public void eval(@NotNull ScriptContext context) throws ScriptException {
+ public void eval(@NotNull ScriptEngine scriptEngine, @NotNull ScriptContext context) throws ScriptException {
try {
if (scriptEngine instanceof Compilable && compiledScript == null) {
compilationLock.lock();
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ScriptContextProvider.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ScriptContextProvider.java
index 3ab0ffd..5607669 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ScriptContextProvider.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/ScriptContextProvider.java
@@ -29,6 +29,8 @@ import java.util.Set;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
import javax.script.SimpleBindings;
import org.apache.sling.api.SlingHttpServletRequest;
@@ -68,10 +70,18 @@ public class ScriptContextProvider {
private BindingsValuesProvidersByContext bvpTracker;
@Reference
+ private ScriptEngineManager scriptEngineManager;
+
+ @Reference
private ScriptingResourceResolverProvider scriptingResourceResolverProvider;
- ScriptContext prepareScriptContext(SlingHttpServletRequest request, SlingHttpServletResponse response, Executable executable)
+ ExecutableContext prepareScriptContext(SlingHttpServletRequest request, SlingHttpServletResponse response, Executable executable)
throws IOException {
+ ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(executable.getScriptEngineName());
+ if (scriptEngine == null) {
+ throw new IllegalStateException(String.format("Cannot find a script engine with name %s for executable %s.",
+ executable.getScriptEngineName(), executable.getPath()));
+ }
// prepare the SlingBindings
Bindings bindings = new SimpleBindings();
bindings.put("properties", request.getResource().getValueMap());
@@ -89,7 +99,7 @@ public class ScriptContextProvider {
bindings.put(ScriptEngine.FILENAME.replaceAll("\\.", "_"), executable.getName());
ProtectedBindings protectedBindings = new ProtectedBindings(bindings, PROTECTED_BINDINGS);
- for (BindingsValuesProvider bindingsValuesProvider : bvpTracker.getBindingsValuesProviders(executable.getScriptEngine().getFactory(),
+ for (BindingsValuesProvider bindingsValuesProvider : bvpTracker.getBindingsValuesProviders(scriptEngine.getFactory(),
BindingsValuesProvider.DEFAULT_CONTEXT)) {
bindingsValuesProvider.addBindings(protectedBindings);
}
@@ -103,7 +113,34 @@ public class ScriptContextProvider {
scriptContext.setWriter(response.getWriter());
scriptContext.setErrorWriter(new LogWriter(scriptLogger));
scriptContext.setReader(request.getReader());
- return scriptContext;
+ return new ExecutableContext(scriptContext, executable, scriptEngine);
+ }
+
+ static class ExecutableContext {
+ private final ScriptContext scriptContext;
+ private final Executable executable;
+ private final ScriptEngine scriptEngine;
+
+ private ExecutableContext(ScriptContext scriptContext, Executable executable, ScriptEngine scriptEngine) {
+ this.scriptContext = scriptContext;
+ this.executable = executable;
+ this.scriptEngine = scriptEngine;
+ }
+
+ void eval() throws ScriptException {
+ executable.eval(scriptEngine, scriptContext);
+ }
+
+ void clean() {
+ Bindings engineBindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
+ if (engineBindings != null && engineBindings.containsKey(SlingBindings.SLING)) {
+ Object scriptHelper = engineBindings.get(SlingBindings.SLING);
+ if (scriptHelper instanceof ScriptHelper) {
+ ((ScriptHelper) scriptHelper).cleanup();
+ }
+ }
+ executable.releaseDependencies();
+ }
}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/TypeProvider.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/TypeProvider.java
index c8cda53..daa4bdf 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/TypeProvider.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/TypeProvider.java
@@ -19,9 +19,7 @@
package org.apache.sling.scripting.bundle.tracker.internal;
import java.util.Objects;
-import java.util.Set;
-import org.apache.sling.scripting.bundle.tracker.ResourceType;
import org.osgi.framework.Bundle;
/**
@@ -29,27 +27,29 @@ import org.osgi.framework.Bundle;
*/
public class TypeProvider {
- private final Set<ResourceType> resourceTypes;
+ private final ResourceTypeCapability resourceTypeCapability;
private final Bundle bundle;
+ private final boolean precompiled;
/**
* Builds a {@code TypeProvider}.
*
- * @param resourceTypes the resource type
+ * @param resourceTypeCapability the resource type capability
* @param bundle the bundle that provides the resource type
*/
- TypeProvider(Set<ResourceType> resourceTypes, Bundle bundle) {
- this.resourceTypes = resourceTypes;
+ TypeProvider(ResourceTypeCapability resourceTypeCapability, Bundle bundle) {
+ this.resourceTypeCapability = resourceTypeCapability;
this.bundle = bundle;
+ precompiled = Boolean.parseBoolean(bundle.getHeaders().get("Sling-ResourceType-Precompiled"));
}
/**
- * Returns the resource type.
+ * Returns the resource type capabilities.
*
- * @return the resource type
+ * @return the resource type capabilities
*/
- Set<ResourceType> getResourceTypes() {
- return resourceTypes;
+ ResourceTypeCapability getResourceTypeCapability() {
+ return resourceTypeCapability;
}
/**
@@ -61,9 +61,18 @@ public class TypeProvider {
return bundle;
}
+ /**
+ * Returns {@code true} if the bundle provides precompiled scripts.
+ *
+ * @return {@code true} if the bundle provides precompiled scripts, {@code false} otherwise
+ */
+ public boolean isPrecompiled() {
+ return precompiled;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(bundle, resourceTypes);
+ return Objects.hash(bundle, resourceTypeCapability, precompiled);
}
@Override
@@ -73,13 +82,15 @@ public class TypeProvider {
}
if (obj instanceof TypeProvider) {
TypeProvider other = (TypeProvider) obj;
- return Objects.equals(bundle, other.bundle) && Objects.equals(resourceTypes, other.resourceTypes);
+ return Objects.equals(bundle, other.bundle) && Objects.equals(resourceTypeCapability, other.resourceTypeCapability) &&
+ Objects.equals(precompiled, other.precompiled);
}
return false;
}
@Override
public String toString() {
- return String.format("TypeProvider{ resourceTypes=%s; bundle=%s }", resourceTypes, bundle.getSymbolicName());
+ return String.format("TypeProvider{ resourceTypeCapability=%s; bundle=%s; precompiled=%s }", resourceTypeCapability,
+ bundle.getSymbolicName(), precompiled);
}
}