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>.