You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:11:37 UTC
[sling-org-apache-sling-scripting-sightly-js-provider] 21/24:
SLING-4964 - Deprecate the asynchronous JavaScript API provided by the
Sightly JS Use Provider
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.scripting.sightly.js.provider-1.0.10
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-js-provider.git
commit bc26af185d4db9206be862fd6728c0f09f3dea3f
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Mon Aug 24 22:57:39 2015 +0000
SLING-4964 - Deprecate the asynchronous JavaScript API provided by the Sightly JS Use Provider
* proxy objects are used to load the async namespaces on first usage for a Use script
* created a new JS performance test for purely synchronous code
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/scripting/sightly/js-use-provider@1697513 13f79535-47bb-0310-9956-ffa450edef68
---
.../scripting/sightly/js/impl/JsEnvironment.java | 75 +-----------------
.../scripting/sightly/js/impl/JsUseProvider.java | 32 ++++----
.../sling/scripting/sightly/js/impl/Utils.java | 51 ++++++++++++
.../js/impl/jsapi/ProxyAsyncScriptableFactory.java | 92 ++++++++++++++++++++++
.../js/impl/jsapi/SlyBindingsValuesProvider.java | 34 +++++---
.../sightly/js/impl/use/DependencyResolver.java | 3 +-
6 files changed, 185 insertions(+), 102 deletions(-)
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
index 3d95960..6175ce6 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
@@ -30,14 +30,8 @@ import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ResourceUtil;
-import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.scripting.core.ScriptNameAwareReader;
-import org.apache.sling.scripting.sightly.ResourceResolution;
import org.apache.sling.scripting.sightly.SightlyException;
import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
import org.apache.sling.scripting.sightly.js.impl.async.TimingBindingsValuesProvider;
@@ -80,31 +74,6 @@ public class JsEnvironment {
Context.exit();
}
- /**
- * Run a Js script at a given path
- * @param caller the resource of the script that invokes the Js code
- * @param path the path to the JS script
- * @param globalBindings the global bindings for the script
- * @param arguments the arguments from the use-plugin
- * @param callback callback that will receive the result of the script
- */
- public void run(Resource caller, String path, Bindings globalBindings, Bindings arguments, UnaryCallback callback) {
- Resource scriptResource = caller.getChild(path);
- SlingScriptHelper scriptHelper = (SlingScriptHelper) globalBindings.get(SlingBindings.SLING);
- Resource componentCaller = ResourceResolution.getResourceForRequest(caller.getResourceResolver(), scriptHelper.getRequest());
- if (scriptResource == null) {
- if (isResourceOverlay(caller, componentCaller)) {
- scriptResource = ResourceResolution.getResourceFromSearchPath(componentCaller, path);
- } else {
- scriptResource = ResourceResolution.getResourceFromSearchPath(caller, path);
- }
- }
- if (scriptResource == null) {
- throw new SightlyException("Required script resource could not be located: " + path);
- }
- runResource(scriptResource, globalBindings, arguments, callback);
- }
-
public void runResource(Resource scriptResource, Bindings globalBindings, Bindings arguments, UnaryCallback callback) {
ScriptContext scriptContext = new SimpleScriptContext();
CommonJsModule module = new CommonJsModule();
@@ -120,22 +89,6 @@ public class JsEnvironment {
return asyncContainer;
}
- /**
- * Run a script at a given path
- *
- * @param caller the resource of the script that invokes the Js code
- * @param path the path to the JS script
- * @param globalBindings bindings for the JS script
- * @param arguments the arguments for the JS script
- * @return an asynchronous container for the result
- * @throws UnsupportedOperationException if this method is run when the event loop is not empty
- */
- public AsyncContainer run(Resource caller, String path, Bindings globalBindings, Bindings arguments) {
- AsyncContainer asyncContainer = new AsyncContainer();
- run(caller, path, globalBindings, arguments, asyncContainer.createCompletionCallback());
- return asyncContainer;
- }
-
private Bindings buildBindings(Resource scriptResource, Bindings local, Bindings arguments, CommonJsModule commonJsModule) {
Bindings bindings = new SimpleBindings();
bindings.putAll(engineBindings);
@@ -186,31 +139,5 @@ public class JsEnvironment {
});
}
- /**
- * Using the inheritance chain created with the help of {@code sling:resourceSuperType} this method checks if {@code resourceB}
- * inherits from {@code resourceA}. In case {@code resourceA} is a {@code nt:file}, its parent will be used for the inheritance check.
- *
- * @param resourceA the base resource
- * @param resourceB the potentially overlaid resource
- * @return {@code true} if {@code resourceB} overlays {@code resourceB}, {@code false} otherwise
- */
- private boolean isResourceOverlay(Resource resourceA, Resource resourceB) {
- String resourceBSuperType = resourceB.getResourceSuperType();
- if (StringUtils.isNotEmpty(resourceBSuperType)) {
- ResourceResolver resolver = resourceA.getResourceResolver();
- String parentResourceType = resourceA.getResourceType();
- if ("nt:file".equals(parentResourceType)) {
- parentResourceType = ResourceUtil.getParent(resourceA.getPath());
- }
- Resource parentB = resolver.getResource(resourceBSuperType);
- while (parentB != null && !"/".equals(parentB.getPath()) && StringUtils.isNotEmpty(resourceBSuperType)) {
- if (parentB.getPath().equals(parentResourceType)) {
- return true;
- }
- resourceBSuperType = parentB.getResourceSuperType();
- parentB = resolver.getResource(resourceBSuperType);
- }
- }
- return false;
- }
+
}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsUseProvider.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsUseProvider.java
index 4ce28bc..2e11221 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsUseProvider.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsUseProvider.java
@@ -33,7 +33,7 @@ import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.scripting.sightly.SightlyException;
import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
import org.apache.sling.scripting.sightly.js.impl.async.AsyncExtractor;
-import org.apache.sling.scripting.sightly.js.impl.jsapi.SlyBindingsValuesProvider;
+import org.apache.sling.scripting.sightly.js.impl.jsapi.ProxyAsyncScriptableFactory;
import org.apache.sling.scripting.sightly.js.impl.rhino.JsValueAdapter;
import org.apache.sling.scripting.sightly.render.RenderContext;
import org.apache.sling.scripting.sightly.use.ProviderOutcome;
@@ -44,21 +44,21 @@ import org.osgi.framework.Constants;
* Use provider for JavaScript Use-API objects.
*/
@Component(
- metatype = true,
- label = "Apache Sling Scripting Sightly JavaScript Use Provider",
- description = "The JavaScript Use Provider is responsible for instantiating JavaScript Use-API objects."
+ metatype = true,
+ label = "Apache Sling Scripting Sightly JavaScript Use Provider",
+ description = "The JavaScript Use Provider is responsible for instantiating JavaScript Use-API objects."
)
@Service(UseProvider.class)
@Properties({
- @Property(
- name = Constants.SERVICE_RANKING,
- label = "Service Ranking",
- description = "The Service Ranking value acts as the priority with which this Use Provider is queried to return an " +
+ @Property(
+ name = Constants.SERVICE_RANKING,
+ label = "Service Ranking",
+ description = "The Service Ranking value acts as the priority with which this Use Provider is queried to return an " +
"Use-object. A higher value represents a higher priority.",
- intValue = 80,
- propertyPrivate = false
- )
-})
+ intValue = 80,
+ propertyPrivate = false
+ )
+ })
public class JsUseProvider implements UseProvider {
private static final String JS_ENGINE_NAME = "javascript";
@@ -68,12 +68,11 @@ public class JsUseProvider implements UseProvider {
private ScriptEngineManager scriptEngineManager = null;
@Reference
- private SlyBindingsValuesProvider slyBindingsValuesProvider = null;
+ private ProxyAsyncScriptableFactory proxyAsyncScriptableFactory = null;
@Override
public ProviderOutcome provide(String identifier, RenderContext renderContext, Bindings arguments) {
Bindings globalBindings = renderContext.getBindings();
- slyBindingsValuesProvider.processBindings(globalBindings);
if (!Utils.isJsScript(identifier)) {
return ProviderOutcome.failure();
}
@@ -89,7 +88,10 @@ public class JsUseProvider implements UseProvider {
String callerPath = scriptHelper.getScript().getScriptResource().getPath();
ResourceResolver adminResolver = renderContext.getScriptResourceResolver();
Resource caller = adminResolver.getResource(callerPath);
- AsyncContainer asyncContainer = environment.run(caller, identifier, globalBindings, arguments);
+ Resource scriptResource = Utils.getScriptResource(caller, identifier, globalBindings);
+ globalBindings.put(ScriptEngine.FILENAME, scriptResource.getPath());
+ proxyAsyncScriptableFactory.registerProxies(globalBindings);
+ AsyncContainer asyncContainer = environment.runResource(scriptResource, globalBindings, arguments);
return ProviderOutcome.success(jsValueAdapter.adapt(asyncContainer));
} finally {
if (environment != null) {
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/Utils.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/Utils.java
index 3b21ede..3c7a4cf 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/js/impl/Utils.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/Utils.java
@@ -23,8 +23,14 @@ import javax.script.SimpleBindings;
import java.util.Collections;
import org.apache.commons.lang.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.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.ResourceResolution;
+import org.apache.sling.scripting.sightly.SightlyException;
/**
* Utilities for script evaluation
@@ -43,4 +49,49 @@ public class Utils {
return JS_EXTENSION.equalsIgnoreCase(extension);
}
+ public static Resource getScriptResource(Resource caller, String path, Bindings bindings) {
+ Resource scriptResource = caller.getChild(path);
+ Resource componentCaller = ResourceResolution.getResourceForRequest(caller.getResourceResolver(), (SlingHttpServletRequest) bindings.get
+ (SlingBindings.REQUEST));
+ if (scriptResource == null) {
+ if (isResourceOverlay(caller, componentCaller)) {
+ scriptResource = ResourceResolution.getResourceFromSearchPath(componentCaller, path);
+ } else {
+ scriptResource = ResourceResolution.getResourceFromSearchPath(caller, path);
+ }
+ }
+ if (scriptResource == null) {
+ throw new SightlyException("Required script resource could not be located: " + path);
+ }
+ return scriptResource;
+ }
+
+ /**
+ * Using the inheritance chain created with the help of {@code sling:resourceSuperType} this method checks if {@code resourceB}
+ * inherits from {@code resourceA}. In case {@code resourceA} is a {@code nt:file}, its parent will be used for the inheritance check.
+ *
+ * @param resourceA the base resource
+ * @param resourceB the potentially overlaid resource
+ * @return {@code true} if {@code resourceB} overlays {@code resourceB}, {@code false} otherwise
+ */
+ private static boolean isResourceOverlay(Resource resourceA, Resource resourceB) {
+ String resourceBSuperType = resourceB.getResourceSuperType();
+ if (StringUtils.isNotEmpty(resourceBSuperType)) {
+ ResourceResolver resolver = resourceA.getResourceResolver();
+ String parentResourceType = resourceA.getResourceType();
+ if ("nt:file".equals(parentResourceType)) {
+ parentResourceType = ResourceUtil.getParent(resourceA.getPath());
+ }
+ Resource parentB = resolver.getResource(resourceBSuperType);
+ while (parentB != null && !"/".equals(parentB.getPath()) && StringUtils.isNotEmpty(resourceBSuperType)) {
+ if (parentB.getPath().equals(parentResourceType)) {
+ return true;
+ }
+ resourceBSuperType = parentB.getResourceSuperType();
+ parentB = resolver.getResource(resourceBSuperType);
+ }
+ }
+ return false;
+ }
+
}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/ProxyAsyncScriptableFactory.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/ProxyAsyncScriptableFactory.java
new file mode 100644
index 0000000..3a38cac
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/ProxyAsyncScriptableFactory.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.scripting.sightly.js.impl.jsapi;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+import javax.script.SimpleBindings;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.scripting.sightly.js.impl.rhino.HybridObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service(ProxyAsyncScriptableFactory.class)
+public class ProxyAsyncScriptableFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProxyAsyncScriptableFactory.class);
+
+ @Reference
+ private SlyBindingsValuesProvider slyBindingsValuesProvider = null;
+
+ public void registerProxies(Bindings bindings) {
+ slyBindingsValuesProvider.initialise(bindings);
+ Bindings bindingsCopy = new SimpleBindings();
+ for (String factoryName : slyBindingsValuesProvider.getScriptPaths().keySet()) {
+ ShadowScriptableObject shadowScriptableObject = new ShadowScriptableObject(factoryName, bindingsCopy);
+ bindings.put(factoryName, shadowScriptableObject);
+ }
+ bindingsCopy.putAll(bindings);
+ }
+
+ class ShadowScriptableObject extends ScriptableObject {
+
+ private String clazz;
+ private Bindings bindings;
+ private Set<String> scriptNSUse = new HashSet<String>();
+
+ public ShadowScriptableObject(String clazz, Bindings bindings) {
+ this.clazz = clazz;
+ this.bindings = bindings;
+ }
+
+ @Override
+ public String getClassName() {
+ return clazz;
+ }
+
+ @Override
+ public Object get(String name, Scriptable start) {
+ Object object = bindings.get(clazz);
+ if (!(object instanceof HybridObject)) {
+ slyBindingsValuesProvider.processBindings(bindings);
+ }
+ HybridObject hybridObject = (HybridObject) bindings.get(clazz);
+ if (hybridObject != null) {
+ String script = (String) bindings.get(ScriptEngine.FILENAME);
+ if (StringUtils.isNotEmpty(script)) {
+ if (scriptNSUse.add(clazz + ":" + script)) {
+ LOGGER.warn(
+ "Script {} uses the deprecated asynchronous API provided by the '{}' namespace. Please refactor the script to" +
+ " use the synchronous API provided by the org.apache.sling.scripting.javascript bundle.", script, clazz);
+ }
+ }
+ return hybridObject.get(name, start);
+ }
+ return Undefined.instance;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
index 71fc67c..ec9a422 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
@@ -21,10 +21,10 @@ package org.apache.sling.scripting.sightly.js.impl.jsapi;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
-
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@@ -45,6 +45,7 @@ import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.scripting.sightly.SightlyException;
import org.apache.sling.scripting.sightly.js.impl.JsEnvironment;
import org.apache.sling.scripting.sightly.js.impl.Variables;
import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
@@ -92,10 +93,10 @@ public class SlyBindingsValuesProvider {
private static final String REQ_NS = SlyBindingsValuesProvider.class.getCanonicalName();
- private static final Logger log = LoggerFactory.getLogger(SlyBindingsValuesProvider.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(SlyBindingsValuesProvider.class);
@Reference
- private ScriptEngineManager scriptEngineManager;
+ private ScriptEngineManager scriptEngineManager = null;
@Reference
private ResourceResolverFactory rrf = null;
@@ -109,10 +110,16 @@ public class SlyBindingsValuesProvider {
private Script qScript;
private final ScriptableObject qScope = createQScope();
- public void processBindings(Bindings bindings) {
+ public void initialise(Bindings bindings) {
if (needsInit()) {
init(bindings);
}
+ }
+
+ public void processBindings(Bindings bindings) {
+ if (needsInit()) {
+ throw new SightlyException("Attempted to call processBindings without calling initialise first.");
+ }
Context context = null;
try {
context = Context.enter();
@@ -130,6 +137,10 @@ public class SlyBindingsValuesProvider {
}
}
+ public Map<String, String> getScriptPaths() {
+ return Collections.unmodifiableMap(scriptPaths);
+ }
+
@Activate
protected void activate(ComponentContext componentContext) {
Dictionary properties = componentContext.getProperties();
@@ -200,18 +211,17 @@ public class SlyBindingsValuesProvider {
resolver = rrf.getAdministrativeResourceResolver(null);
Resource resource = resolver.getResource(path);
if (resource == null) {
- log.warn("Sly namespace loader could not find the following script: " + path);
- return null;
+ throw new SightlyException("Sly namespace loader could not find the following script: " + path);
+
}
AsyncContainer container = jsEnvironment.runResource(resource, createBindings(bindings), new SimpleBindings());
Object obj = container.getResult();
if (!(obj instanceof Function)) {
- log.warn("Script was expected to return a function");
- return null;
+ throw new SightlyException("Script " + path + " was expected to return a function.");
}
return (Function) obj;
} catch (LoginException e) {
- log.error("Cannot evaluate script " + path, e);
+ LOGGER.error("Cannot evaluate script " + path, e);
return null;
} finally {
if (resolver != null) {
@@ -280,12 +290,12 @@ public class SlyBindingsValuesProvider {
resourceResolver = rrf.getAdministrativeResourceResolver(null);
Resource resource = resourceResolver.getResource(Q_PATH);
if (resource == null) {
- log.warn("Could not load Q library at path: " + Q_PATH);
+ LOGGER.warn("Could not load Q library at path: " + Q_PATH);
return null;
}
reader = resource.adaptTo(InputStream.class);
if (reader == null) {
- log.warn("Could not read content of Q library");
+ LOGGER.warn("Could not read content of Q library");
return null;
}
return context.compileReader(new InputStreamReader(reader), Q_PATH, 0, null);
@@ -298,7 +308,7 @@ public class SlyBindingsValuesProvider {
try {
reader.close();
} catch (IOException e) {
- log.error("Error while closing reader", e);
+ LOGGER.error("Error while closing reader", e);
}
}
if (resourceResolver != null) {
diff --git a/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java b/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
index ef24105..46b7cfb 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
@@ -51,7 +51,8 @@ public class DependencyResolver {
if (!Utils.isJsScript(dependency)) {
throw new SightlyException("Only JS scripts are allowed as dependencies. Invalid dependency: " + dependency);
}
- jsEnvironment.run(caller, dependency, globalBindings, Utils.EMPTY_BINDINGS, callback);
+ Resource scriptResource = Utils.getScriptResource(caller, dependency, globalBindings);
+ jsEnvironment.runResource(scriptResource, globalBindings, Utils.EMPTY_BINDINGS, callback);
}
}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.