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 2015/02/16 16:00:23 UTC

svn commit: r1660132 - in /sling/trunk/contrib/scripting/sightly: engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/ engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ engine/src/main/java/org...

Author: radu
Date: Mon Feb 16 15:00:22 2015
New Revision: 1660132

URL: http://svn.apache.org/r1660132
Log:
SLING-4423 - Add support for URI Manipulation options

* added support for URI manipulation options according to the language specification
* modified Expression such that object is not immutable (helps when transforming the same expression over and over by filters)
* defined and ExpressionContext such that filters can choose to process and expression based on this context

Added:
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/ExpressionContext.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/PathInfo.java
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PathInfoTest.java
Modified:
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/Expression.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/CompilerContext.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ExpressionWrapper.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/MarkupHandler.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AttributePlugin.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ElementPlugin.java
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/TextPlugin.java
    sling/trunk/contrib/scripting/sightly/testing-content/pom.xml
    sling/trunk/contrib/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightlytck.json
    sling/trunk/contrib/scripting/sightly/testing/pom.xml

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/Expression.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/Expression.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/Expression.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/expression/Expression.java Mon Feb 16 15:00:22 2015
@@ -44,7 +44,7 @@ public class Expression {
      * @return - the expression options
      */
     public Map<String, ExpressionNode> getOptions() {
-        return Collections.unmodifiableMap(options);
+        return options;
     }
 
     /**
@@ -70,7 +70,7 @@ public class Expression {
      * @param removedOptions the options to be removed
      * @return a copy where the mention options are no longer present
      */
-    public Expression removeOptions(String ... removedOptions) {
+    public Expression withRemovedOptions(String... removedOptions) {
         HashMap<String, ExpressionNode> newOptions = new HashMap<String, ExpressionNode>(options);
         for (String option : removedOptions) {
             newOptions.remove(option);
@@ -79,6 +79,27 @@ public class Expression {
     }
 
     /**
+     * Removes the given options from this expression.
+     *
+     * @param removedOptions the options to be removed
+     */
+    public void removeOptions(String... removedOptions) {
+        for (String option : removedOptions) {
+            options.remove(option);
+        }
+    }
+
+    /**
+     * Removes the given option from this expression.
+     *
+     * @param option the option to be removed
+     * @return the option, or {@code null} if the option doesn't exist
+     */
+    public ExpressionNode removeOption(String option) {
+        return options.remove(option);
+    }
+
+    /**
      * Return a copy, but with the specified node as root
      * @param node the new root
      * @return a copy with a new root

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/CompilerContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/CompilerContext.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/CompilerContext.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/CompilerContext.java Mon Feb 16 15:00:22 2015
@@ -20,6 +20,7 @@ package org.apache.sling.scripting.sight
 
 import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
 import org.apache.sling.scripting.sightly.impl.compiler.expression.Expression;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
 import org.apache.sling.scripting.sightly.impl.plugin.MarkupContext;
 import org.apache.sling.scripting.sightly.impl.compiler.util.SymbolGenerator;
 
@@ -42,9 +43,9 @@ public class CompilerContext {
         return symbolGenerator.next(hint);
     }
 
-    public Expression adjustToContext(Expression expression, MarkupContext context) {
+    public Expression adjustToContext(Expression expression, MarkupContext context, ExpressionContext expressionContext) {
         if (!expression.getOptions().containsKey(Syntax.CONTEXT_OPTION)) {
-            return expressionWrapper.adjustToContext(expression, context);
+            return expressionWrapper.adjustToContext(expression, context, expressionContext);
         }
         return expression;
     }

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ExpressionWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ExpressionWrapper.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ExpressionWrapper.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/frontend/ExpressionWrapper.java Mon Feb 16 15:00:22 2015
@@ -23,15 +23,15 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
-import org.apache.sling.scripting.sightly.impl.filter.Filter;
 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.BinaryOperation;
 import org.apache.sling.scripting.sightly.impl.compiler.expression.node.BinaryOperator;
 import org.apache.sling.scripting.sightly.impl.compiler.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
+import org.apache.sling.scripting.sightly.impl.filter.Filter;
 import org.apache.sling.scripting.sightly.impl.plugin.MarkupContext;
 
 /**
@@ -48,7 +48,7 @@ public class ExpressionWrapper {
         Collections.sort(this.filters);
     }
 
-    public Expression transform(Interpolation interpolation, MarkupContext markupContext) {
+    public Expression transform(Interpolation interpolation, MarkupContext markupContext, ExpressionContext expressionContext) {
         ArrayList<ExpressionNode> nodes = new ArrayList<ExpressionNode>();
         HashMap<String, ExpressionNode> options = new HashMap<String, ExpressionNode>();
         for (Fragment fragment : interpolation.getFragments()) {
@@ -56,8 +56,8 @@ public class ExpressionWrapper {
                 nodes.add(new StringConstant(fragment.getText()));
             } else {
                 Expression expression = fragment.getExpression();
+                nodes.add(adjustToContext(expression, markupContext, expressionContext).getRoot());
                 options.putAll(expression.getOptions());
-                nodes.add(transformExpr(expression, markupContext).getRoot());
             }
         }
         ExpressionNode root = join(nodes);
@@ -68,51 +68,29 @@ public class ExpressionWrapper {
         return new Expression(root, options);
     }
 
-    private Expression applyFilters(Expression expression) {
+    private Expression applyFilters(Expression expression, ExpressionContext expressionContext) {
         Expression result = expression;
         for (Filter filter : filters) {
-            result = filter.apply(result);
+            result = filter.apply(result, expressionContext);
         }
         return result;
     }
 
-    public Expression adjustToContext(Expression expression, MarkupContext markupContext) {
-        if (expression.containsOption(Syntax.CONTEXT_OPTION)) {
-            return expression;
-        }
-        Map<String, ExpressionNode> opt = addDefaultContext(Collections.<String, ExpressionNode>emptyMap(), markupContext);
-        Expression result = applyFilters(new Expression(expression.getRoot(), opt));
-        return expression.withNode(result.getRoot());
+    public Expression adjustToContext(Expression expression, MarkupContext context, ExpressionContext expressionContext) {
+        if (context != null && !expression.containsOption(Syntax.CONTEXT_OPTION)) {
+            expression.getOptions().put(Syntax.CONTEXT_OPTION, new StringConstant(context.getName()));
+        }
+        return applyFilters(expression, expressionContext);
     }
 
     private ExpressionNode join(List<ExpressionNode> nodes) {
         if (nodes.isEmpty()) {
             return StringConstant.EMPTY;
         }
-        ExpressionNode root = nodes.get(0);
-        for (int i = 1; i < nodes.size(); i++) {
-            ExpressionNode node = nodes.get(i);
+        ExpressionNode root = nodes.remove(0);
+        for (ExpressionNode node : nodes) {
             root = new BinaryOperation(BinaryOperator.CONCATENATE, root, node);
         }
         return root;
     }
-
-    private Expression transformExpr(Expression expression, MarkupContext markupContext) {
-        expression = addDefaultContext(expression, markupContext);
-        return applyFilters(expression);
-    }
-
-    private Expression addDefaultContext(Expression expression, MarkupContext context) {
-        return new Expression(expression.getRoot(), addDefaultContext(expression.getOptions(), context));
-    }
-
-    private Map<String, ExpressionNode> addDefaultContext(Map<String, ExpressionNode> options, MarkupContext context) {
-        if (context == null || options.containsKey(Syntax.CONTEXT_OPTION)) {
-            return options;
-        }
-        HashMap<String, ExpressionNode> newOptions = new HashMap<String, ExpressionNode>(options);
-        newOptions.put(Syntax.CONTEXT_OPTION, new StringConstant(context.getName()));
-        return newOptions;
-    }
-
 }

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java Mon Feb 16 15:00:22 2015
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -141,6 +142,14 @@ public class RenderContextImpl implement
     public Map toMap(Object object) {
         if (object instanceof Map) {
             return (Map) object;
+        } else if (object instanceof Record) {
+            Map<String, Object> map = new HashMap<String, Object>();
+            Record record = (Record) object;
+            Set<String> properties = record.getPropertyNames();
+            for (String property : properties) {
+                map.put(property, record.getProperty(property));
+            }
+            return map;
         }
         return Collections.emptyMap();
     }

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/ExpressionContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/ExpressionContext.java?rev=1660132&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/ExpressionContext.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/ExpressionContext.java Mon Feb 16 15:00:22 2015
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.filter;
+
+import org.apache.sling.scripting.sightly.impl.compiler.expression.Expression;
+
+/**
+ * Defines a context for the {@link Expression} that will be processed by a {@link Filter}. The context can then be used by filters to
+ * further enhance the decision mechanism for their processing.
+ */
+public enum ExpressionContext {
+
+    // Plugin contexts
+    PLUGIN_DATA_SLY_USE,
+    PLUGIN_DATA_SLY_TEXT,
+    PLUGIN_DATA_SLY_ATTRIBUTE,
+    PLUGIN_DATA_SLY_ELEMENT,
+    PLUGIN_DATA_SLY_TEST,
+    PLUGIN_DATA_SLY_LIST,
+    PLUGIN_DATA_SLY_REPEAT,
+    PLUGIN_DATA_SLY_INCLUDE,
+    PLUGIN_DATA_SLY_RESOURCE,
+    PLUGIN_DATA_SLY_TEMPLATE,
+    PLUGIN_DATA_SLY_CALL,
+    PLUGIN_DATA_SLY_UNWRAP,
+
+    // Markup contexts
+    ELEMENT,
+    TEXT,
+    ATTRIBUTE;
+
+    private static final String PLUGIN_PREFIX = "PLUGIN_DATA_SLY_";
+
+    /**
+     * Retrieves the context for the plugin specified by {@code pluginName}.
+     *
+     * @param pluginName the name of the plugin for which to retrieve the context
+     * @return the context
+     * @throws IllegalArgumentException if the plugin identified by {@code pluginName} doesn't have a context associated
+     */
+    public static ExpressionContext getContextForPlugin(String pluginName) {
+        return valueOf(PLUGIN_PREFIX + pluginName.toUpperCase());
+    }
+
+}

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java Mon Feb 16 15:00:22 2015
@@ -33,7 +33,7 @@ public interface Filter extends Comparab
      * @return a transformed expression. If the filter is not applicable
      * to the given expression, then the original expression shall be returned
      */
-    Expression apply(Expression expression);
+    Expression apply(Expression expression, ExpressionContext expressionContext);
 
     /**
      * The priority with which filters are applied. This establishes order between filters. Filters with

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java Mon Feb 16 15:00:22 2015
@@ -50,15 +50,16 @@ public class FormatFilter extends Filter
     private static final Pattern PLACEHOLDER_REGEX = Pattern.compile("\\{\\d}");
 
     @Override
-    public Expression apply(Expression expression) {
+    public Expression apply(Expression expression, ExpressionContext expressionContext) {
         //todo: if the expression is a string constant, we can produce the transformation at
         //compile time, with no need of a runtime function
-        if (!expression.containsOption(FORMAT_OPTION)) {
+        if (!expression.containsOption(FORMAT_OPTION) || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_USE || expressionContext
+                == ExpressionContext.PLUGIN_DATA_SLY_TEMPLATE || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_CALL) {
             return expression;
         }
         ExpressionNode argNode = expression.getOption(FORMAT_OPTION);
         ExpressionNode formattedNode = new RuntimeCall(FORMAT_FUNCTION, expression.getRoot(), argNode);
-        return expression.withNode(formattedNode).removeOptions(FORMAT_OPTION);
+        return expression.withNode(formattedNode).withRemovedOptions(FORMAT_OPTION);
     }
 
     @Override

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java Mon Feb 16 15:00:22 2015
@@ -42,14 +42,15 @@ public class I18nFilter extends FilterCo
     public static final String LOCALE_OPTION = "locale";
 
     @Override
-    public Expression apply(Expression expression) {
-        if (!expression.containsOption(I18N_OPTION)) {
+    public Expression apply(Expression expression, ExpressionContext expressionContext) {
+        if (!expression.containsOption(I18N_OPTION) || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_USE || expressionContext
+                == ExpressionContext.PLUGIN_DATA_SLY_TEMPLATE || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_CALL) {
             return expression;
         }
         ExpressionNode hint = option(expression, HINT_OPTION);
         ExpressionNode locale = option(expression, LOCALE_OPTION);
         ExpressionNode translation = new RuntimeCall(FUNCTION, expression.getRoot(), locale, hint);
-        return expression.withNode(translation).removeOptions(HINT_OPTION, LOCALE_OPTION);
+        return expression.withNode(translation).withRemovedOptions(HINT_OPTION, LOCALE_OPTION);
     }
 
     private ExpressionNode option(Expression expression, String optionName) {

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java Mon Feb 16 15:00:22 2015
@@ -49,13 +49,14 @@ public class JoinFilter extends FilterCo
     public static final String JOIN_FUNCTION = "join";
 
     @Override
-    public Expression apply(Expression expression) {
-        if (!expression.containsOption(JOIN_OPTION)) {
+    public Expression apply(Expression expression, ExpressionContext expressionContext) {
+        if (!expression.containsOption(JOIN_OPTION) || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_USE || expressionContext
+                == ExpressionContext.PLUGIN_DATA_SLY_TEMPLATE || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_CALL) {
             return expression;
         }
         ExpressionNode argumentNode = expression.getOption(JOIN_OPTION);
         ExpressionNode joinResult = new RuntimeCall(JOIN_FUNCTION, expression.getRoot(), argumentNode);
-        return expression.withNode(joinResult).removeOptions(JOIN_OPTION);
+        return expression.withNode(joinResult).withRemovedOptions(JOIN_OPTION);
     }
 
     @Override

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java?rev=1660132&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/URIManipulationFilter.java Mon Feb 16 15:00:22 2015
@@ -0,0 +1,349 @@
+package org.apache.sling.scripting.sightly.impl.filter;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+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.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.engine.runtime.RenderContextImpl;
+import org.apache.sling.scripting.sightly.impl.utils.PathInfo;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+/**
+ * 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})
+@Properties({
+        @Property(name = RuntimeExtension.NAME, value = URIManipulationFilter.URI_MANIPULATION_FUNCTION)
+})
+public class URIManipulationFilter extends FilterComponent implements RuntimeExtension {
+
+    public static final String URI_MANIPULATION_FUNCTION = "uriManipulation";
+
+    private static final String SCHEME = "scheme";
+    private static final String DOMAIN = "domain";
+    private static final String PATH = "path";
+    private static final String APPEND_PATH = "appendPath";
+    private static final String PREPEND_PATH = "prependPath";
+    private static final String SELECTORS = "selectors";
+    private static final String ADD_SELECTORS = "addSelectors";
+    private static final String REMOVE_SELECTORS = "removeSelectors";
+    private static final String EXTENSION = "extension";
+    private static final String SUFFIX = "suffix";
+    private static final String PREPEND_SUFFIX = "prependSuffix";
+    private static final String APPEND_SUFFIX = "appendSuffix";
+    private static final String FRAGMENT = "fragment";
+    private static final String QUERY = "query";
+    private static final String ADD_QUERY = "addQuery";
+    private 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 = new HashMap<String, ExpressionNode>();
+            collectOptions(expression, uriOptions, 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);
+        RenderContextImpl rci = (RenderContextImpl) renderContext;
+        String uriString = rci.toString(arguments[0]);
+        Map<String, Object> options = rci.toMap(arguments[1]);
+        if (uriString == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        PathInfo pathInfo = new PathInfo(uriString);
+        uriAppender(sb, SCHEME, options, pathInfo.getScheme());
+        if (sb.length() > 0) {
+            sb.append(":");
+            sb.append(StringUtils.defaultIfEmpty(pathInfo.getBeginPathSeparator(), "//"));
+        }
+        if (sb.length() > 0) {
+            uriAppender(sb, DOMAIN, options, pathInfo.getHost());
+        } else {
+            String domain = getOption(DOMAIN, options, pathInfo.getHost());
+            if (StringUtils.isNotEmpty(domain)) {
+                sb.append("//").append(domain);
+            }
+        }
+        if (pathInfo.getPort() > -1) {
+            sb.append(":").append(pathInfo.getPort());
+        }
+        String prependPath = getOption(PREPEND_PATH, options, StringUtils.EMPTY);
+        if (prependPath == null) {
+            prependPath = StringUtils.EMPTY;
+        }
+        if (StringUtils.isNotEmpty(prependPath)) {
+            if (sb.length() > 0 && !prependPath.startsWith("/")) {
+                prependPath = "/" + prependPath;
+            }
+            if (!prependPath.endsWith("/")) {
+                prependPath += "/";
+            }
+        }
+        String path = getOption(PATH, options, pathInfo.getPath());
+        if (StringUtils.isEmpty(path)) {
+            // if the path is forced to be empty don't remove the path
+            path = pathInfo.getPath();
+        }
+        String appendPath = getOption(APPEND_PATH, options, StringUtils.EMPTY);
+        if (appendPath == null) {
+            appendPath = StringUtils.EMPTY;
+        }
+        if (StringUtils.isNotEmpty(appendPath)) {
+            if (!appendPath.startsWith("/")) {
+                appendPath = "/" + appendPath;
+            }
+        }
+        String newPath;
+        try {
+            newPath = new URI(prependPath + path + appendPath).normalize().getPath();
+        } catch (URISyntaxException e) {
+            newPath = prependPath + path + appendPath;
+        }
+        if (sb.length() > 0 && sb.lastIndexOf("/") != sb.length() - 1 && StringUtils.isNotEmpty(newPath) && !newPath.startsWith("/")) {
+            sb.append("/");
+        }
+        sb.append(newPath);
+        Set<String> selectors = pathInfo.getSelectors();
+        handleSelectors(rci, selectors, options);
+        for (String selector : selectors) {
+            if (StringUtils.isNotBlank(selector) && !selector.contains(" ")) {
+                // make sure not to append empty or invalid selectors
+                sb.append(".").append(selector);
+            }
+        }
+        String extension = getOption(EXTENSION, options, pathInfo.getExtension());
+        if (StringUtils.isNotEmpty(extension)) {
+            sb.append(".").append(extension);
+        }
+
+        String prependSuffix = getOption(PREPEND_SUFFIX, options, StringUtils.EMPTY);
+        if (StringUtils.isNotEmpty(prependSuffix)) {
+            if (!prependSuffix.startsWith("/")) {
+                prependSuffix = "/" + prependSuffix;
+            }
+            if (!prependSuffix.endsWith("/")) {
+                prependSuffix += "/";
+            }
+        }
+        String pathInfoSuffix = pathInfo.getSuffix();
+        String suffix = getOption(SUFFIX, options, pathInfoSuffix == null ? StringUtils.EMPTY : pathInfoSuffix);
+        if (suffix == null) {
+            suffix = StringUtils.EMPTY;
+        }
+        String appendSuffix = getOption(APPEND_SUFFIX, options, StringUtils.EMPTY);
+        if (StringUtils.isNotEmpty(appendSuffix)) {
+            appendSuffix = "/" + appendSuffix;
+        }
+        String newSuffix = ResourceUtil.normalize(prependSuffix + suffix + appendSuffix);
+        if (StringUtils.isNotEmpty(newSuffix)) {
+            if (!newSuffix.startsWith("/")) {
+                sb.append("/");
+            }
+            sb.append(newSuffix);
+        }
+        Map<String, Collection<String>> parameters = pathInfo.getParameters();
+        handleParameters(rci, parameters, options);
+        if (!parameters.isEmpty()) {
+            sb.append("?");
+            for (Map.Entry<String, Collection<String>> entry : parameters.entrySet()) {
+                for (String value : entry.getValue()) {
+                    sb.append(entry.getKey()).append("=").append(value).append("&");
+                }
+            }
+            // delete the last &
+            sb.deleteCharAt(sb.length() - 1);
+        }
+        String fragment = getOption(FRAGMENT, options, pathInfo.getFragment());
+        if (StringUtils.isNotEmpty(fragment)) {
+            sb.append("#").append(fragment);
+        }
+        return sb.toString();
+    }
+
+    private void collectOptions(Expression expression, Map<String, ExpressionNode> collector, String... optionNames) {
+        for (String optionName : optionNames) {
+            if (expression.containsOption(optionName)) {
+                collector.put(optionName, expression.getOption(optionName));
+            }
+        }
+        expression.removeOptions(optionNames);
+    }
+
+    private void uriAppender(StringBuilder stringBuilder, String option, Map<String, Object> options, String defaultValue) {
+        String value = (String) options.get(option);
+        if (StringUtils.isNotEmpty(value)) {
+            stringBuilder.append(value);
+        } else {
+            if (StringUtils.isNotEmpty(defaultValue)) {
+                stringBuilder.append(defaultValue);
+            }
+        }
+    }
+
+    private String getOption(String option, Map<String, Object> options, String defaultValue) {
+        if (options.containsKey(option)) {
+            return (String) options.get(option);
+
+        }
+        return defaultValue;
+    }
+
+    private void handleSelectors(RenderContextImpl rci, Set<String> selectors, Map<String, Object> options) {
+        if (options.containsKey(SELECTORS)) {
+            Object selectorsOption = options.get(SELECTORS);
+            if (selectorsOption == null) {
+                // we want to remove all selectors
+                selectors.clear();
+            } else if (selectorsOption instanceof String) {
+                String selectorString = (String) selectorsOption;
+                String[] selectorsArray = selectorString.split("\\.");
+                replaceSelectors(selectors, selectorsArray);
+            } else if (selectorsOption instanceof Object[]) {
+                Object[] selectorsURIArray = (Object[]) selectorsOption;
+                String[] selectorsArray = new String[selectorsURIArray.length];
+                int index = 0;
+                for (Object selector : selectorsURIArray) {
+                    selectorsArray[index++] = rci.toString(selector);
+                }
+                replaceSelectors(selectors, selectorsArray);
+            }
+        }
+        Object addSelectorsOption = options.get(ADD_SELECTORS);
+        if (addSelectorsOption instanceof String) {
+            String selectorString = (String) addSelectorsOption;
+            String[] selectorsArray = selectorString.split("\\.");
+            addSelectors(selectors, selectorsArray);
+        } else if (addSelectorsOption instanceof Object[]) {
+            Object[] selectorsURIArray = (Object[]) addSelectorsOption;
+            String[] selectorsArray = new String[selectorsURIArray.length];
+            int index = 0;
+            for (Object selector : selectorsURIArray) {
+                selectorsArray[index++] = rci.toString(selector);
+            }
+            addSelectors(selectors, selectorsArray);
+        }
+        Object removeSelectorsOption = options.get(REMOVE_SELECTORS);
+        if (removeSelectorsOption instanceof String) {
+            String selectorString = (String) removeSelectorsOption;
+            String[] selectorsArray = selectorString.split("\\.");
+            removeSelectors(selectors, selectorsArray);
+        } else if (removeSelectorsOption instanceof Object[]) {
+            Object[] selectorsURIArray = (Object[]) removeSelectorsOption;
+            String[] selectorsArray = new String[selectorsURIArray.length];
+            int index = 0;
+            for (Object selector : selectorsURIArray) {
+                selectorsArray[index++] = rci.toString(selector);
+            }
+            removeSelectors(selectors, selectorsArray);
+        }
+
+    }
+
+    private void replaceSelectors(Set<String> selectors, String[] selectorsArray) {
+        selectors.clear();
+        selectors.addAll(Arrays.asList(selectorsArray));
+    }
+
+    private void addSelectors(Set<String> selectors, String[] selectorsArray) {
+        selectors.addAll(Arrays.asList(selectorsArray));
+    }
+
+    private void removeSelectors(Set<String> selectors, String[] selectorsArray) {
+        selectors.removeAll(Arrays.asList(selectorsArray));
+    }
+
+    @SuppressWarnings("unchecked")
+    private void handleParameters(RenderContextImpl rci, Map<String, Collection<String>> parameters, Map<String, Object> options) {
+        if (options.containsKey(QUERY)) {
+            Object queryOption = options.get(QUERY);
+            parameters.clear();
+            Map<String, Object> queryParameters = rci.toMap(queryOption);
+            for (Map.Entry<String, Object> entry : queryParameters.entrySet()) {
+                Object entryValue = entry.getValue();
+                if (rci.isCollection(entryValue)) {
+                    Collection<Object> collection = rci.toCollection(entryValue);
+                    Collection<String> values = new ArrayList<String>(collection.size());
+                    for (Object o : collection) {
+                        values.add(rci.toString(o));
+                    }
+                    parameters.put(entry.getKey(), values);
+                } else {
+                    Collection<String> values = new ArrayList<String>(1);
+                    values.add(rci.toString(entryValue));
+                    parameters.put(entry.getKey(), values);
+                }
+            }
+        }
+        Object addQueryOption = options.get(ADD_QUERY);
+        if (addQueryOption != null) {
+            Map<String, Object> addParams = rci.toMap(addQueryOption);
+            for (Map.Entry<String, Object> entry : addParams.entrySet()) {
+                Object entryValue = entry.getValue();
+                if (rci.isCollection(entryValue)) {
+                    Collection<Object> collection = rci.toCollection(entryValue);
+                    Collection<String> values = new ArrayList<String>(collection.size());
+                    for (Object o : collection) {
+                        values.add(rci.toString(o));
+                    }
+                    parameters.put(entry.getKey(), values);
+                } else {
+                    Collection<String> values = new ArrayList<String>(1);
+                    values.add(rci.toString(entryValue));
+                    parameters.put(entry.getKey(), values);
+                }
+            }
+        }
+        Object removeQueryOption = options.get(REMOVE_QUERY);
+        if (removeQueryOption != null) {
+            if (removeQueryOption instanceof String) {
+                parameters.remove(removeQueryOption);
+            } else if (removeQueryOption instanceof Object[]) {
+                Object[] removeQueryParamArray = (Object[]) removeQueryOption;
+                for (Object param : removeQueryParamArray) {
+                    String paramString = rci.toString(param);
+                    if (paramString != null) {
+                        parameters.remove(paramString);
+                    }
+                }
+            }
+        }
+    }
+}

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java Mon Feb 16 15:00:22 2015
@@ -39,7 +39,11 @@ public class XSSFilter extends FilterCom
     public static final String FUNCTION_NAME = "xss";
 
     @Override
-    public Expression apply(Expression expression) {
+    public Expression apply(Expression expression, ExpressionContext expressionContext) {
+        if (expressionContext == ExpressionContext.PLUGIN_DATA_SLY_USE || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_TEMPLATE
+                || expressionContext == ExpressionContext.PLUGIN_DATA_SLY_CALL) {
+            return expression;
+        }
         ExpressionNode node = expression.getRoot();
         Map<String, ExpressionNode> options = expression.getOptions();
         ExpressionNode context = options.get(Syntax.CONTEXT_OPTION);

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/MarkupHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/MarkupHandler.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/MarkupHandler.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/MarkupHandler.java Mon Feb 16 15:00:22 2015
@@ -32,6 +32,7 @@ import org.apache.sling.scripting.sightl
 import org.apache.sling.scripting.sightly.impl.compiler.frontend.Fragment;
 import org.apache.sling.scripting.sightly.impl.compiler.frontend.Interpolation;
 import org.apache.sling.scripting.sightly.impl.compiler.ris.command.Patterns;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
 import org.apache.sling.scripting.sightly.impl.filter.Filter;
 import org.apache.sling.scripting.sightly.impl.compiler.expression.Expression;
 import org.apache.sling.scripting.sightly.impl.compiler.expression.ExpressionNode;
@@ -173,7 +174,7 @@ public class MarkupHandler {
         // Simplified algorithm for attribute output, which works when the interpolation is not of size 1. In this
         // case we are certain that the attribute value cannot be the boolean value true, so we can skip this test
         // altogether
-        Expression expression = expressionWrapper.transform(interpolation, getAttributeMarkupContext(name));
+        Expression expression = expressionWrapper.transform(interpolation, getAttributeMarkupContext(name), ExpressionContext.ATTRIBUTE);
         String attrContent = symbolGenerator.next("attrContent");
         String shouldDisplayAttr = symbolGenerator.next("shouldDisplayAttr");
         stream.emit(new VariableBinding.Start(attrContent, expression.getRoot()));
@@ -200,7 +201,7 @@ public class MarkupHandler {
     }
 
     private void emitSingleFragment(String name, Interpolation interpolation, PluginInvoke invoke) {
-        Expression valueExpression = expressionWrapper.transform(interpolation, null); //raw expression
+        Expression valueExpression = expressionWrapper.transform(interpolation, null, ExpressionContext.ATTRIBUTE); //raw expression
         String attrValue = symbolGenerator.next("attrValue"); //holds the raw attribute value
         String attrContent = symbolGenerator.next("attrContent"); //holds the escaped attribute value
         String isTrueVar = symbolGenerator.next("isTrueAttr"); // holds the comparison (attrValue == true)
@@ -209,7 +210,8 @@ public class MarkupHandler {
         Expression contentExpression = valueExpression.withNode(new Identifier(attrValue));
         ExpressionNode node = valueExpression.getRoot();
         stream.emit(new VariableBinding.Start(attrValue, node)); //attrContent = <expr>
-        stream.emit(new VariableBinding.Start(attrContent, expressionWrapper.adjustToContext(contentExpression, markupContext).getRoot()));
+        stream.emit(new VariableBinding.Start(attrContent, expressionWrapper.adjustToContext(contentExpression, markupContext,
+                ExpressionContext.ATTRIBUTE).getRoot()));
         stream.emit(
                 new VariableBinding.Start(
                         shouldDisplayAttr,
@@ -309,7 +311,7 @@ public class MarkupHandler {
         if (text != null) {
             out(text);
         } else {
-            outExprNode(expressionWrapper.transform(interpolation, context).getRoot());
+            outExprNode(expressionWrapper.transform(interpolation, context, ExpressionContext.TEXT).getRoot());
         }
     }
 
@@ -383,8 +385,8 @@ public class MarkupHandler {
         PluginCallInfo callInfo = Syntax.parsePluginAttribute(name);
         if (callInfo != null) {
             Plugin plugin = obtainPlugin(callInfo.getName());
-            Expression expr = expressionWrapper.transform(
-                    expressionParser.parseInterpolation(value), null);
+            ExpressionContext expressionContext = ExpressionContext.getContextForPlugin(plugin.name());
+            Expression expr = expressionWrapper.transform(expressionParser.parseInterpolation(value), null, expressionContext);
             PluginInvoke invoke = plugin.invoke(expr, callInfo, compilerContext);
             context.addPlugin(invoke, plugin.priority());
             context.addPluginCall(name, callInfo, expr);

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AttributePlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AttributePlugin.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AttributePlugin.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AttributePlugin.java Mon Feb 16 15:00:22 2015
@@ -47,6 +47,7 @@ import org.apache.sling.scripting.sightl
 import org.apache.sling.scripting.sightly.impl.compiler.common.DefaultPluginInvoke;
 import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 import org.apache.sling.scripting.sightly.impl.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
 import org.apache.sling.scripting.sightly.impl.html.MarkupUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -351,6 +352,6 @@ public class AttributePlugin extends Plu
             //todo: this is not the indicated way to escape via XSS. Correct after modifying the compiler context API
             return new RuntimeCall("xss", node, new StringConstant(markupContext.getName()), hint);
         }
-        return compilerContext.adjustToContext(new Expression(node), markupContext).getRoot();
+        return compilerContext.adjustToContext(new Expression(node), markupContext, ExpressionContext.ATTRIBUTE).getRoot();
     }
 }

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ElementPlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ElementPlugin.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ElementPlugin.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ElementPlugin.java Mon Feb 16 15:00:22 2015
@@ -32,6 +32,7 @@ import org.apache.sling.scripting.sightl
 import org.apache.sling.scripting.sightly.impl.compiler.common.DefaultPluginInvoke;
 import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 import org.apache.sling.scripting.sightly.impl.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
 
 /**
  * Implementation for the {@code data-sly-element} plugin.
@@ -50,7 +51,8 @@ public class ElementPlugin extends Plugi
 
         return new DefaultPluginInvoke() {
 
-            private final ExpressionNode node = compilerContext.adjustToContext(expression, MarkupContext.ELEMENT_NAME).getRoot();
+            private final ExpressionNode node = compilerContext.adjustToContext(expression, MarkupContext.ELEMENT_NAME, ExpressionContext
+                    .ELEMENT).getRoot();
             private String tagVar = compilerContext.generateVariable("tagVar");
 
             @Override

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/TextPlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/TextPlugin.java?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/TextPlugin.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/TextPlugin.java Mon Feb 16 15:00:22 2015
@@ -29,6 +29,7 @@ import org.apache.sling.scripting.sightl
 import org.apache.sling.scripting.sightly.impl.compiler.common.DefaultPluginInvoke;
 import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 import org.apache.sling.scripting.sightly.impl.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.impl.filter.ExpressionContext;
 
 /**
  * The {@code data-sly-text} plugin.
@@ -49,7 +50,7 @@ public class TextPlugin extends PluginCo
             public void beforeChildren(PushStream stream) {
                 String variable = compilerContext.generateVariable("textContent");
                 stream.emit(new VariableBinding.Start(variable,
-                        compilerContext.adjustToContext(expression, MarkupContext.TEXT).getRoot()));
+                        compilerContext.adjustToContext(expression, MarkupContext.TEXT, ExpressionContext.TEXT).getRoot()));
                 stream.emit(new OutVariable(variable));
                 stream.emit(VariableBinding.END);
                 Patterns.beginStreamIgnore(stream);

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/PathInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/PathInfo.java?rev=1660132&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/PathInfo.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/utils/PathInfo.java Mon Feb 16 15:00:22 2015
@@ -0,0 +1,230 @@
+/**
+ * ****************************************************************************
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.utils;
+
+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.lang.StringUtils;
+import org.apache.sling.scripting.sightly.SightlyException;
+
+/**
+ * The {@code PathInfo} class provides path processing methods useful for extracting the path of a request, the selectors applied to the
+ * path, the extension and query parameters.
+ */
+public 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<String, Collection<String>>();
+
+    /**
+     * 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>();
+        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<String>();
+                        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;
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PathInfoTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PathInfoTest.java?rev=1660132&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PathInfoTest.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PathInfoTest.java Mon Feb 16 15:00:22 2015
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class PathInfoTest {
+
+    private static final String EMPTY = "";
+    private static final String PATH = "test";
+    private static final String ABSOLUTE_PATH = "/" + PATH;
+    private static final String SCHEME = "http";
+    private static final String SCHEME_PATH_SEPARATOR = "//";
+    private static final int PORT = 8080;
+    private static final String HOST = "www.example.com";
+    private static final String SELECTOR_STRING = "a.b";
+    private static final Set<String> SELECTOR_STRING_SET = new LinkedHashSet<String>() {{
+        add("a");
+        add("b");
+    }};
+    private static final String EXTENSION = "html";
+    private static final String SUFFIX = "/suffix1/suffix2";
+    private static final String FRAGMENT = "fragment";
+
+    private static final PathInfo emptyPathInfo = new PathInfo(EMPTY);
+    private static final PathInfo simplePath = new PathInfo(PATH);
+    private static final PathInfo pathWithExtension = new PathInfo(PATH + "." + EXTENSION);
+    private static final PathInfo pathWithSelectors = new PathInfo(PATH + "." + SELECTOR_STRING + "." + EXTENSION);
+    private static final PathInfo pathWithSelectorsSuffix = new PathInfo(PATH + "." + SELECTOR_STRING + "." + EXTENSION + SUFFIX);
+    private static final PathInfo pathWithScheme = new PathInfo(SCHEME + ":" + "//" + HOST);
+    private static final PathInfo pathWithSchemePath = new PathInfo(SCHEME + ":" + "//" + HOST + ABSOLUTE_PATH);
+    private static final PathInfo pathWithSchemePathExtension = new PathInfo(SCHEME + ":" + "//" + HOST + ABSOLUTE_PATH + "." + EXTENSION);
+    private static final PathInfo pathWithSchemePathExtensionSelectors = new PathInfo(SCHEME + ":" + "//" + HOST + ABSOLUTE_PATH + "." +
+            SELECTOR_STRING + "." + EXTENSION);
+    private static final PathInfo pathWithSchemePathExtensionSelectorsSuffix = new PathInfo(SCHEME + ":" + "//" + HOST + ABSOLUTE_PATH +
+            "." + SELECTOR_STRING + "." + EXTENSION + SUFFIX);
+    private static final PathInfo pathWithSchemePathExtensionSelectorsSuffixFragment = new PathInfo(SCHEME + ":" + "//" + HOST +
+            ABSOLUTE_PATH + "." + SELECTOR_STRING + "." + EXTENSION + SUFFIX + "#" + FRAGMENT);
+    private static final PathInfo pathWithSchemePortPathExtensionSelectorsSuffixFragment = new PathInfo(SCHEME + ":" + "//" + HOST +
+            ":" + PORT + ABSOLUTE_PATH + "." + SELECTOR_STRING + "." + EXTENSION + SUFFIX + "#" + FRAGMENT);
+
+    @Test
+    public void testGetPath() throws Exception {
+        assertEquals(EMPTY, emptyPathInfo.getPath());
+        assertEquals(PATH, simplePath.getPath());
+        assertEquals(PATH, pathWithExtension.getPath());
+        assertEquals(PATH, pathWithSelectors.getPath());
+        assertEquals(PATH, pathWithSelectorsSuffix.getPath());
+        assertEquals(EMPTY, pathWithScheme.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePath.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePathExtension.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePathExtensionSelectors.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePathExtensionSelectorsSuffix.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePathExtensionSelectorsSuffixFragment.getPath());
+        assertEquals(ABSOLUTE_PATH, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getPath());
+    }
+
+    @Test
+    public void testGetSelectors() throws Exception {
+        assertEquals(0, emptyPathInfo.getSelectors().size());
+        assertEquals(0, simplePath.getSelectors().size());
+        assertEquals(0, pathWithExtension.getSelectors().size());
+        assertEquals(SELECTOR_STRING_SET, pathWithSelectors.getSelectors());
+        assertEquals(SELECTOR_STRING_SET, pathWithSelectorsSuffix.getSelectors());
+        assertEquals(EMPTY, pathWithScheme.getPath());
+        assertEquals(0, pathWithSchemePath.getSelectors().size());
+        assertEquals(0, pathWithSchemePathExtension.getSelectors().size());
+        assertEquals(SELECTOR_STRING_SET, pathWithSchemePathExtensionSelectors.getSelectors());
+        assertEquals(SELECTOR_STRING_SET, pathWithSchemePathExtensionSelectorsSuffix.getSelectors());
+        assertEquals(SELECTOR_STRING_SET, pathWithSchemePathExtensionSelectorsSuffixFragment.getSelectors());
+        assertEquals(SELECTOR_STRING_SET, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getSelectors());
+    }
+
+    @Test
+    public void testGetSelectorString() throws Exception {
+        assertNull(emptyPathInfo.getSelectorString());
+        assertNull(simplePath.getSelectorString());
+        assertNull(pathWithExtension.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSelectors.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSelectorsSuffix.getSelectorString());
+        assertNull(pathWithScheme.getSelectorString());
+        assertNull(pathWithSchemePath.getSelectorString());
+        assertNull(pathWithSchemePathExtension.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSchemePathExtensionSelectors.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSchemePathExtensionSelectorsSuffix.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSchemePathExtensionSelectorsSuffixFragment.getSelectorString());
+        assertEquals(SELECTOR_STRING, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getSelectorString());
+    }
+
+    @Test
+    public void testGetExtension() throws Exception {
+        assertNull(emptyPathInfo.getExtension());
+        assertNull(simplePath.getExtension());
+        assertEquals(EXTENSION, pathWithExtension.getExtension());
+        assertEquals(EXTENSION, pathWithSelectors.getExtension());
+        assertEquals(EXTENSION, pathWithSelectorsSuffix.getExtension());
+        assertNull(pathWithScheme.getExtension());
+        assertNull(pathWithSchemePath.getExtension());
+        assertEquals(EXTENSION, pathWithSchemePathExtension.getExtension());
+        assertEquals(EXTENSION, pathWithSchemePathExtensionSelectors.getExtension());
+        assertEquals(EXTENSION, pathWithSchemePathExtensionSelectorsSuffix.getExtension());
+        assertEquals(EXTENSION, pathWithSchemePathExtensionSelectorsSuffixFragment.getExtension());
+        assertEquals(EXTENSION, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getExtension());
+    }
+
+    @Test
+    public void testGetScheme() {
+        assertNull(emptyPathInfo.getScheme());
+        assertNull(simplePath.getScheme());
+        assertNull(pathWithExtension.getScheme());
+        assertNull(pathWithSelectors.getScheme());
+        assertNull(pathWithSelectorsSuffix.getScheme());
+        assertEquals(SCHEME, pathWithScheme.getScheme());
+        assertEquals(SCHEME, pathWithSchemePath.getScheme());
+        assertEquals(SCHEME, pathWithSchemePathExtension.getScheme());
+        assertEquals(SCHEME, pathWithSchemePathExtensionSelectors.getScheme());
+        assertEquals(SCHEME, pathWithSchemePathExtensionSelectorsSuffix.getScheme());
+        assertEquals(SCHEME, pathWithSchemePathExtensionSelectorsSuffixFragment.getScheme());
+        assertEquals(SCHEME, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getScheme());
+    }
+
+    @Test
+    public void testGetBeginPathSeparator() {
+        assertNull(emptyPathInfo.getBeginPathSeparator());
+        assertNull(simplePath.getBeginPathSeparator());
+        assertNull(pathWithExtension.getBeginPathSeparator());
+        assertNull(pathWithSelectors.getBeginPathSeparator());
+        assertNull(pathWithSelectorsSuffix.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithScheme.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePath.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePathExtension.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePathExtensionSelectors.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePathExtensionSelectorsSuffix.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePathExtensionSelectorsSuffixFragment.getBeginPathSeparator());
+        assertEquals(SCHEME_PATH_SEPARATOR, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getBeginPathSeparator());
+    }
+
+    @Test
+    public void testGetHost() {
+        assertNull(emptyPathInfo.getHost());
+        assertNull(simplePath.getHost());
+        assertNull(pathWithExtension.getHost());
+        assertNull(pathWithSelectors.getHost());
+        assertNull(pathWithSelectorsSuffix.getHost());
+        assertEquals(HOST, pathWithScheme.getHost());
+        assertEquals(HOST, pathWithSchemePath.getHost());
+        assertEquals(HOST, pathWithSchemePathExtension.getHost());
+        assertEquals(HOST, pathWithSchemePathExtensionSelectors.getHost());
+        assertEquals(HOST, pathWithSchemePathExtensionSelectorsSuffix.getHost());
+        assertEquals(HOST, pathWithSchemePathExtensionSelectorsSuffixFragment.getHost());
+        assertEquals(HOST, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getHost());
+    }
+
+    @Test
+    public void testGetPort() {
+        assertEquals(-1, emptyPathInfo.getPort());
+        assertEquals(-1, simplePath.getPort());
+        assertEquals(-1, pathWithExtension.getPort());
+        assertEquals(-1, pathWithSelectors.getPort());
+        assertEquals(-1, pathWithSelectorsSuffix.getPort());
+        assertEquals(-1, pathWithScheme.getPort());
+        assertEquals(-1, pathWithSchemePath.getPort());
+        assertEquals(-1, pathWithSchemePathExtension.getPort());
+        assertEquals(-1, pathWithSchemePathExtensionSelectors.getPort());
+        assertEquals(-1, pathWithSchemePathExtensionSelectorsSuffix.getPort());
+        assertEquals(-1, pathWithSchemePathExtensionSelectorsSuffixFragment.getPort());
+        assertEquals(PORT, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getPort());
+    }
+
+    @Test
+    public void testGetSuffix() {
+        assertNull(emptyPathInfo.getSuffix());
+        assertNull(simplePath.getSuffix());
+        assertNull(pathWithExtension.getSuffix());
+        assertNull(pathWithSelectors.getSuffix());
+        assertEquals(SUFFIX, pathWithSelectorsSuffix.getSuffix());
+        assertNull(pathWithScheme.getSuffix());
+        assertNull(pathWithSchemePath.getSuffix());
+        assertNull(pathWithSchemePathExtension.getSuffix());
+        assertNull(pathWithSchemePathExtensionSelectors.getSuffix());
+        assertEquals(SUFFIX, pathWithSchemePathExtensionSelectorsSuffix.getSuffix());
+        assertEquals(SUFFIX, pathWithSchemePathExtensionSelectorsSuffixFragment.getSuffix());
+        assertEquals(SUFFIX, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getSuffix());
+    }
+
+    @Test
+    public void testGetFragment() {
+        assertNull(emptyPathInfo.getFragment());
+        assertNull(simplePath.getFragment());
+        assertNull(pathWithExtension.getFragment());
+        assertNull(pathWithSelectors.getFragment());
+        assertNull(pathWithSelectorsSuffix.getFragment());
+        assertNull(pathWithScheme.getFragment());
+        assertNull(pathWithSchemePath.getFragment());
+        assertNull(pathWithSchemePathExtension.getFragment());
+        assertNull(pathWithSchemePathExtensionSelectors.getFragment());
+        assertNull(pathWithSchemePathExtensionSelectorsSuffix.getFragment());
+        assertEquals(FRAGMENT, pathWithSchemePathExtensionSelectorsSuffixFragment.getFragment());
+        assertEquals(FRAGMENT, pathWithSchemePortPathExtensionSelectorsSuffixFragment.getFragment());
+    }
+}

Modified: sling/trunk/contrib/scripting/sightly/testing-content/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/testing-content/pom.xml?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/testing-content/pom.xml (original)
+++ sling/trunk/contrib/scripting/sightly/testing-content/pom.xml Mon Feb 16 15:00:22 2015
@@ -85,7 +85,7 @@
                                 <artifactItem>
                                     <groupId>io.sightly</groupId>
                                     <artifactId>io.sightly.tck</artifactId>
-                                    <version>1.1.0</version>
+                                    <version>1.1.1</version>
                                     <type>jar</type>
                                     <outputDirectory>${project.build.directory}/sightlytck/</outputDirectory>
                                     <includes>**/*.html,**/*.js,**/*.java</includes>

Modified: sling/trunk/contrib/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightlytck.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightlytck.json?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightlytck.json (original)
+++ sling/trunk/contrib/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightlytck.json Mon Feb 16 15:00:22 2015
@@ -10,6 +10,10 @@
             "jcr:primaryType": "nt:unstructured",
             "sling:resourceType": "/sightlytck/scripts/exprlang/filters"
         },
+        "filteroptions": {
+            "jcr:primaryType": "nt:unstructured",
+            "sling:resourceType": "/sightlytck/scripts/exprlang/filteroptions"
+        },
         "strings": {
             "jcr:primaryType": "nt:unstructured",
             "sling:resourceType": "/sightlytck/scripts/exprlang/strings"

Modified: sling/trunk/contrib/scripting/sightly/testing/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/testing/pom.xml?rev=1660132&r1=1660131&r2=1660132&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/testing/pom.xml (original)
+++ sling/trunk/contrib/scripting/sightly/testing/pom.xml Mon Feb 16 15:00:22 2015
@@ -293,7 +293,7 @@
         <dependency>
             <groupId>io.sightly</groupId>
             <artifactId>io.sightly.tck</artifactId>
-            <version>1.1.0</version>
+            <version>1.1.1</version>
             <scope>test</scope>
         </dependency>