You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2014/11/28 11:18:09 UTC

svn commit: r1642281 [14/14] - in /sling/trunk/contrib/scripting/sightly: ./ engine/ engine/src/main/antlr4/org/apache/sling/parser/expr/generated/ engine/src/main/antlr4/org/apache/sling/scripting/ engine/src/main/antlr4/org/apache/sling/scripting/sig...

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoop.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoop.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoop.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoop.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.loop;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Simulates an event loop for the Rhino JS engine.
+ */
+public class EventLoop {
+
+    private static final Logger log = LoggerFactory.getLogger(EventLoop.class);
+
+    private Queue<Task> taskQueue = new LinkedList<Task>();
+    private boolean isRunning;
+
+    /**
+     * Add a task to the queue. If the queue is empty, start running tasks. If it
+     * isn't empty, continue running the available tasks
+     * @param task the task to be added
+     */
+    public void schedule(Task task) {
+        taskQueue.offer(task);
+        run();
+    }
+
+    private void run() {
+        if (isRunning) {
+            return;
+        }
+        isRunning = true;
+        try {
+            // Holds the first exception encountered. If there is such a first exception, it will be
+            // rethrown
+            Exception thrownException = null;
+            while (!taskQueue.isEmpty()) {
+                Task task = taskQueue.poll();
+                try {
+                    task.run();
+                } catch (Exception e) {
+                    if (thrownException == null) {
+                        thrownException = e; //first exception
+                    } else {
+                        log.error("Additional error occurred while running JS script: ", e);
+                    }
+                }
+            }
+            if (thrownException != null) {
+                throw new SightlyUseException(thrownException);
+            }
+        } finally {
+            isRunning = false;
+        }
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoop.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoopInterop.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoopInterop.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoopInterop.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoopInterop.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.loop;
+
+import org.mozilla.javascript.Context;
+
+/**
+ * Event-loop utilities for interoperability with JS code
+ */
+public class EventLoopInterop {
+
+    public static final String EVENT_LOOP_KEY = "EventLoop";
+
+    public static EventLoop obtainEventLoop(Context context) {
+        EventLoop eventLoop = getEventLoop(context);
+        if (eventLoop == null) {
+            eventLoop = new EventLoop();
+            context.putThreadLocal(EVENT_LOOP_KEY, eventLoop);
+        }
+        return eventLoop;
+    }
+
+    public static void cleanupEventLoop(Context context) {
+        context.removeThreadLocal(EVENT_LOOP_KEY);
+    }
+
+    public static Task schedule(Context context, Runnable runnable) {
+        Task task = new Task(runnable);
+        obtainEventLoop(context).schedule(task);
+        return task;
+    }
+
+    private static EventLoop getEventLoop(Context context) {
+        return (EventLoop) context.getThreadLocal(EVENT_LOOP_KEY);
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/EventLoopInterop.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/Task.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/Task.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/Task.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/Task.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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.loop;
+
+/**
+ * Task in an event loop
+ */
+public class Task {
+
+    private final Runnable runnable;
+    private boolean active;
+
+    public Task(Runnable runnable) {
+        this.runnable = runnable;
+        this.active = true;
+    }
+
+    public void run() {
+        if (active) {
+            runnable.run();
+        }
+    }
+
+    public void deactivate() {
+        this.active = false;
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/loop/Task.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/HybridObject.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/HybridObject.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/HybridObject.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/HybridObject.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * 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.rhino;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.scripting.sightly.Record;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+
+
+/**
+ * Instances of this class can be used in both Sightly & JS scripts
+ */
+public class HybridObject implements Scriptable, Record<Object> {
+
+    private final Scriptable scriptable;
+    private final JsValueAdapter jsValueAdapter;
+
+    public HybridObject(Scriptable scriptable, JsValueAdapter jsValueAdapter) {
+        this.scriptable = scriptable;
+        this.jsValueAdapter = jsValueAdapter;
+    }
+
+    // Record implementation
+
+    @Override
+    public Object get(String name) {
+        if (name == null) {
+            return null;
+        }
+        Context.enter();
+        try {
+            return getAdapted(name);
+        } finally {
+            Context.exit();
+        }
+    }
+
+    @Override
+    public Set<String> properties() {
+        Object[] properties = scriptable.getIds();
+        Set<String> keys = new HashSet<String>();
+        for (Object property: properties) {
+            if (property instanceof String) {
+                keys.add((String) property);
+            }
+        }
+        return keys;
+    }
+
+    private Object getAdapted(String key) {
+        Object obj = ScriptableObject.getProperty(scriptable, key);
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Function) {
+            return jsValueAdapter.adapt(JsUtils.callFn((Function) obj, null, scriptable, scriptable, new Object[0]));
+        }
+        return jsValueAdapter.adapt(obj);
+    }
+
+    // Scriptable implementation
+
+    @Override
+    public String getClassName() {
+        return scriptable.getClassName();
+    }
+
+    @Override
+    public Object get(String name, Scriptable start) {
+        return scriptable.get(name, start);
+    }
+
+    @Override
+    public Object get(int index, Scriptable start) {
+        return scriptable.get(index, start);
+    }
+
+    @Override
+    public boolean has(String name, Scriptable start) {
+        return scriptable.has(name, start);
+    }
+
+    @Override
+    public boolean has(int index, Scriptable start) {
+        return scriptable.has(index, start);
+    }
+
+    @Override
+    public void put(String name, Scriptable start, Object value) {
+        scriptable.put(name, start, value);
+    }
+
+    @Override
+    public void put(int index, Scriptable start, Object value) {
+        scriptable.put(index, start, value);
+    }
+
+    @Override
+    public void delete(String name) {
+        scriptable.delete(name);
+    }
+
+    @Override
+    public void delete(int index) {
+        scriptable.delete(index);
+    }
+
+    @Override
+    public Scriptable getPrototype() {
+        return scriptable.getPrototype();
+    }
+
+    @Override
+    public void setPrototype(Scriptable prototype) {
+        scriptable.setPrototype(prototype);
+    }
+
+    @Override
+    public Scriptable getParentScope() {
+        return scriptable.getParentScope();
+    }
+
+    @Override
+    public void setParentScope(Scriptable parent) {
+        scriptable.setParentScope(parent);
+    }
+
+    @Override
+    public Object[] getIds() {
+        return scriptable.getIds();
+    }
+
+    @Override
+    public Object getDefaultValue(Class hint) {
+        return scriptable.getDefaultValue(hint);
+    }
+
+    @Override
+    public boolean hasInstance(Scriptable instance) {
+        return scriptable.hasInstance(instance);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/HybridObject.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsUtils.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsUtils.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsUtils.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsUtils.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.rhino;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.Scriptable;
+
+/**
+ * Utilities when inter-operating with JS scripts
+ */
+public class JsUtils {
+
+    public static Object callFn(Function function, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
+        boolean exitContext = false;
+        if (Context.getCurrentContext() == null) {
+            Context.enter();
+            exitContext = true;
+        }
+        Context context = (cx == null) ? Context.getCurrentContext() : cx;
+        Object result = function.call(context, scope, thisObj, args);
+        if (exitContext) {
+            Context.exit();
+        }
+        return result;
+    }
+
+
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsValueAdapter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsValueAdapter.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsValueAdapter.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsValueAdapter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * 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.rhino;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Wrapper;
+import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
+import org.apache.sling.scripting.sightly.js.impl.async.AsyncExtractor;
+
+/**
+ * Converts JS objects to Java objects
+ */
+public class JsValueAdapter {
+
+    private static final Map<String, Class<?>> knownConversions = new HashMap<String, Class<?>>();
+
+    static {
+        knownConversions.put("String", String.class);
+        knownConversions.put("Date", Date.class);
+    }
+
+    private final AsyncExtractor asyncExtractor;
+
+    public JsValueAdapter(AsyncExtractor asyncExtractor) {
+        this.asyncExtractor = asyncExtractor;
+    }
+
+    /**
+     * Convert a given JS value to a Java object
+     * @param jsValue the original JS value
+     * @return the Java correspondent
+     */
+    @SuppressWarnings("unchecked")
+    public Object adapt(Object jsValue) {
+        if (jsValue == null || jsValue == Context.getUndefinedValue() || jsValue == ScriptableObject.NOT_FOUND) {
+            return null;
+        }
+        if (jsValue instanceof Wrapper) {
+            return adapt(((Wrapper) jsValue).unwrap());
+        }
+        if (asyncExtractor.isPromise(jsValue)) {
+            return adapt(forceAsync(jsValue));
+        }
+        if (jsValue instanceof ScriptableObject) {
+            return extractScriptable((ScriptableObject) jsValue);
+        }
+        if (jsValue instanceof CharSequence) {
+            //convert any string-like type to plain java strings
+            return jsValue.toString();
+        }
+        if (jsValue instanceof Map) {
+            return convertMap((Map) jsValue);
+        }
+        if (jsValue instanceof Iterable) {
+            return convertIterable((Iterable) jsValue);
+        }
+        if (jsValue instanceof Number) {
+            return convertNumber((Number) jsValue);
+        }
+        if (jsValue instanceof Object[]) {
+            return convertIterable(Arrays.asList((Object[]) jsValue));
+        }
+        return jsValue;
+    }
+
+    private Object convertNumber(Number numValue) {
+        if (numValue instanceof Double) {
+            if (isLong((Double) numValue)) {
+                return numValue.longValue();
+            }
+        }
+        if (numValue instanceof Float) {
+            if (isLong((Float) numValue)) {
+                return numValue.longValue();
+            }
+        }
+        return numValue;
+    }
+
+    private boolean isLong(double x) {
+        return x == Math.floor(x);
+    }
+
+    private Object forceAsync(Object jsValue) {
+        AsyncContainer asyncContainer = new AsyncContainer();
+        asyncExtractor.extract(jsValue, asyncContainer.createCompletionCallback());
+        return asyncContainer.getResult();
+    }
+
+    private Object extractScriptable(ScriptableObject scriptableObject) {
+        Object obj = tryKnownConversion(scriptableObject);
+        if (obj != null) { return obj; }
+        if (scriptableObject instanceof NativeArray) {
+            return convertNativeArray((NativeArray) scriptableObject);
+        }
+        if (scriptableObject instanceof Function) {
+            return callFunction((Function) scriptableObject);
+        }
+        return new HybridObject(scriptableObject, this);
+    }
+
+    private Object callFunction(Function function) {
+        Object result = JsUtils.callFn(function, null, function, function, new Object[0]);
+        return adapt(result);
+    }
+
+    private Object[] convertNativeArray(NativeArray nativeArray) {
+        int length = (int) nativeArray.getLength();
+        Object[] objects = new Object[length];
+        for (int i = 0; i < length; i++) {
+            Object jsItem = nativeArray.get(i, nativeArray);
+            objects[i] = adapt(jsItem);
+        }
+        return objects;
+    }
+
+    private Map<Object, Object> convertMap(Map<Object, Object> original) {
+        Map<Object, Object> map = new HashMap<Object, Object>();
+        for (Map.Entry<Object, Object> entry : original.entrySet()) {
+            map.put(entry.getKey(), adapt(entry.getValue()));
+        }
+        return map;
+    }
+
+    private List<Object> convertIterable(Iterable<Object> iterable) {
+        List<Object> objects = new ArrayList<Object>();
+        for (Object obj : iterable) {
+            objects.add(adapt(obj));
+        }
+        return objects;
+    }
+
+    private static Object tryKnownConversion(ScriptableObject object) {
+        String className = object.getClassName();
+        Class<?> cls = knownConversions.get(className);
+        return (cls == null) ? null : Context.jsToJava(object, cls);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/rhino/JsValueAdapter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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.use;
+
+import javax.script.Bindings;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.scripting.sightly.js.impl.JsEnvironment;
+import org.apache.sling.scripting.sightly.js.impl.Utils;
+import org.apache.sling.scripting.sightly.js.impl.async.UnaryCallback;
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+
+/**
+ * Resolves dependencies specified by the Use function
+ */
+public class DependencyResolver {
+
+    private final Resource caller;
+    private final JsEnvironment jsEnvironment;
+    private final Bindings globalBindings;
+
+    public DependencyResolver(Resource resource, JsEnvironment jsEnvironment, Bindings globalBindings) {
+        this.caller = resource;
+        this.jsEnvironment = jsEnvironment;
+        this.globalBindings = globalBindings;
+    }
+
+    /**
+     * Resolve a dependency
+     * @param dependency the dependency identifier
+     * @param callback the callback that will receive the resolved dependency
+     */
+    public void resolve(String dependency, UnaryCallback callback) {
+        if (!Utils.isJsScript(dependency)) {
+            throw new SightlyUseException("Only JS scripts are allowed as dependencies. Invalid dependency: " + dependency);
+        }
+        jsEnvironment.run(caller, dependency, globalBindings, Utils.EMPTY_BINDINGS, callback);
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/UseFunction.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/UseFunction.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/UseFunction.java (added)
+++ sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/UseFunction.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * 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.use;
+
+import javax.script.Bindings;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.mozilla.javascript.BaseFunction;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.NativeObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
+import org.apache.sling.scripting.sightly.js.impl.async.UnaryCallback;
+import org.apache.sling.scripting.sightly.js.impl.loop.EventLoopInterop;
+import org.apache.sling.scripting.sightly.js.impl.rhino.JsUtils;
+
+/**
+ * The JavaScript {@code use} function
+ */
+public class UseFunction extends BaseFunction {
+
+    private final DependencyResolver dependencyResolver;
+    private final Scriptable thisObj;
+
+    public UseFunction(DependencyResolver dependencyResolver, Bindings arguments) {
+        this.dependencyResolver = dependencyResolver;
+        this.thisObj = createThisBinding(arguments);
+    }
+
+    @Override
+    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
+        Function function;
+        List<String> depNames;
+        if (args.length == 0) {
+            throw new IllegalArgumentException("Not enough arguments for use");
+        } else if (args.length == 1) {
+            function = decodeCallback(args[0]);
+            depNames = Collections.emptyList();
+        } else {
+            function = decodeCallback(args[1]);
+            depNames = decodeDepNames(args[0]);
+        }
+        return use(depNames, function, cx, scope);
+    }
+
+    private Object use(List<String> depNames, final Function callback, final Context cx, final Scriptable scope) {
+        final AsyncContainer asyncContainer = new AsyncContainer();
+        if (depNames.isEmpty()) {
+            callImmediate(callback, asyncContainer, cx, scope);
+        } else {
+            final int[] counter = {depNames.size()};
+            final Object[] dependencies = new Object[depNames.size()];
+            for (int i = 0; i < depNames.size(); i++) {
+                final int dependencyPos = i;
+                dependencyResolver.resolve(depNames.get(i), new UnaryCallback() {
+                    @Override
+                    public void invoke(Object arg) {
+                        counter[0]--;
+                        dependencies[dependencyPos] = arg;
+                        if (counter[0] == 0) {
+                            Object result = JsUtils.callFn(callback, cx, scope, thisObj, dependencies);
+                            asyncContainer.complete(result);
+                        }
+                    }
+                });
+            }
+        }
+        return asyncContainer;
+    }
+
+    private void callImmediate(final Function callback, final AsyncContainer asyncContainer, final Context cx, final Scriptable scope) {
+        EventLoopInterop.schedule(cx, new Runnable() {
+            @Override
+            public void run() {
+                Object value = JsUtils.callFn(callback, cx, scope, thisObj, new Object[0]);
+                asyncContainer.complete(value);
+            }
+        });
+    }
+
+    private Function decodeCallback(Object obj) {
+        if (!(obj instanceof Function)) {
+            throw new IllegalArgumentException("No callback argument supplied");
+        }
+        return (Function) obj;
+    }
+
+    private List<String> decodeDepNames(Object obj) {
+        if (obj instanceof NativeArray) {
+            return decodeDepArray((NativeArray) obj);
+        }
+        return Collections.singletonList(jsToString(obj));
+    }
+
+    private List<String> decodeDepArray(NativeArray nativeArray) {
+        int depLength = (int) nativeArray.getLength();
+        List<String> depNames = new ArrayList<String>(depLength);
+        for (int i = 0; i < depLength; i++) {
+            String depName = jsToString(nativeArray.get(i, nativeArray));
+            depNames.add(depName);
+        }
+        return depNames;
+    }
+
+    private String jsToString(Object obj) {
+        return (String) Context.jsToJava(obj, String.class);
+    }
+
+    private Scriptable createThisBinding(Bindings arguments) {
+        NativeObject nativeObject = new NativeObject();
+        for (Map.Entry<String, Object> entry : arguments.entrySet()) {
+            ScriptableObject.putProperty(nativeObject, entry.getKey(), entry.getValue());
+        }
+        return nativeObject;
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/js-use-provider/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/UseFunction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain