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 2016/06/16 16:08:00 UTC

svn commit: r1748750 [8/12] - in /sling/trunk/bundles/scripting/sightly: ./ compiler/ compiler/src/ compiler/src/main/ compiler/src/main/antlr4/ compiler/src/main/antlr4/org/ compiler/src/main/antlr4/org/apache/ compiler/src/main/antlr4/org/apache/slin...

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java Thu Jun 16 16:07:57 2016
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  ******************************************************************************/
-
 package org.apache.sling.scripting.sightly.impl.engine;
 
 import java.io.IOException;
@@ -36,6 +35,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.sling.commons.classloader.ClassLoaderWriter;
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
+import org.apache.sling.scripting.sightly.compiler.SightlyCompiler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,19 +53,19 @@ public class SightlyScriptEngineFactory
     private static final Logger LOGGER = LoggerFactory.getLogger(SightlyScriptEngineFactory.class);
 
     @Reference
-    private UnitLoader unitLoader;
+    private DynamicClassLoaderManager dynamicClassLoaderManager;
 
     @Reference
-    private ExtensionRegistryService extensionRegistryService;
+    private SightlyEngineConfiguration sightlyEngineConfiguration;
 
     @Reference
-    private DynamicClassLoaderManager dynamicClassLoaderManager;
+    private ClassLoaderWriter classLoaderWriter;
 
     @Reference
-    private SightlyEngineConfiguration sightlyEngineConfiguration;
+    private SightlyCompiler sightlyCompiler;
 
     @Reference
-    private ClassLoaderWriter classLoaderWriter;
+    private SightlyJavaCompilerService sightlyJavaCompilerService;
 
     public final static String SHORT_NAME = "sightly";
 
@@ -94,7 +94,7 @@ public class SightlyScriptEngineFactory
 
     @Override
     public ScriptEngine getScriptEngine() {
-        return new SightlyScriptEngine(this, unitLoader, extensionRegistryService);
+        return new SightlyScriptEngine(this, sightlyCompiler, sightlyJavaCompilerService, sightlyEngineConfiguration);
     }
 
     protected ClassLoader getClassLoader() {
@@ -102,7 +102,6 @@ public class SightlyScriptEngineFactory
     }
 
     @Activate
-    @SuppressWarnings("unused")
     protected void activate() {
         InputStream is;
         boolean newVersion = true;

Added: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/UnitChangeMonitor.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/UnitChangeMonitor.java?rev=1748750&view=auto
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/UnitChangeMonitor.java (added)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/UnitChangeMonitor.java Thu Jun 16 16:07:57 2016
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * 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.impl.engine;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service(UnitChangeMonitor.class)
+public class UnitChangeMonitor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnitChangeMonitor.class);
+
+    private Map<String, Long> slyJavaUseMap = new ConcurrentHashMap<String, Long>();
+    private ServiceRegistration eventHandlerServiceRegistration;
+
+    @Reference
+    private ResourceResolverFactory rrf = null;
+
+    @Reference
+    private SightlyEngineConfiguration sightlyEngineConfiguration = null;
+
+    /**
+     * Returns the last modified date for a Java Use-API object stored in the repository.
+     *
+     * @param className the fully qualified class name
+     * @return the Java Use-API file's last modified date or 0 if there's no information about this file
+     */
+    public long getLastModifiedDateForJavaUseObject(String className) {
+        if (className == null) {
+            return 0;
+        }
+        Long date = slyJavaUseMap.get(className);
+        return date != null ? date : 0;
+    }
+
+    public void clearJavaUseObject(String className) {
+        if (StringUtils.isNotEmpty(className)) {
+            slyJavaUseMap.remove(className);
+        }
+    }
+
+    @Activate
+    protected void activate(ComponentContext componentContext) {
+        ResourceResolver adminResolver = null;
+        try {
+            adminResolver = rrf.getAdministrativeResourceResolver(null);
+            StringBuilder eventHandlerFilteredPaths = new StringBuilder("(|");
+            String[] searchPaths = adminResolver.getSearchPath();
+            for (String sp : searchPaths) {
+                // Sightly Java Use-API objects
+                eventHandlerFilteredPaths.append("(path=").append(sp).append("**/*.java").append(")");
+            }
+            eventHandlerFilteredPaths.append(")");
+            Dictionary eventHandlerProperties = new Hashtable();
+            eventHandlerProperties.put(EventConstants.EVENT_FILTER, eventHandlerFilteredPaths.toString());
+            eventHandlerProperties.put(EventConstants.EVENT_TOPIC, new String[]{SlingConstants.TOPIC_RESOURCE_ADDED, SlingConstants
+                    .TOPIC_RESOURCE_CHANGED, SlingConstants.TOPIC_RESOURCE_REMOVED});
+            eventHandlerServiceRegistration = componentContext.getBundleContext().registerService(
+                    EventHandler.class.getName(),
+                    new EventHandler() {
+                        @Override
+                        public void handleEvent(Event event) {
+                            processEvent(event);
+                        }
+                    },
+                    eventHandlerProperties
+            );
+        } catch (LoginException e) {
+            LOG.error("Unable to listen for change events.", e);
+        } finally {
+            if (adminResolver != null) {
+                adminResolver.close();
+            }
+        }
+
+    }
+
+    @Deactivate
+    protected void deactivate(ComponentContext componentContext) {
+        if (eventHandlerServiceRegistration != null) {
+            eventHandlerServiceRegistration.unregister();
+        }
+    }
+
+    private void processEvent(Event event) {
+        String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
+        String topic = event.getTopic();
+        LOG.debug("Received event {} for path {}.", topic, path);
+        if (path.endsWith(".java")) {
+            SourceIdentifier sourceIdentifier = new SourceIdentifier(sightlyEngineConfiguration, path);
+            if (SlingConstants.TOPIC_RESOURCE_ADDED.equals(topic) || SlingConstants.TOPIC_RESOURCE_CHANGED.equals(topic)) {
+                LOG.debug("Java Use Object {} was {}.", path, topic);
+                slyJavaUseMap.put(sourceIdentifier.getFullyQualifiedClassName(), System.currentTimeMillis());
+            } else if (SlingConstants.TOPIC_RESOURCE_REMOVED.equals(topic)) {
+                LOG.debug("Removed Java Use Object {} from UnitChangeMonitor cache.", path);
+                slyJavaUseMap.remove(sourceIdentifier.getFullyQualifiedClassName());
+            }
+        }
+    }
+}

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java Thu Jun 16 16:07:57 2016
@@ -16,118 +16,242 @@
  * specific language governing permissions and limitations
  * under the License.
  ******************************************************************************/
-
 package org.apache.sling.scripting.sightly.impl.engine.compiled;
 
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceUtil;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.scripting.sightly.impl.compiler.UnitChangeMonitor;
 import org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
-import org.apache.sling.scripting.sightly.impl.utils.JavaEscapeUtils;
+import org.apache.sling.scripting.sightly.java.compiler.ClassInfo;
 
 /**
  * Identifies a Java source file based on a {@link Resource}. Depending on the used constructor this class might provide the abstraction
  * for either a Java source file generated for a Sightly HTML script or for a Sightly {@link Resource}-based Java Use-API Object.
  */
-public class SourceIdentifier {
-
-    private final String className;
-    private final Resource resource;
-    private final String packageName;
-    private final String fullyQualifiedName;
-    private SightlyEngineConfiguration configuration;
-    private UnitChangeMonitor unitChangeMonitor;
-    private ClassLoaderWriter writer;
-    private boolean scriptSource = false;
-
-    public SourceIdentifier(SightlyEngineConfiguration configuration, UnitChangeMonitor unitChangeMonitor, ClassLoaderWriter writer,
-                            Resource resource) {
-        this(configuration, unitChangeMonitor, writer, resource, null);
-    }
-
-    public SourceIdentifier(SightlyEngineConfiguration configuration, UnitChangeMonitor unitChangeMonitor, ClassLoaderWriter writer,
-                            Resource resource, String classNamePrefix) {
-        this.resource = resource;
-        this.configuration = configuration;
-        this.unitChangeMonitor = unitChangeMonitor;
-        this.writer = writer;
-        if (StringUtils.isNotEmpty(classNamePrefix)) {
-            scriptSource = true;
-        }
-        this.className = buildClassName(resource, classNamePrefix);
-        this.packageName = buildPackageName(resource);
-        this.fullyQualifiedName = buildFullyQualifiedName(packageName, className);
-    }
+public class SourceIdentifier implements ClassInfo {
 
-    public String getClassName() {
-        return className;
+    private static final Set<String> javaKeywords = new HashSet<String>() {{
+        add("abstract");
+        add("assert");
+        add("boolean");
+        add("break");
+        add("byte");
+        add("case");
+        add("catch");
+        add("char");
+        add("class");
+        add("const");
+        add("continue");
+        add("default");
+        add("do");
+        add("double");
+        add("else");
+        add("enum");
+        add("extends");
+        add("final");
+        add("finally");
+        add("float");
+        add("for");
+        add("goto");
+        add("if");
+        add("implements");
+        add("import");
+        add("instanceof");
+        add("int");
+        add("interface");
+        add("long");
+        add("native");
+        add("new");
+        add("package");
+        add("private");
+        add("protected");
+        add("public");
+        add("return");
+        add("short");
+        add("static");
+        add("strictfp");
+        add("super");
+        add("switch");
+        add("synchronized");
+        add("this");
+        add("throws");
+        add("transient");
+        add("try");
+        add("void");
+        add("volatile");
+        add("while");
+    }};
+
+    public static final Pattern MANGLED_CHAR_PATTER = Pattern.compile("(.*)(__[0-9a-f]{4}__)(.*)");
+
+    private SightlyEngineConfiguration engineConfiguration;
+    private String scriptName;
+    private String simpleClassName;
+    private String packageName;
+    private String fullyQualifiedClassName;
+
+    public SourceIdentifier(SightlyEngineConfiguration engineConfiguration, String scriptName) {
+        this.engineConfiguration = engineConfiguration;
+        this.scriptName = scriptName;
     }
 
-    public Resource getResource() {
-        return resource;
+    @Override
+    public String getSimpleClassName() {
+        if (simpleClassName == null) {
+            int lastSlashIndex = scriptName.lastIndexOf("/");
+            String processingScriptName = scriptName;
+            if (scriptName.endsWith(".java")) {
+                processingScriptName = scriptName.substring(0, scriptName.length() - 5);
+            }
+            if (lastSlashIndex != -1) {
+                simpleClassName = makeJavaPackage(processingScriptName.substring(lastSlashIndex));
+            } else {
+                simpleClassName = makeJavaPackage(processingScriptName);
+            }
+        }
+        return simpleClassName;
     }
 
+    @Override
     public String getPackageName() {
+        if (packageName == null) {
+            int lastSlashIndex = scriptName.lastIndexOf("/");
+            String processingScriptName = scriptName;
+            boolean javaFile = scriptName.endsWith(".java");
+            if (javaFile) {
+                processingScriptName = scriptName.substring(0, scriptName.length() - 5);
+            }
+            if (lastSlashIndex != -1) {
+                packageName = makeJavaPackage(processingScriptName.substring(0, lastSlashIndex));
+            } else {
+                packageName = makeJavaPackage(processingScriptName);
+            }
+            if (!javaFile) {
+                packageName = engineConfiguration.getBundleSymbolicName() + "." + packageName;
+            }
+        }
         return packageName;
     }
 
-    public String getFullyQualifiedName() {
-        return fullyQualifiedName;
-    }
-
-    public boolean needsUpdate() {
-        if (configuration.isDevMode()) {
-            return true;
+    @Override
+    public String getFullyQualifiedClassName() {
+        if (fullyQualifiedClassName == null) {
+            fullyQualifiedClassName = getPackageName() + "." + getSimpleClassName();
         }
-        String slyPath = getResource().getPath();
-        long slyScriptChangeDate = unitChangeMonitor.getLastModifiedDateForScript(slyPath);
-        String javaCompilerPath = "/" + getFullyQualifiedName().replaceAll("\\.", "/") + ".class";
-        long javaFileDate = writer.getLastModified(javaCompilerPath);
-        return ((slyScriptChangeDate == 0 && javaFileDate > -1) || (slyScriptChangeDate > javaFileDate));
-    }
-
-    private String buildFullyQualifiedName(String packageName, String className) {
-        return packageName + "." + className;
+        return fullyQualifiedClassName;
     }
 
-    private String buildClassName(Resource resource, String classNamePrefix) {
-        String scriptName = ResourceUtil.getName(resource.getPath());
-        scriptName = scriptName.substring(0, scriptName.lastIndexOf(getExtension(scriptName)));
-        String className;
-        if (StringUtils.isNotEmpty(classNamePrefix)) {
-            className = classNamePrefix + scriptName;
-        } else {
-            className = scriptName;
+    /**
+     * Converts the given identifier to a legal Java identifier
+     *
+     * @param identifier the identifier to convert
+     * @return legal Java identifier corresponding to the given identifier
+     */
+    public static String makeJavaIdentifier(String identifier) {
+        StringBuilder modifiedIdentifier = new StringBuilder(identifier.length());
+        if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
+            modifiedIdentifier.append('_');
+        }
+        for (int i = 0; i < identifier.length(); i++) {
+            char ch = identifier.charAt(i);
+            if (Character.isJavaIdentifierPart(ch) && ch != '_') {
+                modifiedIdentifier.append(ch);
+            } else if (ch == '.') {
+                modifiedIdentifier.append('_');
+            } else {
+                modifiedIdentifier.append(mangleChar(ch));
+            }
+        }
+        if (isJavaKeyword(modifiedIdentifier.toString())) {
+            modifiedIdentifier.append('_');
         }
-        return className.replaceAll("-", "_").replaceAll("\\.", "_");
+        return modifiedIdentifier.toString();
     }
 
-    private String buildPackageName(Resource resource) {
-        String packageName = ResourceUtil.getParent(resource.getPath()).replaceAll("/", ".").substring(1).replaceAll("-", "_");
-        String[] packageNameElements = packageName.split("\\.");
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < packageNameElements.length; i++) {
-            String subPackage = packageNameElements[i];
-            sb.append(JavaEscapeUtils.getEscapedToken(subPackage));
-            if (i != packageNameElements.length - 1) {
-                sb.append(".");
+    /**
+     * Converts the given scriptName to a Java package or fully-qualified class name
+     *
+     * @param scriptName the scriptName to convert
+     * @return Java package corresponding to the given scriptName
+     */
+    public static String makeJavaPackage(String scriptName) {
+        String classNameComponents[] = StringUtils.split(scriptName, '/');
+        StringBuilder legalClassNames = new StringBuilder();
+        for (int i = 0; i < classNameComponents.length; i++) {
+            legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
+            if (i < classNameComponents.length - 1) {
+                legalClassNames.append('.');
             }
         }
-        if (!scriptSource) {
-            return sb.toString();
-        }
-        return configuration.getBundleSymbolicName() + "." + sb.toString();
+        return legalClassNames.toString();
     }
 
-    private String getExtension(String scriptName) {
-        int lastDotIndex = scriptName.lastIndexOf('.');
-        return scriptName.substring(lastDotIndex);
+    public static String getScriptName(String slashSubpackage, String fullyQualifiedClassName) {
+        String className = fullyQualifiedClassName;
+        StringBuilder pathElements = new StringBuilder("/");
+        if (StringUtils.isNotEmpty(slashSubpackage) && className.contains(slashSubpackage)) {
+            className = className.replaceAll(slashSubpackage + "\\.", "");
+        }
+        String[] classElements = StringUtils.split(className, '.');
+        for (int i = 0; i < classElements.length; i++) {
+            String classElem = classElements[i];
+            Matcher matcher = MANGLED_CHAR_PATTER.matcher(classElem);
+            if (matcher.matches()) {
+                String group = matcher.group(2);
+                char unmangled = unmangle(group);
+                classElem = classElem.replaceAll(group, Character.toString(unmangled));
+                while (matcher.find()) {
+                    group = matcher.group(2);
+                    unmangled = unmangle(group);
+                    classElem = classElem.replaceAll(group, Character.toString(unmangled));
+                }
+            } else {
+                int underscoreIndex = classElem.indexOf('_');
+                if (underscoreIndex > -1) {
+                    if (underscoreIndex == classElem.length() - 1) {
+                        classElem = classElem.substring(0, classElem.length() -1);
+                    } else {
+                        classElem = classElem.replaceAll("_", ".");
+                    }
+                }
+            }
+            pathElements.append(classElem);
+            if (i < classElements.length - 1) {
+                pathElements.append("/");
+            }
+        }
+        return pathElements.toString();
     }
 
-    @Override
-    public String toString() {
-        return "SourceIdentifier { resourcePath=" + resource.getPath() + ", fqcn=" + fullyQualifiedName + " }";
+    /**
+     * Mangle the specified character to create a legal Java class name.
+     *
+     * @param ch the character to mangle
+     * @return the mangled
+     */
+    public static String mangleChar(char ch) {
+        return String.format("__%04x__", (int) ch);
+    }
+
+    /**
+     * Provided a mangled string (obtained by calling {@link #mangleChar(char)}) it will will return the character that was mangled.
+     *
+     * @param mangled the mangled string
+     * @return the original character
+     */
+    public static char unmangle(String mangled) {
+        String toProcess = mangled.replaceAll("__", "");
+        return (char) Integer.parseInt(toProcess, 16);
+    }
+
+    /**
+     * Test whether the argument is a Java keyword
+     */
+    public static boolean isJavaKeyword(String key) {
+        return javaKeywords.contains(key);
     }
 }

Added: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java?rev=1748750&view=auto
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java (added)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java Thu Jun 16 16:07:57 2016
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.impl.engine.extension;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
+
+@Component
+@Service(RuntimeExtension.class)
+@Properties({
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.FORMAT)
+})
+public class FormatFilterExtension implements RuntimeExtension {
+
+    private static final Pattern PLACEHOLDER_REGEX = Pattern.compile("\\{\\d+}");
+
+    @Override
+    public Object call(final RenderContext renderContext, Object... arguments) {
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.FORMAT, arguments, 2);
+        RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+        String source = runtimeObjectModel.toString(arguments[0]);
+        Object[] params = decodeParams(runtimeObjectModel, arguments[1]);
+        return replace(runtimeObjectModel, source, params);
+    }
+
+    private Object[] decodeParams(RuntimeObjectModel runtimeObjectModel, Object paramObj) {
+        if (runtimeObjectModel.isCollection(paramObj)) {
+            return runtimeObjectModel.toCollection(paramObj).toArray();
+        }
+        return new Object[] {paramObj};
+    }
+
+    private String replace(RuntimeObjectModel runtimeObjectModel, String source, Object[] params) {
+        Matcher matcher = PLACEHOLDER_REGEX.matcher(source);
+        StringBuilder builder = new StringBuilder();
+        int lastPos = 0;
+        boolean matched = true;
+        while (matched) {
+            matched = matcher.find();
+            if (matched) {
+                String group = matcher.group();
+                int paramIndex = Integer.parseInt(group.substring(1, group.length() - 1));
+                String replacement = param(runtimeObjectModel, params, paramIndex);
+                int matchStart = matcher.start();
+                int matchEnd = matcher.end();
+                builder.append(source, lastPos, matchStart).append(replacement);
+                lastPos = matchEnd;
+            }
+        }
+        builder.append(source, lastPos, source.length());
+        return builder.toString();
+    }
+
+    private String param(RuntimeObjectModel runtimeObjectModel, Object[] params, int index) {
+        if (index >= 0 && index < params.length) {
+            return runtimeObjectModel.toString(params[index]);
+        }
+        return "";
+    }
+}

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java Thu Jun 16 16:07:57 2016
@@ -31,20 +31,20 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.i18n.ResourceBundleProvider;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
-import org.apache.sling.scripting.sightly.impl.filter.I18nFilter;
-import org.apache.sling.scripting.sightly.impl.utils.RenderUtils;
+import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component
 @Service(RuntimeExtension.class)
 @Properties({
-        @Property(name = RuntimeExtension.NAME, value = I18nFilter.FUNCTION)
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.I18N)
 })
 public class I18nRuntimeExtension implements RuntimeExtension {
 
@@ -52,19 +52,20 @@ public class I18nRuntimeExtension implem
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) {
-        ExtensionUtils.checkArgumentCount(I18nFilter.FUNCTION, arguments, 2);
-        String text = RenderUtils.toString(arguments[0]);
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.I18N, arguments, 2);
+        RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+        String text = runtimeObjectModel.toString(arguments[0]);
         Map<String, Object> options = (Map<String, Object>) arguments[1];
-        String locale = RenderUtils.toString(options.get(I18nFilter.LOCALE_OPTION));
-        String hint = RenderUtils.toString(options.get(I18nFilter.HINT_OPTION));
+        String locale = runtimeObjectModel.toString(options.get("locale"));
+        String hint = runtimeObjectModel.toString(options.get("hint"));
         final Bindings bindings = renderContext.getBindings();
         return get(bindings, text, locale, hint);
     }
 
     private String get(final Bindings bindings, String text, String locale, String hint) {
 
-        final SlingScriptHelper slingScriptHelper = (SlingScriptHelper) bindings.get(SlingBindings.SLING);
-        final SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+        final SlingScriptHelper slingScriptHelper = BindingsUtils.getHelper(bindings);
+        final SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
         final ResourceBundleProvider resourceBundleProvider = slingScriptHelper.getService(ResourceBundleProvider.class);
         if (resourceBundleProvider != null) {
             String key = text;

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java Thu Jun 16 16:07:57 2016
@@ -31,26 +31,25 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.api.servlets.ServletResolver;
 import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
-import org.apache.sling.scripting.sightly.impl.plugin.IncludePlugin;
-import org.apache.sling.scripting.sightly.impl.utils.RenderUtils;
+import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Runtime support for including resources in a Sightly script through {@code data-sly-include}.
+ */
 @Component
 @Service(RuntimeExtension.class)
 @Properties({
-        @Property(name = RuntimeExtension.NAME, value = IncludePlugin.FUNCTION)
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.INCLUDE)
 })
-/**
- * Runtime support for including resources in a Sightly script through {@code data-sly-include}. For more details check the implementation
- * of the {@link org.apache.sling.scripting.sightly.impl.plugin.IncludePlugin}.
- */
 public class IncludeRuntimeExtension implements RuntimeExtension {
 
     private static final Logger LOG = LoggerFactory.getLogger(IncludeRuntimeExtension.class);
@@ -61,8 +60,9 @@ public class IncludeRuntimeExtension imp
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) {
-        ExtensionUtils.checkArgumentCount(IncludePlugin.FUNCTION, arguments, 2);
-        String originalPath = RenderUtils.toString(arguments[0]);
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.INCLUDE, arguments, 2);
+        RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+        String originalPath = runtimeObjectModel.toString(arguments[0]);
         Map options = (Map) arguments[1];
         String path = buildPath(originalPath, options);
         StringWriter output = new StringWriter();
@@ -95,14 +95,14 @@ public class IncludeRuntimeExtension imp
             throw new SightlyException("Path for data-sly-include is empty");
         } else {
             LOG.debug("Attempting to include script {}.", script);
-            SlingScriptHelper slingScriptHelper = (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+            SlingScriptHelper slingScriptHelper = BindingsUtils.getHelper(bindings);
             ServletResolver servletResolver = slingScriptHelper.getService(ServletResolver.class);
             if (servletResolver != null) {
-                SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+                SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
                 Servlet servlet = servletResolver.resolveServlet(request.getResource(), script);
                 if (servlet != null) {
                     try {
-                        SlingHttpServletResponse response = (SlingHttpServletResponse) bindings.get(SlingBindings.RESPONSE);
+                        SlingHttpServletResponse response = BindingsUtils.getResponse(bindings);
                         PrintWriterResponseWrapper resWrapper = new PrintWriterResponseWrapper(out, response);
                         servlet.service(request, resWrapper);
                     } catch (Exception e) {

Added: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java?rev=1748750&view=auto
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java (added)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java Thu Jun 16 16:07:57 2016
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.impl.engine.extension;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
+
+@Component
+@Service(RuntimeExtension.class)
+@Properties({
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.JOIN)
+})
+public class JoinFilterExtension implements RuntimeExtension {
+
+    @Override
+    public Object call(final RenderContext renderContext, Object... arguments) {
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.JOIN, arguments, 2);
+        Object joinArgument = arguments[0];
+        RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+        Collection<?> collection = runtimeObjectModel.toCollection(joinArgument);
+        String joinString = runtimeObjectModel.toString(arguments[1]);
+        return join(runtimeObjectModel, collection, joinString);
+    }
+
+    private String join(RuntimeObjectModel runtimeObjectModel, Collection<?> collection, String joinString) {
+        StringBuilder sb = new StringBuilder();
+        Iterator<?> iterator = collection.iterator();
+        while (iterator.hasNext()) {
+            String element = runtimeObjectModel.toString(iterator.next());
+            sb.append(element);
+            if (iterator.hasNext()) {
+                sb.append(joinString);
+            }
+        }
+        return sb.toString();
+    }
+
+}

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java Thu Jun 16 16:07:57 2016
@@ -26,7 +26,6 @@ import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
-
 import javax.script.Bindings;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
@@ -43,24 +42,22 @@ import org.apache.sling.api.resource.Non
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.SyntheticResource;
-import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
-import org.apache.sling.scripting.sightly.impl.plugin.ResourcePlugin;
+import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Runtime support for including resources in a Sightly script through {@code data-sly-resource}. For more details check the implementation
- * of the {@link org.apache.sling.scripting.sightly.impl.plugin.ResourcePlugin}.
+ * Runtime support for including resources in a Sightly script through {@code data-sly-resource}.
  */
 @Component
 @Service(RuntimeExtension.class)
 @Properties(
-        @Property(name = RuntimeExtension.NAME, value = ResourcePlugin.FUNCTION)
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.RESOURCE)
 )
-@SuppressWarnings("unused")
 public class ResourceRuntimeExtension implements RuntimeExtension {
 
     private static final Logger LOG = LoggerFactory.getLogger(ResourceRuntimeExtension.class);
@@ -74,18 +71,17 @@ public class ResourceRuntimeExtension im
     private static final String OPTION_REPLACE_SELECTORS = "replaceSelectors";
 
     @Override
-    @SuppressWarnings("unchecked")
     public Object call(final RenderContext renderContext, Object... arguments) {
-        ExtensionUtils.checkArgumentCount(ResourcePlugin.FUNCTION, arguments, 2);
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.RESOURCE, arguments, 2);
         return provideResource(renderContext, arguments[0], (Map<String, Object>) arguments[1]);
     }
 
     private String provideResource(final RenderContext renderContext, Object pathObj, Map<String, Object> options) {
-        Map<String, Object> opts = new HashMap<String, Object>(options);
+        Map<String, Object> opts = new HashMap<>(options);
         PathInfo pathInfo = new PathInfo(coerceString(pathObj));
         String path = pathInfo.path;
         final Bindings bindings = renderContext.getBindings();
-        String finalPath = buildPath(path, opts, (Resource) bindings.get(SlingBindings.RESOURCE));
+        String finalPath = buildPath(path, opts, BindingsUtils.getResource(bindings));
         String resourceType = coerceString(getAndRemoveOption(opts, OPTION_RESOURCE_TYPE));
         Map<String, String> dispatcherOptionsMap = handleSelectors(bindings, pathInfo.selectors, opts);
         String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap);
@@ -97,46 +93,22 @@ public class ResourceRuntimeExtension im
 
     private Map<String, String> handleSelectors(Bindings bindings, Set<String> selectors, Map<String, Object> options) {
         if (selectors.isEmpty()) {
-            SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+            SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
             selectors.addAll(Arrays.asList(request.getRequestPathInfo().getSelectors()));
         }
-        Map<String, String> dispatcherOptionsMap = new HashMap<String, String>();
+        Map<String, String> dispatcherOptionsMap = new HashMap<>();
         dispatcherOptionsMap.put(OPTION_ADD_SELECTORS, getSelectorString(selectors));
         dispatcherOptionsMap.put(OPTION_REPLACE_SELECTORS, " ");
         if (options.containsKey(OPTION_SELECTORS)) {
             Object selectorsObject = getAndRemoveOption(options, OPTION_SELECTORS);
             selectors.clear();
-            if (selectorsObject instanceof String) {
-                String selectorString = (String) selectorsObject;
-                String[] parts = selectorString.split("\\.");
-                selectors.addAll(Arrays.asList(parts));
-            } else if (selectorsObject instanceof Object[]) {
-                for (Object s : (Object[]) selectorsObject) {
-                    String selector = coerceString(s);
-                    if (StringUtils.isNotEmpty(selector)) {
-                        selectors.add(selector);
-                    }
-                }
-            }
+            addSelectors(selectors, selectorsObject);
             dispatcherOptionsMap.put(OPTION_ADD_SELECTORS, getSelectorString(selectors));
             dispatcherOptionsMap.put(OPTION_REPLACE_SELECTORS, " ");
         }
         if (options.containsKey(OPTION_ADD_SELECTORS)) {
             Object selectorsObject = getAndRemoveOption(options, OPTION_ADD_SELECTORS);
-            if (selectorsObject instanceof String) {
-                String selectorString = (String) selectorsObject;
-                String[] parts = selectorString.split("\\.");
-                for (String s : parts) {
-                    selectors.add(s);
-                }
-            } else if (selectorsObject instanceof Object[]) {
-                for (Object s : (Object[]) selectorsObject) {
-                    String selector = coerceString(s);
-                    if (StringUtils.isNotEmpty(selector)) {
-                        selectors.add(selector);
-                    }
-                }
-            }
+            addSelectors(selectors, selectorsObject);
             dispatcherOptionsMap.put(OPTION_ADD_SELECTORS, getSelectorString(selectors));
             dispatcherOptionsMap.put(OPTION_REPLACE_SELECTORS, " ");
         }
@@ -169,6 +141,21 @@ public class ResourceRuntimeExtension im
         return dispatcherOptionsMap;
     }
 
+    private void addSelectors(Set<String> selectors, Object selectorsObject) {
+        if (selectorsObject instanceof String) {
+            String selectorString = (String) selectorsObject;
+            String[] parts = selectorString.split("\\.");
+            selectors.addAll(Arrays.asList(parts));
+        } else if (selectorsObject instanceof Object[]) {
+            for (Object s : (Object[]) selectorsObject) {
+                String selector = coerceString(s);
+                if (StringUtils.isNotEmpty(selector)) {
+                    selectors.add(selector);
+                }
+            }
+        }
+    }
+
     private String buildPath(Object pathObj, Map<String, Object> options, Resource currentResource) {
         String prependPath = getOption(OPTION_PREPEND_PATH, options, StringUtils.EMPTY);
         if (prependPath == null) {
@@ -244,9 +231,8 @@ public class ResourceRuntimeExtension im
         if (StringUtils.isEmpty(script)) {
             LOG.error("Script path cannot be empty");
         } else {
-            SlingHttpServletResponse customResponse = new PrintWriterResponseWrapper(out,
-                    (SlingHttpServletResponse) bindings.get(SlingBindings.RESPONSE));
-            SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+            SlingHttpServletResponse customResponse = new PrintWriterResponseWrapper(out, BindingsUtils.getResponse(bindings));
+            SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
             script = normalizePath(request, script);
 
             Resource includeRes = request.getResourceResolver().resolve(script);
@@ -291,7 +277,7 @@ public class ResourceRuntimeExtension im
     }
 
     private Set<String> getSelectorsFromPath(String path) {
-        Set<String> selectors = new LinkedHashSet<String>();
+        Set<String> selectors = new LinkedHashSet<>();
         if (path != null) {
             String processingPath = path;
             int lastSlashPos = path.lastIndexOf('/');

Copied: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java (from r1748726, sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java?p2=sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java&p1=sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java&r1=1748726&r2=1748750&rev=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java Thu Jun 16 16:07:57 2016
@@ -7,7 +7,7 @@
  * "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
+ *  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
@@ -16,44 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  ******************************************************************************/
-package org.apache.sling.scripting.sightly.impl.filter;
+package org.apache.sling.scripting.sightly.impl.engine.extension;
 
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
-import org.apache.sling.scripting.sightly.impl.compiler.expression.Expression;
-import org.apache.sling.scripting.sightly.impl.compiler.expression.ExpressionNode;
-import org.apache.sling.scripting.sightly.impl.compiler.expression.node.MapLiteral;
-import org.apache.sling.scripting.sightly.impl.compiler.expression.node.RuntimeCall;
-import org.apache.sling.scripting.sightly.impl.engine.extension.ExtensionUtils;
-import org.apache.sling.scripting.sightly.impl.utils.PathInfo;
-import org.apache.sling.scripting.sightly.impl.utils.RenderUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
 
-/**
- * The {@code URIManipulationFilter} provides support for Sightly's URI Manipulation options according to the
- * <a href="https://github.com/Adobe-Marketing-Cloud/sightly-spec/blob/1.1/SPECIFICATION.md">language specification</a>
- */
 @Component
-@Service({Filter.class, RuntimeExtension.class})
+@Service(RuntimeExtension.class)
 @Properties({
-        @Property(name = RuntimeExtension.NAME, value = URIManipulationFilter.URI_MANIPULATION_FUNCTION)
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.URI_MANIPULATION)
 })
-public class URIManipulationFilter extends FilterComponent implements RuntimeExtension {
-
-    public static final String URI_MANIPULATION_FUNCTION = "uriManipulation";
+public class URIManipulationFilterExtension implements RuntimeExtension {
 
     public static final String SCHEME = "scheme";
     public static final String DOMAIN = "domain";
@@ -72,34 +64,14 @@ public class URIManipulationFilter exten
     public static final String ADD_QUERY = "addQuery";
     public static final String REMOVE_QUERY = "removeQuery";
 
-    @Override
-    public Expression apply(Expression expression, ExpressionContext expressionContext) {
-        if ((expression.containsOption(SCHEME) || expression.containsOption(DOMAIN) || expression.containsOption(PATH) || expression
-                .containsOption(APPEND_PATH) || expression.containsOption(PREPEND_PATH) || expression.containsOption(SELECTORS) ||
-                expression.containsOption(ADD_SELECTORS) || expression.containsOption(REMOVE_SELECTORS) || expression.containsOption
-                (EXTENSION) || expression.containsOption(SUFFIX) || expression.containsOption(PREPEND_SUFFIX) || expression
-                .containsOption(APPEND_SUFFIX) || expression.containsOption(FRAGMENT) || expression.containsOption(QUERY) || expression
-                .containsOption(ADD_QUERY) || expression.containsOption(REMOVE_QUERY)) && expressionContext != ExpressionContext
-                .PLUGIN_DATA_SLY_USE && expressionContext
-                != ExpressionContext.PLUGIN_DATA_SLY_TEMPLATE && expressionContext != ExpressionContext.PLUGIN_DATA_SLY_CALL &&
-                expressionContext != ExpressionContext.PLUGIN_DATA_SLY_RESOURCE) {
-            Map<String, ExpressionNode> uriOptions = getFilterOptions(expression, SCHEME, DOMAIN, PATH, APPEND_PATH, PREPEND_PATH,
-                    SELECTORS, ADD_SELECTORS, REMOVE_SELECTORS, EXTENSION, SUFFIX, PREPEND_SUFFIX, APPEND_SUFFIX, FRAGMENT, QUERY,
-                    ADD_QUERY, REMOVE_QUERY);
-            if (uriOptions.size() > 0) {
-                ExpressionNode translation = new RuntimeCall(URI_MANIPULATION_FUNCTION, expression.getRoot(), new MapLiteral(uriOptions));
-                return expression.withNode(translation);
-            }
-        }
-        return expression;
-    }
 
     @Override
     @SuppressWarnings("unchecked")
     public Object call(RenderContext renderContext, Object... arguments) {
-        ExtensionUtils.checkArgumentCount(URI_MANIPULATION_FUNCTION, arguments, 2);
-        String uriString = RenderUtils.toString(arguments[0]);
-        Map<String, Object> options = RenderUtils.toMap(arguments[1]);
+        ExtensionUtils.checkArgumentCount(RuntimeFunction.URI_MANIPULATION, arguments, 2);
+        RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+        String uriString = runtimeObjectModel.toString(arguments[0]);
+        Map<String, Object> options = runtimeObjectModel.toMap(arguments[1]);
         StringBuilder sb = new StringBuilder();
         PathInfo pathInfo = new PathInfo(uriString);
         uriAppender(sb, SCHEME, options, pathInfo.getScheme());
@@ -155,7 +127,7 @@ public class URIManipulationFilter exten
         }
         sb.append(newPath);
         Set<String> selectors = pathInfo.getSelectors();
-        handleSelectors(selectors, options);
+        handleSelectors(runtimeObjectModel, selectors, options);
         for (String selector : selectors) {
             if (StringUtils.isNotBlank(selector) && !selector.contains(" ")) {
                 // make sure not to append empty or invalid selectors
@@ -185,7 +157,7 @@ public class URIManipulationFilter exten
         if (StringUtils.isNotEmpty(appendSuffix)) {
             appendSuffix = "/" + appendSuffix;
         }
-        String newSuffix = ResourceUtil.normalize(prependSuffix + suffix + appendSuffix);
+        String newSuffix = FilenameUtils.normalize(prependSuffix + suffix + appendSuffix, true);
         if (StringUtils.isNotEmpty(newSuffix)) {
             if (!newSuffix.startsWith("/")) {
                 sb.append("/");
@@ -193,7 +165,7 @@ public class URIManipulationFilter exten
             sb.append(newSuffix);
         }
         Map<String, Collection<String>> parameters = pathInfo.getParameters();
-        handleParameters(parameters, options);
+        handleParameters(runtimeObjectModel, parameters, options);
         if (!parameters.isEmpty()) {
             sb.append("?");
             for (Map.Entry<String, Collection<String>> entry : parameters.entrySet()) {
@@ -230,7 +202,7 @@ public class URIManipulationFilter exten
         return defaultValue;
     }
 
-    private void handleSelectors(Set<String> selectors, Map<String, Object> options) {
+    private void handleSelectors(RuntimeObjectModel runtimeObjectModel, Set<String> selectors, Map<String, Object> options) {
         if (options.containsKey(SELECTORS)) {
             Object selectorsOption = options.get(SELECTORS);
             if (selectorsOption == null) {
@@ -245,7 +217,7 @@ public class URIManipulationFilter exten
                 String[] selectorsArray = new String[selectorsURIArray.length];
                 int index = 0;
                 for (Object selector : selectorsURIArray) {
-                    selectorsArray[index++] = RenderUtils.toString(selector);
+                    selectorsArray[index++] = runtimeObjectModel.toString(selector);
                 }
                 replaceSelectors(selectors, selectorsArray);
             }
@@ -260,7 +232,7 @@ public class URIManipulationFilter exten
             String[] selectorsArray = new String[selectorsURIArray.length];
             int index = 0;
             for (Object selector : selectorsURIArray) {
-                selectorsArray[index++] = RenderUtils.toString(selector);
+                selectorsArray[index++] = runtimeObjectModel.toString(selector);
             }
             addSelectors(selectors, selectorsArray);
         }
@@ -274,7 +246,7 @@ public class URIManipulationFilter exten
             String[] selectorsArray = new String[selectorsURIArray.length];
             int index = 0;
             for (Object selector : selectorsURIArray) {
-                selectorsArray[index++] = RenderUtils.toString(selector);
+                selectorsArray[index++] = runtimeObjectModel.toString(selector);
             }
             removeSelectors(selectors, selectorsArray);
         }
@@ -295,45 +267,18 @@ public class URIManipulationFilter exten
     }
 
     @SuppressWarnings("unchecked")
-    private void handleParameters(Map<String, Collection<String>> parameters, Map<String, Object> options) {
+    private void handleParameters(RuntimeObjectModel runtimeObjectModel, Map<String, Collection<String>> parameters, Map<String, Object>
+            options) {
         if (options.containsKey(QUERY)) {
             Object queryOption = options.get(QUERY);
             parameters.clear();
-            Map<String, Object> queryParameters = RenderUtils.toMap(queryOption);
-            for (Map.Entry<String, Object> entry : queryParameters.entrySet()) {
-                Object entryValue = entry.getValue();
-                if (RenderUtils.isCollection(entryValue)) {
-                    Collection<Object> collection = RenderUtils.toCollection(entryValue);
-                    Collection<String> values = new ArrayList<String>(collection.size());
-                    for (Object o : collection) {
-                        values.add(RenderUtils.toString(o));
-                    }
-                    parameters.put(entry.getKey(), values);
-                } else {
-                    Collection<String> values = new ArrayList<String>(1);
-                    values.add(RenderUtils.toString(entryValue));
-                    parameters.put(entry.getKey(), values);
-                }
-            }
+            Map<String, Object> queryParameters = runtimeObjectModel.toMap(queryOption);
+            addQueryParameters(runtimeObjectModel, parameters, queryParameters);
         }
         Object addQueryOption = options.get(ADD_QUERY);
         if (addQueryOption != null) {
-            Map<String, Object> addParams = RenderUtils.toMap(addQueryOption);
-            for (Map.Entry<String, Object> entry : addParams.entrySet()) {
-                Object entryValue = entry.getValue();
-                if (RenderUtils.isCollection(entryValue)) {
-                    Collection<Object> collection = RenderUtils.toCollection(entryValue);
-                    Collection<String> values = new ArrayList<String>(collection.size());
-                    for (Object o : collection) {
-                        values.add(RenderUtils.toString(o));
-                    }
-                    parameters.put(entry.getKey(), values);
-                } else {
-                    Collection<String> values = new ArrayList<String>(1);
-                    values.add(RenderUtils.toString(entryValue));
-                    parameters.put(entry.getKey(), values);
-                }
-            }
+            Map<String, Object> addParams = runtimeObjectModel.toMap(addQueryOption);
+            addQueryParameters(runtimeObjectModel, parameters, addParams);
         }
         Object removeQueryOption = options.get(REMOVE_QUERY);
         if (removeQueryOption != null) {
@@ -342,7 +287,7 @@ public class URIManipulationFilter exten
             } else if (removeQueryOption instanceof Object[]) {
                 Object[] removeQueryParamArray = (Object[]) removeQueryOption;
                 for (Object param : removeQueryParamArray) {
-                    String paramString = RenderUtils.toString(param);
+                    String paramString = runtimeObjectModel.toString(param);
                     if (paramString != null) {
                         parameters.remove(paramString);
                     }
@@ -350,4 +295,216 @@ public class URIManipulationFilter exten
             }
         }
     }
+
+    private void addQueryParameters(RuntimeObjectModel runtimeObjectModel, Map<String, Collection<String>> parameters, Map<String, Object>
+            queryParameters) {
+        for (Map.Entry<String, Object> entry : queryParameters.entrySet()) {
+            Object entryValue = entry.getValue();
+            if (runtimeObjectModel.isCollection(entryValue)) {
+                Collection<Object> collection = runtimeObjectModel.toCollection(entryValue);
+                Collection<String> values = new ArrayList<>(collection.size());
+                for (Object o : collection) {
+                    values.add(runtimeObjectModel.toString(o));
+                }
+                parameters.put(entry.getKey(), values);
+            } else {
+                Collection<String> values = new ArrayList<>(1);
+                values.add(runtimeObjectModel.toString(entryValue));
+                parameters.put(entry.getKey(), values);
+            }
+        }
+    }
+
+    public static class PathInfo {
+
+        private URI uri;
+        private String path;
+        private Set<String> selectors;
+        private String selectorString;
+        private String extension;
+        private String suffix;
+        private Map<String, Collection<String>> parameters = new LinkedHashMap<>();
+
+        /**
+         * Creates a {@code PathInfo} object based on a request path.
+         *
+         * @param path the full normalized path (no '.', '..', or double slashes8) of the request, including the query parameters
+         * @throws NullPointerException if the supplied {@code path} is null
+         */
+        public PathInfo(String path) {
+            if (path == null) {
+                throw new NullPointerException("The path parameter cannot be null.");
+            }
+            try {
+                uri = new URI(path);
+            } catch (URISyntaxException e) {
+                throw new SightlyException("The provided path does not represent a valid URI: " + path);
+            }
+            selectors = new LinkedHashSet<>();
+            String processingPath = path;
+            if (uri.getPath() != null) {
+                processingPath = uri.getPath();
+            }
+            int lastDot = processingPath.lastIndexOf('.');
+            if (lastDot > -1) {
+                String afterLastDot = processingPath.substring(lastDot + 1);
+                String[] parts = afterLastDot.split("/");
+                extension = parts[0];
+                if (parts.length > 1) {
+                    // we have a suffix
+                    StringBuilder suffixSB = new StringBuilder();
+                    for (int i = 1; i < parts.length; i++) {
+                        suffixSB.append("/").append(parts[i]);
+                    }
+                    int hashIndex = suffixSB.indexOf("#");
+                    if (hashIndex > -1) {
+                        suffix = suffixSB.substring(0, hashIndex);
+                    } else {
+                        suffix = suffixSB.toString();
+                    }
+                }
+            }
+            int firstDot = processingPath.indexOf('.');
+            if (firstDot < lastDot) {
+                selectorString = processingPath.substring(firstDot + 1, lastDot);
+                String[] selectorsArray = selectorString.split("\\.");
+                selectors.addAll(Arrays.asList(selectorsArray));
+            }
+            int pathLength = processingPath.length() - (selectorString == null ? 0 : selectorString.length() + 1) - (extension == null ? 0:
+                    extension.length() + 1) - (suffix == null ? 0 : suffix.length());
+            if (pathLength == processingPath.length()) {
+                this.path = processingPath;
+            } else {
+                this.path = processingPath.substring(0, pathLength);
+            }
+            String query = uri.getQuery();
+            if (StringUtils.isNotEmpty(query)) {
+                String[] keyValuePairs = query.split("&");
+                for (int i = 0; i < keyValuePairs.length; i++) {
+                    String[] pair = keyValuePairs[i].split("=");
+                    if (pair.length == 2) {
+                        String param = pair[0];
+                        String value = pair[1];
+                        Collection<String> values = parameters.get(param);
+                        if (values == null) {
+                            values = new ArrayList<>();
+                            parameters.put(param, values);
+                        }
+                        values.add(value);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Returns the scheme of this path if the path corresponds to a URI and if the URI provides scheme information.
+         *
+         * @return the scheme or {@code null} if the path does not contain a scheme
+         */
+        public String getScheme() {
+            return uri.getScheme();
+        }
+
+        /**
+         * Returns the path separator ("//") if the path defines an absolute URI.
+         *
+         * @return the path separator if the path is an absolute URI, {@code null} otherwise
+         */
+        public String getBeginPathSeparator() {
+            if (uri.isAbsolute()) {
+                return "//";
+            }
+            return null;
+        }
+
+        /**
+         * Returns the host part of the path, if the path defines a URI.
+         *
+         * @return the host if the path defines a URI, {@code null} otherwise
+         */
+        public String getHost() {
+            return uri.getHost();
+        }
+
+        /**
+         * Returns the port if the path defines a URI and if it contains port information.
+         *
+         * @return the port or -1 if no port is defined
+         */
+        public int getPort() {
+            return uri.getPort();
+        }
+
+        /**
+         * Returns the path from which <i>{@code this}</i> object was built.
+         *
+         * @return the original path
+         */
+        public String getFullPath() {
+            return uri.toString();
+        }
+
+        /**
+         * Returns the path identifying the resource, without any selectors, extension or query parameters.
+         *
+         * @return the path of the resource
+         */
+        public String getPath() {
+            return path;
+        }
+
+        /**
+         * Returns the selectors set.
+         *
+         * @return the selectors set; if there are no selectors the set will be empty
+         */
+        public Set<String> getSelectors() {
+            return selectors;
+        }
+
+        /**
+         * Returns the extension.
+         *
+         * @return the extension, if one exists, otherwise {@code null}
+         */
+        public String getExtension() {
+            return extension;
+        }
+
+        /**
+         * Returns the selector string.
+         *
+         * @return the selector string, if the path has selectors, otherwise {@code null}
+         */
+        public String getSelectorString() {
+            return selectorString;
+        }
+
+        /**
+         * Returns the suffix appended to the path. The suffix represents the path segment between the path's extension and the path's fragment.
+         *
+         * @return the suffix if the path contains one, {@code null} otherwise
+         */
+        public String getSuffix() {
+            return suffix;
+        }
+
+        /**
+         * Returns the fragment is this path defines a URI and it contains a fragment.
+         *
+         * @return the fragment, or {@code null} if one doesn't exist
+         */
+        public String getFragment() {
+            return uri.getFragment();
+        }
+
+        /**
+         * Returns the URI parameters if the provided path defines a URI.
+         * @return the parameters map; can be empty if there are no parameters of if the path doesn't identify a URI
+         */
+        public Map<String, Collection<String>> getParameters() {
+            return parameters;
+        }
+    }
+
 }

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java Thu Jun 16 16:07:57 2016
@@ -16,13 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  ******************************************************************************/
-
 package org.apache.sling.scripting.sightly.impl.engine.extension;
 
 import java.util.HashSet;
 import java.util.Set;
 import java.util.regex.Pattern;
-
 import javax.script.Bindings;
 
 import org.apache.felix.scr.annotations.Component;
@@ -31,12 +29,10 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
+import org.apache.sling.scripting.sightly.compiler.expression.MarkupContext;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
-import org.apache.sling.scripting.sightly.impl.compiler.CompilerException;
-import org.apache.sling.scripting.sightly.impl.filter.XSSFilter;
-import org.apache.sling.scripting.sightly.impl.html.MarkupUtils;
-import org.apache.sling.scripting.sightly.impl.plugin.MarkupContext;
-import org.apache.sling.scripting.sightly.impl.utils.RenderUtils;
+import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.xss.XSSAPI;
 import org.slf4j.Logger;
@@ -48,19 +44,20 @@ import org.slf4j.LoggerFactory;
 @Component
 @Service(RuntimeExtension.class)
 @Properties(
-        @Property(name = RuntimeExtension.NAME, value = XSSFilter.FUNCTION_NAME)
+        @Property(name = RuntimeExtension.NAME, value = RuntimeFunction.XSS)
 )
 public class XSSRuntimeExtension implements RuntimeExtension {
 
     private static final Set<String> elementNameWhiteList = new HashSet<String>();
     private static final Logger LOG = LoggerFactory.getLogger(XSSRuntimeExtension.class);
     private static final Pattern VALID_ATTRIBUTE = Pattern.compile("^[a-zA-Z_:][\\-a-zA-Z0-9_:\\.]*$");
+    private static final Pattern ATTRIBUTE_BLACKLIST = Pattern.compile("^(style|(on.*))$", Pattern.CASE_INSENSITIVE);
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) {
         if (arguments.length < 2) {
             throw new SightlyException(
-                    String.format("Extension %s requires at least %d arguments", XSSFilter.FUNCTION_NAME, 2));
+                    String.format("Extension %s requires at least %d arguments", RuntimeFunction.XSS, 2));
         }
         Object original = arguments[0];
         Object option = arguments[1];
@@ -80,7 +77,7 @@ public class XSSRuntimeExtension impleme
             LOG.warn("Expression context {} is invalid, expression will be replaced by the empty string", option);
             return "";
         }
-        String text = RenderUtils.toString(original);
+        String text = renderContext.getObjectModel().toString(original);
         final XSSAPI xssapi = obtainAPI(renderContext.getBindings());
         return applyXSSFilter(xssapi, text, hint, markupContext);
     }
@@ -104,7 +101,10 @@ public class XSSRuntimeExtension impleme
             case ATTRIBUTE_NAME:
                 return escapeAttributeName(text);
             case NUMBER:
-                return xssapi.getValidLong(text, 0).toString();
+                Long result = xssapi.getValidLong(text, 0);
+                if (result != null) {
+                    return result.toString();
+                }
             case URI:
                 return xssapi.getValidHref(text);
             case SCRIPT_TOKEN:
@@ -135,9 +135,9 @@ public class XSSRuntimeExtension impleme
     }
 
     private XSSAPI obtainAPI(Bindings bindings) {
-        SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get("request");
+        SlingHttpServletRequest request = BindingsUtils.getRequest(bindings);
         if (request == null) {
-            throw new CompilerException("Cannot obtain request from bindings");
+            throw new SightlyException("Cannot obtain request from bindings");
         }
         return request.adaptTo(XSSAPI.class);
     }
@@ -154,7 +154,7 @@ public class XSSRuntimeExtension impleme
             return null;
         }
         attributeName = attributeName.trim();
-        if (matchPattern(VALID_ATTRIBUTE, attributeName) && !MarkupUtils.isSensitiveAttribute(attributeName)) {
+        if (matchPattern(VALID_ATTRIBUTE, attributeName) && !isSensitiveAttribute(attributeName)) {
             return attributeName;
         }
         return null;
@@ -234,4 +234,7 @@ public class XSSRuntimeExtension impleme
         elementNameWhiteList.add("th");
     }
 
+    private boolean isSensitiveAttribute(String name) {
+        return ATTRIBUTE_BLACKLIST.matcher(name).matches();
+    }
 }

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java Thu Jun 16 16:07:57 2016
@@ -31,11 +31,10 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.scripting.sightly.impl.compiler.SightlyJavaCompilerService;
-import org.apache.sling.scripting.sightly.impl.compiler.UnitChangeMonitor;
+import org.apache.sling.scripting.sightly.impl.engine.SightlyJavaCompilerService;
+import org.apache.sling.scripting.sightly.impl.engine.UnitChangeMonitor;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.pojo.Use;
 import org.apache.sling.scripting.sightly.render.RenderContext;
@@ -83,7 +82,7 @@ public class JavaUseProvider implements
         }
         Bindings globalBindings = renderContext.getBindings();
         SlingScriptHelper sling = BindingsUtils.getHelper(globalBindings);
-        SlingHttpServletRequest request = (SlingHttpServletRequest) globalBindings.get(SlingBindings.REQUEST);
+        SlingHttpServletRequest request = BindingsUtils.getRequest(globalBindings);
         Map<String, Object> overrides = setRequestAttributes(request, arguments);
 
         Object result;
@@ -106,7 +105,7 @@ public class JavaUseProvider implements
             }
             result = request.adaptTo(cls);
             if (result == null) {
-                Resource resource = (Resource) globalBindings.get(SlingBindings.RESOURCE);
+                Resource resource = BindingsUtils.getResource(globalBindings);
                 result = resource.adaptTo(cls);
             }
             if (result != null) {
@@ -141,7 +140,7 @@ public class JavaUseProvider implements
     }
 
     private Map<String, Object> setRequestAttributes(ServletRequest request, Bindings arguments) {
-        Map<String, Object> overrides = new HashMap<String, Object>();
+        Map<String, Object> overrides = new HashMap<>();
         for (Map.Entry<String, Object> entry : arguments.entrySet()) {
             String key = entry.getKey();
             Object value = entry.getValue();

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java Thu Jun 16 16:07:57 2016
@@ -19,7 +19,11 @@
 
 package org.apache.sling.scripting.sightly.impl.engine.extension.use;
 
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import javax.script.Bindings;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngineManager;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.felix.scr.annotations.Component;
@@ -27,14 +31,19 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.api.CachedScript;
+import org.apache.sling.scripting.api.ScriptCache;
 import org.apache.sling.scripting.sightly.ResourceResolution;
 import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.impl.engine.SightlyCompiledScript;
+import org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngine;
 import org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngineFactory;
-import org.apache.sling.scripting.sightly.impl.engine.UnitLoader;
-import org.apache.sling.scripting.sightly.impl.engine.runtime.RenderUnit;
+import org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
+import org.apache.sling.scripting.sightly.java.compiler.RenderUnit;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.use.ProviderOutcome;
 import org.apache.sling.scripting.sightly.use.UseProvider;
@@ -62,17 +71,21 @@ import org.osgi.framework.Constants;
 public class RenderUnitProvider implements UseProvider {
 
     @Reference
-    private UnitLoader unitLoader;
+    private ScriptCache scriptCache;
+
+    @Reference
+    private ScriptEngineManager scriptEngineManager;
 
     @Override
     public ProviderOutcome provide(String identifier, RenderContext renderContext, Bindings arguments) {
         if (identifier.endsWith("." + SightlyScriptEngineFactory.EXTENSION)) {
+            RenderContextImpl rci  = (RenderContextImpl) renderContext;
             Bindings globalBindings = renderContext.getBindings();
             SlingScriptHelper sling = BindingsUtils.getHelper(globalBindings);
-            Resource renderUnitResource = UseProviderUtils.locateScriptResource(renderContext, identifier);
+            SlingHttpServletRequest request = BindingsUtils.getRequest(globalBindings);
+            final Resource renderUnitResource = rci.resolveScript(identifier);
             if (renderUnitResource == null) {
-                Resource caller = ResourceResolution.getResourceForRequest(sling.getRequest().getResourceResolver(), sling
-                        .getRequest());
+                Resource caller = ResourceResolution.getResourceForRequest(request.getResourceResolver(), request);
                 if (caller != null) {
                     String resourceSuperType = caller.getResourceSuperType();
                     StringBuilder errorMessage = new StringBuilder("Cannot find resource ");
@@ -87,8 +100,35 @@ public class RenderUnitProvider implemen
                             .getScript().getScriptResource().getPath()));
                 }
             }
+            RenderUnit renderUnit;
             try {
-                RenderUnit renderUnit = unitLoader.createUnit(renderUnitResource, renderContext);
+                CachedScript cachedScript = scriptCache.getScript(renderUnitResource.getPath());
+                final SightlyCompiledScript compiledScript;
+                if (cachedScript != null) {
+                    compiledScript = (SightlyCompiledScript) cachedScript.getCompiledScript();
+                } else {
+                    SightlyScriptEngine sightlyScriptEngine =
+                            (SightlyScriptEngine) scriptEngineManager.getEngineByName(SightlyScriptEngineFactory.SHORT_NAME);
+                    InputStream inputStream = renderUnitResource.adaptTo(InputStream.class);
+                    String encoding = renderUnitResource.getResourceMetadata().getCharacterEncoding();
+                    if (StringUtils.isEmpty(encoding)) {
+                        encoding = "UTF-8";
+                    }
+                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, encoding);
+                    compiledScript = (SightlyCompiledScript) sightlyScriptEngine.compile(inputStreamReader);
+                    scriptCache.putScript(new CachedScript() {
+                        @Override
+                        public String getScriptPath() {
+                            return renderUnitResource.getPath();
+                        }
+
+                        @Override
+                        public CompiledScript getCompiledScript() {
+                            return compiledScript;
+                        }
+                    });
+                }
+                renderUnit = compiledScript.getRenderUnit();
                 return ProviderOutcome.success(renderUnit);
             } catch (Exception e) {
                 return ProviderOutcome.failure(e);

Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java?rev=1748750&r1=1748749&r2=1748750&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java (original)
+++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java Thu Jun 16 16:07:57 2016
@@ -30,6 +30,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScript;
 import org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngineFactory;
+import org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.use.ProviderOutcome;
@@ -68,13 +69,14 @@ public class ScriptUseProvider implement
 
     @Override
     public ProviderOutcome provide(String scriptName, RenderContext renderContext, Bindings arguments) {
-        Bindings globalBindings = renderContext.getBindings();
+        RenderContextImpl rci = (RenderContextImpl) renderContext;
+        Bindings globalBindings = rci.getBindings();
         Bindings bindings = BindingsUtils.merge(globalBindings, arguments);
         String extension = scriptExtension(scriptName);
         if (extension == null || extension.equals(SightlyScriptEngineFactory.EXTENSION)) {
             return ProviderOutcome.failure();
         }
-        Resource scriptResource = UseProviderUtils.locateScriptResource(renderContext, scriptName);
+        Resource scriptResource = rci.resolveScript(scriptName);
         if (scriptResource == null) {
             log.debug("Path does not match an existing resource: {}", scriptName);
             return ProviderOutcome.failure();