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

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

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.use;
+
+import javax.script.Bindings;
+
+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.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.ResourceResolution;
+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.RenderContextImpl;
+import org.apache.sling.scripting.sightly.impl.engine.runtime.RenderUnit;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.use.ProviderOutcome;
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+import org.apache.sling.scripting.sightly.use.UseProvider;
+import org.osgi.framework.Constants;
+
+/**
+ * Interprets identifiers as paths to other Sightly templates
+ */
+@Component(
+        metatype = true,
+        label = "Apache Sling Scripting Sightly Render Unit Use Provider",
+        description = "The Render Unit Use Provider is responsible for instantiating Sightly templates through the Use-API."
+)
+@Service(UseProvider.class)
+@Properties({
+        @Property(
+                name = Constants.SERVICE_RANKING,
+                label = "Service Ranking",
+                description = "The Service Ranking value acts as the priority with which this Use Provider is queried to return an " +
+                        "Use-object. A higher value represents a higher priority.",
+                intValue = 100,
+                propertyPrivate = false
+        )
+})
+public class RenderUnitProvider implements UseProvider {
+
+    @Reference
+    private UnitLoader unitLoader = null;
+
+    @Reference
+    private ResourceResolverFactory rrf = null;
+
+    @Override
+    public ProviderOutcome provide(String identifier, RenderContext renderContext, Bindings arguments) {
+        if (identifier.endsWith("." + SightlyScriptEngineFactory.EXTENSION)) {
+            Bindings globalBindings = renderContext.getBindings();
+            Resource renderUnitResource = locateResource(globalBindings, identifier);
+            RenderUnit renderUnit = unitLoader.createUnit(renderUnitResource, globalBindings, (RenderContextImpl) renderContext);
+            return ProviderOutcome.notNullOrFailure(renderUnit);
+        }
+        return ProviderOutcome.failure();
+    }
+
+    private Resource locateResource(Bindings bindings, String script) {
+        ResourceResolver adminResolver = null;
+        try {
+            adminResolver = rrf.getAdministrativeResourceResolver(null);
+            SlingHttpServletRequest request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+            SlingScriptHelper ssh = (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+            Resource resource = ResourceResolution.resolveComponentForRequest(adminResolver, request);
+            if (resource != null) {
+                return ResourceResolution.resolveComponentRelative(adminResolver, resource, script);
+            } else {
+                return ResourceResolution.resolveComponentRelative(adminResolver, ssh.getScript().getScriptResource(), script);
+            }
+        } catch (LoginException e) {
+            throw new SightlyUseException(e);
+        } finally {
+            if (adminResolver != null) {
+                adminResolver.close();
+            }
+        }
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/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/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.use;
+
+import javax.script.Bindings;
+
+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.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScript;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngineFactory;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.use.ProviderOutcome;
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+import org.apache.sling.scripting.sightly.use.UseProvider;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Use provider that interprets the identifier as a script path, and runs the respective script using a script engine that matches the
+ * script extension.
+ *
+ * This provider returns a non-failure outcome only if the evaluated script actually returns something. For more details check the
+ * implementation of the {@link SlingScript#eval(SlingBindings)} method for the available script engines from your platform.
+ */
+@Component(
+        metatype = true,
+        label = "Apache Sling Scripting Sightly Script Use Provider",
+        description = "The Script Use Provider is responsible for instantiating objects from scripts evaluated by other Sling Scripting " +
+                "Engines."
+)
+@Service(UseProvider.class)
+@Properties({
+        @Property(
+                name = Constants.SERVICE_RANKING,
+                label = "Service Ranking",
+                description = "The Service Ranking value acts as the priority with which this Use Provider is queried to return an " +
+                        "Use-object. A higher value represents a higher priority.",
+                intValue = 0,
+                propertyPrivate = false
+        )
+})
+public class ScriptUseProvider implements UseProvider {
+
+    private static final Logger log = LoggerFactory.getLogger(ScriptUseProvider.class);
+
+    @Reference
+    private ResourceResolverFactory rrf = null;
+
+    @Override
+    public ProviderOutcome provide(String scriptName, RenderContext renderContext, Bindings arguments) {
+        Bindings globalBindings = renderContext.getBindings();
+        Bindings bindings = UseProviderUtils.merge(globalBindings, arguments);
+        String extension = scriptExtension(scriptName);
+        if (extension == null || extension.equals(SightlyScriptEngineFactory.EXTENSION)) {
+            return ProviderOutcome.failure();
+        }
+        SlingScriptHelper sling = (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+        ResourceResolver adminResolver = null;
+        try {
+            adminResolver = rrf.getAdministrativeResourceResolver(null);
+            if (adminResolver == null) {
+                log.warn("Cannot obtain administrative resource resolver for " + scriptName);
+                return ProviderOutcome.failure();
+            }
+            Resource scriptResource = UseProviderUtils.locateScriptResource(adminResolver, sling, scriptName);
+            if (scriptResource == null) {
+                log.debug("Path does not match an existing resource: {}", scriptName);
+                return ProviderOutcome.failure();
+            }
+            return evalScript(scriptResource, bindings);
+        } catch (LoginException e) {
+            throw new SightlyUseException(e);
+        } finally {
+            if (adminResolver != null) {
+                adminResolver.close();
+            }
+        }
+
+    }
+
+    private ProviderOutcome evalScript(Resource scriptResource, Bindings bindings) {
+        SlingScript slingScript = scriptResource.adaptTo(SlingScript.class);
+        if (slingScript == null) {
+            return ProviderOutcome.failure();
+        }
+        SlingBindings slingBindings = new SlingBindings();
+        slingBindings.putAll(bindings);
+        Object scriptEval = slingScript.eval(slingBindings);
+        return ProviderOutcome.notNullOrFailure(scriptEval);
+    }
+
+    private String scriptExtension(String path) {
+        String extension = StringUtils.substringAfterLast(path, ".");
+        if (StringUtils.isEmpty(extension)) {
+            extension = null;
+        }
+        return extension;
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/ScriptUseProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseProviderUtils.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseProviderUtils.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseProviderUtils.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseProviderUtils.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.use;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.ResourceResolution;
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+import org.apache.sling.scripting.sightly.use.UseProvider;
+
+/**
+ * Helper class for {@link UseProvider} implementations.
+ */
+public class UseProviderUtils {
+
+    /**
+     * Combine two bindings objects. Priority goes to latter bindings.
+     *
+     * @param former first map of bindings
+     * @param latter second map of bindings, which can override the fist one
+     * @return the merging of the two maps
+     */
+    public static Bindings merge(Bindings former, Bindings latter) {
+        Bindings bindings = new SimpleBindings();
+        bindings.putAll(former);
+        bindings.putAll(latter);
+        return bindings;
+    }
+
+    /**
+     * Retrieves the {@link SlingScriptHelper} from a {@link Bindings} map.
+     *
+     * @param bindings the bindings map
+     * @return the {@link SlingScriptHelper} if found, {@code null} otherwise
+     */
+    public static SlingScriptHelper getHelper(Bindings bindings) {
+        return (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+    }
+
+    /**
+     * Locates a script resource identified by the {@code script} path. This path can be absolute or relative. If the path is relative
+     * then it will be used to locate a script for the current request, provided by the {@link SlingScriptHelper} parameter.
+     *
+     * @param resourceResolver a resource resolver used for searching the script
+     * @param sling            the {@link SlingScriptHelper}
+     * @param script           the path to the script
+     * @return the script resource if found, {@code null} otherwise
+     */
+    public static Resource locateScriptResource(ResourceResolver resourceResolver, SlingScriptHelper sling, String script) {
+        Resource result = null;
+        if (script.startsWith("/")) {
+            result = resourceResolver.getResource(script);
+        }
+        if (result == null) {
+            Resource componentResource = ResourceResolution.resolveComponentForRequest(resourceResolver, sling.getRequest());
+            result = ResourceResolution.resolveComponentRelative(resourceResolver, componentResource, script);
+        }
+        if (result != null) {
+            checkSearchPath(result, resourceResolver);
+        }
+        return result;
+    }
+
+    private static void checkSearchPath(Resource resource, ResourceResolver resourceResolver) {
+        String resourcePath = resource.getPath();
+        for (String path : resourceResolver.getSearchPath()) {
+            if (resourcePath.startsWith(path)) {
+                return;
+            }
+        }
+        throw new SightlyUseException("Use plugin cannot access path: " + resource.getPath());
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseProviderUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * 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.use;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+
+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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.scripting.sightly.extension.ExtensionInstance;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtensionException;
+import org.apache.sling.scripting.sightly.impl.plugin.UsePlugin;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.use.ProviderOutcome;
+import org.apache.sling.scripting.sightly.use.SightlyUseException;
+import org.apache.sling.scripting.sightly.use.UseProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Runtime extension for the USE plugin
+ */
+@Component
+@Service(RuntimeExtension.class)
+@Properties(
+        @Property(name = RuntimeExtension.SCR_PROP_NAME, value = UsePlugin.FUNCTION_NAME)
+)
+@Reference(
+        policy = ReferencePolicy.DYNAMIC,
+        referenceInterface = UseProvider.class,
+        name = "useProvider",
+        cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE
+)
+public class UseRuntimeExtension implements RuntimeExtension {
+
+    private final Map<ServiceReference, UseProvider> providersMap = new ConcurrentSkipListMap<ServiceReference, UseProvider>();
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ExtensionInstance provide(final RenderContext renderContext) {
+        return new ExtensionInstance() {
+
+            @Override
+            public Object call(Object... arguments) {
+                if (arguments.length != 2) {
+                    throw new RuntimeExtensionException("Use extension requires two arguments");
+                }
+                String identifier = renderContext.toString(arguments[0]);
+                if (StringUtils.isEmpty(identifier)) {
+                    return null;
+                }
+                Map<String, Object> useArgumentsMap = renderContext.toMap(arguments[1]);
+                Bindings useArguments = new SimpleBindings(Collections.unmodifiableMap(useArgumentsMap));
+                ArrayList<UseProvider> providers = new ArrayList<UseProvider>(providersMap.values());
+                ListIterator<UseProvider> iterator = providers.listIterator(providers.size());
+                while (iterator.hasPrevious()) {
+                    UseProvider provider = iterator.previous();
+                    ProviderOutcome outcome = provider.provide(identifier, renderContext, useArguments);
+                    if (outcome.isSuccess()) {
+                        return outcome.getResult();
+                    }
+                }
+                throw new SightlyUseException("No use provider could resolve identifier: " + identifier);
+            }
+        };
+    }
+
+    // OSGi ################################################################################################################################
+
+    @SuppressWarnings("UnusedDeclaration")
+    private void bindUseProvider(ServiceReference serviceReference) {
+        BundleContext bundleContext = serviceReference.getBundle().getBundleContext();
+        providersMap.put(serviceReference, (UseProvider) bundleContext.getService(serviceReference));
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    private void unbindUseProvider(ServiceReference serviceReference) {
+        providersMap.remove(serviceReference);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,418 @@
+/*******************************************************************************
+ * 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.runtime;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+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;
+import java.util.Map;
+import java.util.Set;
+
+import javax.script.Bindings;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.scripting.sightly.Record;
+import org.apache.sling.scripting.sightly.extension.ExtensionInstance;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+/**
+ * Rendering context for Sightly rendering units.
+ * @see RenderUnit
+ */
+public class RenderContextImpl implements RenderContext {
+
+    public static final String TO_STRING_METHOD = "toString";
+    public static final String PROPERTY_ACCESS = "resolveProperty";
+    public static final String COLLECTION_COERCE = "toCollection";
+    public static final String NUMERIC_COERCE = "toNumber";
+    public static final String STRING_COERCE = "toString";
+    public static final String BOOLEAN_COERCE = "toBoolean";
+
+
+    private final Bindings bindings;
+    private final Map<String, RuntimeExtension> mapping;
+    private final Map<String, ExtensionInstance> instanceCache = new HashMap<String, ExtensionInstance>();
+
+    public RenderContextImpl(Bindings bindings, Map<String, RuntimeExtension> mapping) {
+        this.bindings = bindings;
+        this.mapping = mapping;
+    }
+
+    /**
+     * Provide the bindings for this script
+     * @return - the list of global bindings available to the script
+     */
+    @Override
+    public Bindings getBindings() {
+        return bindings;
+    }
+
+    @Override
+    public Object call(String functionName, Object... arguments) {
+        ExtensionInstance instance;
+        instance = instanceCache.get(functionName);
+        if (instance == null) {
+            instance = createInstance(functionName);
+            instanceCache.put(functionName, instance);
+        }
+        return instance.call(arguments);
+    }
+
+    private ExtensionInstance createInstance(String name) {
+        RuntimeExtension extension = mapping.get(name);
+        if (extension == null) {
+            throw new SightlyRenderException("Runtime extension is not available: " + name);
+        }
+        return extension.provide(this);
+    }
+
+    @Override
+    public Object resolveProperty(Object target, Object property) {
+        if (property instanceof Number) {
+            return getIndex(target, ((Number) property).intValue());
+        }
+        return getProperty(target, property);
+    }
+
+    @Override
+    public String toString(Object target) {
+        return objectToString(target);
+    }
+
+    @Override
+    public boolean toBoolean(Object object) {
+        return toBooleanInternal(object);
+    }
+
+    @Override
+    public Collection<Object> toCollection(Object object) {
+        return obtainCollection(object);
+    }
+
+    @Override
+    public Map toMap(Object object) {
+        if (object instanceof Map) {
+            return (Map) object;
+        }
+        return Collections.emptyMap();
+    }
+
+
+    @Override
+    public Number toNumber(Object object) {
+        if (object instanceof Number) {
+            return (Number) object;
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean isCollection(Object obj) {
+        return (obj instanceof Collection) || (obj instanceof Object[])
+                || (obj instanceof Iterable)
+                || (obj instanceof Iterator);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Collection<Object> obtainCollection(Object obj) {
+        if (obj == null) {
+            return Collections.emptyList();
+        }
+        if (obj instanceof Object[]) {
+            return Arrays.asList((Object[]) obj);
+        }
+        if (obj instanceof Collection) {
+            return (Collection<Object>) obj;
+        }
+        if (obj instanceof Map) {
+            return ((Map) obj).keySet();
+        }
+        if (obj instanceof Record) {
+            return ((Record) obj).properties();
+        }
+        if (obj instanceof Enumeration) {
+            return Collections.list((Enumeration<Object>) obj);
+        }
+        if (obj instanceof Iterator) {
+            return fromIterator((Iterator<Object>) obj);
+        }
+        return Collections.emptyList();
+    }
+
+    private Collection<Object> fromIterator(Iterator<Object> iterator) {
+        ArrayList<Object> result = new ArrayList<Object>();
+        while (iterator.hasNext()) {
+            result.add(iterator.next());
+        }
+        return result;
+    }
+
+    private boolean toBooleanInternal(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof Number) {
+            Number number = (Number) obj;
+            //todo should we consider precision issues?
+            return !(number.doubleValue() == 0.0);
+        }
+
+        String s = obj.toString().trim();
+        if ("".equals(s)) {
+            return false;
+        } else if ("true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) {
+            return Boolean.parseBoolean(s);
+        }
+
+        if (obj instanceof Collection) {
+            return ((Collection) obj).size() > 0;
+        }
+
+        if (obj instanceof Map) {
+            return ((Map) obj).size() > 0;
+        }
+
+        if (obj instanceof Iterable<?>) {
+            return ((Iterable<?>) obj).iterator().hasNext();
+        }
+
+        if (obj instanceof Iterator<?>) {
+            return ((Iterator<?>) obj).hasNext();
+        }
+
+        if (obj instanceof Object[]) {
+            return ((Object[]) obj).length > 0;
+        }
+
+        return true;
+    }
+
+    private Object getProperty(Object target, Object propertyObj) {
+        String property = toString(propertyObj);
+        if (StringUtils.isEmpty(property)) {
+            throw new IllegalArgumentException("Invalid property name");
+        }
+        if (target == null) {
+            return null;
+        }
+        Object result = null;
+        if (target instanceof Map) {
+            result = getMapProperty((Map) target, property);
+        }
+        if (result == null && target instanceof Record) {
+            result = ((Record) target).get(property);
+        }
+        if (result == null) {
+            result = getObjectProperty(target, property);
+        }
+        if (result == null && target instanceof Adaptable) {
+            result = getValueMapProperty(((Adaptable) target).adaptTo(ValueMap.class), property);
+        }
+        return result;
+    }
+
+    private Object getIndex(Object obj, int index) {
+        if (obj instanceof Map) {
+            Map map = (Map) obj;
+            if (map.containsKey(index)) {
+                return map.get(index);
+            }
+        }
+        Collection collection = toCollection(obj);
+        if (collection instanceof List) {
+            return getIndexSafe((List) collection, index);
+        }
+        return null;
+    }
+
+    private Object getIndexSafe(List list, int index) {
+        if (index < 0 || index >= list.size()) {
+            return null;
+        }
+        return list.get(index);
+    }
+
+    private Object getValueMapProperty(ValueMap valueMap, String property) {
+        if (valueMap == null) {
+            return null;
+        }
+        return valueMap.get(property);
+    }
+
+    private Object getMapProperty(Map map, String property) {
+        return map.get(property);
+    }
+
+    private Object getObjectProperty(Object obj, String property) {
+        Object result = getObjectNoArgMethod(obj, property);
+        if (result != null) return result;
+        return getField(obj, property);
+    }
+
+    private Object getField(Object obj, String property) {
+        if (obj instanceof Object[] && "length".equals(property)) {
+            // Working around this limitation: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getFields%28%29
+            return ((Object[]) obj).length;
+        }
+        Class<?> cls = obj.getClass();
+        try {
+            Field field = cls.getDeclaredField(property);
+            return field.get(obj);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private Object getObjectNoArgMethod(Object obj, String property) {
+        Class<?> cls = obj.getClass();
+        Method method = findMethod(cls, property);
+        if (method != null) {
+            try {
+                method = extractMethodInheritanceChain(cls, method);
+                return method.invoke(obj);
+            } catch (Exception e) {
+                throw new SightlyRenderException(e);
+            }
+        }
+        return null;
+    }
+
+    private Method findMethod(Class<?> cls, String baseName) {
+        Method method;
+        String capitalized = StringUtils.capitalize(baseName);
+        method = tryMethod(cls, "get" + capitalized);
+        if (method != null) return method;
+        method = tryMethod(cls, "is" + capitalized);
+        if (method != null) return method;
+        method = tryMethod(cls, baseName);
+        return method;
+    }
+
+
+    private Method tryMethod(Class<?> cls, String name) {
+        try {
+            Method m = cls.getMethod(name);
+            Class<?> declaringClass = m.getDeclaringClass();
+            return (isMethodAllowed(m)) ? m : null;
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    private boolean isMethodAllowed(Method method) {
+        Class<?> declaringClass = method.getDeclaringClass();
+        //methods of the Object.class are forbidden (except toString, which is allowed)
+        return declaringClass != Object.class || TO_STRING_METHOD.equals(method.getName());
+    }
+
+
+    private String objectToString(Object obj) {
+        String output = "";
+        if (obj != null) {
+            if (obj instanceof String) {
+                output = (String) obj;
+            } else if (isPrimitive(obj)) {
+                output = obj.toString();
+            } else {
+                Collection<?> col = obtainCollection(obj);
+                if (col != null) {
+                    output = collectionToString(col);
+                }
+            }
+        }
+        return output;
+    }
+
+    private static final Set<Class<?>> primitiveClasses = primitiveClasses();
+
+    private boolean isPrimitive(Object obj) {
+        return primitiveClasses.contains(obj.getClass());
+    }
+
+    private String collectionToString(Collection<?> col) {
+        StringBuilder builder = new StringBuilder();
+        String prefix = "";
+        for (Object o : col) {
+            builder.append(prefix).append(objectToString(o));
+            prefix = ",";
+        }
+        return builder.toString();
+    }
+
+    private static Set<Class<?>> primitiveClasses() {
+        Set<Class<?>> set = new HashSet<Class<?>>();
+        set.add(Boolean.class);
+        set.add(Character.class);
+        set.add(Byte.class);
+        set.add(Short.class);
+        set.add(Integer.class);
+        set.add(Long.class);
+        set.add(Float.class);
+        set.add(Double.class);
+        set.add(Void.class);
+        return set;
+    }
+
+    private static Method extractMethodInheritanceChain(Class type, Method m) {
+        if (m == null || Modifier.isPublic(type.getModifiers())) {
+            return m;
+        }
+        Class[] inf = type.getInterfaces();
+        Method mp;
+        for (Class<?> iface : inf) {
+            try {
+                mp = iface.getMethod(m.getName(), m.getParameterTypes());
+                mp = extractMethodInheritanceChain(mp.getDeclaringClass(), mp);
+                if (mp != null) {
+                    return mp;
+                }
+            } catch (NoSuchMethodException e) {
+                // do nothing
+            }
+        }
+        Class<?> sup = type.getSuperclass();
+        if (sup != null) {
+            try {
+                mp = sup.getMethod(m.getName(), m.getParameterTypes());
+                mp = extractMethodInheritanceChain(mp.getDeclaringClass(), mp);
+                if (mp != null) {
+                    return mp;
+                }
+            } catch (NoSuchMethodException e) {
+                // do nothing
+            }
+        }
+        return null;
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderUnit.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderUnit.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderUnit.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderUnit.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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.runtime;
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.Record;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+/**
+ * Basic unit of rendering. This also extends the record interface. The properties for a unit are the sub-units.
+ */
+public abstract class RenderUnit implements Record<RenderUnit> {
+
+    private final Map<String, RenderUnit> subTemplates = new HashMap<String, RenderUnit>();
+
+    private Map<String, RenderUnit> siblings;
+
+    /**
+     * Render the main script template
+     * @param renderContext - the rendering context
+     * @param arguments - the arguments for this unit
+     */
+    public final void render(RenderContext renderContext, Bindings arguments) {
+        Bindings globalBindings = renderContext.getBindings();
+        PrintWriter writer = (PrintWriter) globalBindings.get(SlingBindings.OUT);
+        render(writer, buildGlobalScope(globalBindings), new CaseInsensitiveBindings(arguments), (RenderContextImpl) renderContext);
+    }
+
+    @Override
+    public RenderUnit get(String name) {
+        return subTemplates.get(name.toLowerCase());
+    }
+
+    @Override
+    public Set<String> properties() {
+        return subTemplates.keySet();
+    }
+
+    protected abstract void render(PrintWriter writer,
+                                   Bindings bindings,
+                                   Bindings arguments,
+                                   RenderContextImpl renderContext);
+
+    @SuppressWarnings({"unused", "unchecked"})
+    protected void callUnit(RenderContext renderContext, Object templateObj, Object argsObj) {
+        if (!(templateObj instanceof RenderUnit)) {
+            return;
+        }
+        RenderUnit unit = (RenderUnit) templateObj;
+        SlingScriptHelper ssh = (SlingScriptHelper) renderContext.getBindings().get(SlingBindings.SLING);
+        Map<String, Object> argumentsMap = renderContext.toMap(argsObj);
+        Bindings arguments = new SimpleBindings(Collections.unmodifiableMap(argumentsMap));
+        unit.render(renderContext, arguments);
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected FluentMap obj() {
+        return new FluentMap();
+    }
+
+    protected final void addSubTemplate(String name, RenderUnit renderUnit) {
+        renderUnit.setSiblings(subTemplates);
+        subTemplates.put(name.toLowerCase(), renderUnit);
+    }
+
+    private void setSiblings(Map<String, RenderUnit> siblings) {
+        this.siblings = siblings;
+    }
+
+    private Bindings buildGlobalScope(Bindings bindings) {
+        SimpleBindings simpleBindings = new SimpleBindings(bindings);
+        simpleBindings.putAll(bindings);
+        if (siblings != null) {
+            simpleBindings.putAll(siblings);
+        }
+        simpleBindings.putAll(subTemplates);
+        return new CaseInsensitiveBindings(simpleBindings);
+    }
+
+    protected static class FluentMap extends HashMap<String, Object> {
+
+        /**
+         * Fluent variant of put
+         * @param name - the name of the property
+         * @param value - the value of the property
+         * @return - this instance
+         */
+        public FluentMap with(String name, Object value) {
+            put(name, value);
+            return this;
+        }
+
+    }
+
+    private static final class CaseInsensitiveBindings extends SimpleBindings {
+
+        private CaseInsensitiveBindings(Map<String, Object> m) {
+            for (Map.Entry<String, Object> entry : m.entrySet()) {
+                put(entry.getKey().toLowerCase(), entry.getValue());
+            }
+        }
+
+        @Override
+        public Object get(Object key) {
+            if (!(key instanceof String)) {
+                throw new ClassCastException("key should be a String");
+            }
+            return super.get(((String) key).toLowerCase());
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            if (!(key instanceof String)) {
+                throw new ClassCastException("key should be a String");
+            }
+            return super.containsKey(((String) key).toLowerCase());
+        }
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderUnit.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/SightlyRenderException.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/SightlyRenderException.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/SightlyRenderException.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/SightlyRenderException.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+
+package org.apache.sling.scripting.sightly.impl.engine.runtime;
+
+import org.apache.sling.scripting.sightly.SightlyException;
+
+/**
+ * Exceptions generated by Sightly during runtime
+ */
+public class SightlyRenderException extends SightlyException {
+
+    public SightlyRenderException() {
+    }
+
+    public SightlyRenderException(String message) {
+        super(message);
+    }
+
+    public SightlyRenderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SightlyRenderException(Throwable cause) {
+        super(cause);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/SightlyRenderException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * A filter is a transformation which performs modifications on expressions. Unlike plugins, filters
+ * are always applied on an expression. Whether the filter transformation is actually necessary is
+ * decided by the filter. The application order of filters is given by filter priority.
+ */
+public interface Filter extends Comparable<Filter> {
+
+    /**
+     * Transform the given expression
+     * @param expression the original expression
+     * @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);
+
+    /**
+     * The priority with which filters are applied. This establishes order between filters. Filters with
+     * lower priority are applied first.
+     * @return an integer representing the filter's priority
+     */
+    int priority();
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/Filter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FilterComponent.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FilterComponent.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FilterComponent.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FilterComponent.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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 java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * Filters implemented as components.
+ */
+public abstract class FilterComponent implements Filter {
+
+    public static final String PRIORITY = "org.apache.sling.scripting.sightly.impl.filter.priority";
+    public static final int DEFAULT_PRIORITY = 100;
+
+    private int priority = DEFAULT_PRIORITY;
+
+    @Override
+    public int priority() {
+        return priority;
+    }
+
+    @Override
+    public int compareTo(Filter o) {
+        if (this.priority < o.priority()) {
+            return -1;
+        } else if (this.priority == o.priority()) {
+            return  0;
+        }
+        return 1;
+    }
+
+    @Activate
+    protected void activate(ComponentContext componentContext) {
+        Dictionary properties = componentContext.getProperties();
+        priority = PropertiesUtil.toInteger(properties.get(PRIORITY), DEFAULT_PRIORITY);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FilterComponent.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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 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.extension.ExtensionInstance;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtensionException;
+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.RuntimeCall;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+/**
+ * Implementation for the format filter & runtime support.
+ */
+@Component
+@Service({Filter.class, RuntimeExtension.class})
+@Properties({
+        @Property(name = RuntimeExtension.SCR_PROP_NAME, value = FormatFilter.FORMAT_FUNCTION)
+})
+public class FormatFilter extends FilterComponent implements RuntimeExtension {
+
+    public static final String FORMAT_OPTION = "format";
+    public static final String FORMAT_FUNCTION = "format";
+
+    private static final Pattern PLACEHOLDER_REGEX = Pattern.compile("\\{\\d}");
+
+    @Override
+    public Expression apply(Expression expression) {
+        //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)) {
+            return expression;
+        }
+        ExpressionNode argNode = expression.getOption(FORMAT_OPTION);
+        ExpressionNode formattedNode = new RuntimeCall(FORMAT_FUNCTION, expression.getRoot(), argNode);
+        return expression.withNode(formattedNode).removeOptions(FORMAT_OPTION);
+    }
+
+    @Override
+    public ExtensionInstance provide(final RenderContext renderContext) {
+
+        return new ExtensionInstance() {
+            @Override
+            public Object call(Object... arguments) {
+                if (arguments.length != 2) {
+                    throw new RuntimeExtensionException("Format function must be called with two arguments");
+                }
+                String source = renderContext.toString(arguments[0]);
+                Object[] params = decodeParams(arguments[1]);
+                return replace(source, params);
+            }
+
+            private Object[] decodeParams(Object paramObj) {
+                if (renderContext.isCollection(paramObj)) {
+                    return renderContext.toCollection(paramObj).toArray();
+                }
+                return new Object[] {paramObj};
+            }
+
+            private String replace(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) {
+                        int paramIndex = placeholderIndex(matcher.group());
+                        String replacement = param(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(Object[] params, int index) {
+                if (index >= 0 && index < params.length) {
+                    return renderContext.toString(params[index]);
+                }
+                return "";
+            }
+
+            private int placeholderIndex(String placeholder) {
+                return Integer.parseInt(placeholder.substring(1, placeholder.length() - 1));
+            }
+        };
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/FormatFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+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.NullLiteral;
+import org.apache.sling.scripting.sightly.impl.compiler.expression.node.RuntimeCall;
+
+/**
+ * Filter for i18n translation
+ */
+@Component
+@Service(Filter.class)
+@Property(name = FilterComponent.PRIORITY, intValue = 90)
+public class I18nFilter extends FilterComponent {
+
+    public static final String FUNCTION = "i18nTranslation";
+
+    public static final String I18N_OPTION = "i18n";
+    public static final String HINT_OPTION = "hint";
+    public static final String LOCALE_OPTION = "locale";
+
+    @Override
+    public Expression apply(Expression expression) {
+        if (!expression.containsOption(I18N_OPTION)) {
+            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);
+    }
+
+    private ExpressionNode option(Expression expression, String optionName) {
+        ExpressionNode node = expression.getOption(optionName);
+        if (node == null) {
+            return NullLiteral.INSTANCE;
+        }
+        return node;
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/I18nFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * 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 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.extension.ExtensionInstance;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.extension.RuntimeExtensionException;
+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.RuntimeCall;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+/**
+ * Filter providing support for the {@code join} option applied to arrays.
+ */
+@Component
+@Service({Filter.class, RuntimeExtension.class})
+@Properties({
+        @Property(name = RuntimeExtension.SCR_PROP_NAME, value = JoinFilter.JOIN_FUNCTION)
+})
+public class JoinFilter extends FilterComponent implements RuntimeExtension {
+
+    public static final String JOIN_OPTION = "join";
+    public static final String JOIN_FUNCTION = "join";
+
+    @Override
+    public Expression apply(Expression expression) {
+        if (!expression.containsOption(JOIN_OPTION)) {
+            return expression;
+        }
+        ExpressionNode argumentNode = expression.getOption(JOIN_OPTION);
+        ExpressionNode joinResult = new RuntimeCall(JOIN_FUNCTION, expression.getRoot(), argumentNode);
+        return expression.withNode(joinResult).removeOptions(JOIN_OPTION);
+    }
+
+    @Override
+    public ExtensionInstance provide(final RenderContext renderContext) {
+
+        return new ExtensionInstance() {
+            @Override
+            public Object call(Object... arguments) {
+                if (arguments.length != 2) {
+                    throw new RuntimeExtensionException("Join function must be called with two arguments.");
+                }
+                Collection<?> collection = renderContext.toCollection(arguments[0]);
+                String joinString = renderContext.toString(arguments[1]);
+                return join(collection, joinString);
+            }
+
+            private String join(Collection<?> collection, String joinString) {
+                StringBuilder sb = new StringBuilder();
+                Iterator<?> iterator = collection.iterator();
+                while (iterator.hasNext()) {
+                    String element = renderContext.toString(iterator.next());
+                    sb.append(element);
+                    if (iterator.hasNext()) {
+                        sb.append(joinString);
+                    }
+                }
+                return sb.toString();
+            }
+        };
+
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/JoinFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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 java.util.Map;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+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.compiler.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.impl.compiler.expression.node.RuntimeCall;
+
+/**
+ * XSS filter implementation
+ */
+@Component
+@Service(Filter.class)
+@Property(name = FilterComponent.PRIORITY, intValue = 110)
+public class XSSFilter extends FilterComponent {
+
+    public static final String FUNCTION_NAME = "xss";
+
+    @Override
+    public Expression apply(Expression expression) {
+        ExpressionNode node = expression.getRoot();
+        Map<String, ExpressionNode> options = expression.getOptions();
+        ExpressionNode context = options.get(Syntax.CONTEXT_OPTION);
+        if (context != null) {
+            return new Expression(new RuntimeCall(FUNCTION_NAME, node, context), options);
+        }
+        return expression;
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/filter/XSSFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/MarkupUtils.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/MarkupUtils.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/MarkupUtils.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/MarkupUtils.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.html;
+
+import java.util.regex.Pattern;
+
+/**
+ * Utility methods related to markup
+ */
+public class MarkupUtils {
+
+    private static final Pattern ATTRIBUTE_BLACKLIST = Pattern.compile("^(style|(on.*))$", Pattern.CASE_INSENSITIVE);
+
+    /**
+     * Attributes which should not be generated by Sightly
+     * @param name the name of the attribute
+     * @return if the attribute is sensitive or not
+     */
+    public static boolean isSensitiveAttribute(String name) {
+        return ATTRIBUTE_BLACKLIST.matcher(name).matches();
+    }
+
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/MarkupUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/AttributeList.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/AttributeList.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/AttributeList.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/AttributeList.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.html.dom;
+
+import java.util.Iterator;
+
+/**
+ * Contains the list of attributes inside an HTML tag.
+ */
+public interface AttributeList {
+
+    /**
+     * Return the count of attributes
+     * @return count of attributes
+     */
+    int attributeCount();
+
+    /**
+     * Return the list of attribute names
+     * @return <code>Iterator</code> iterating over the attribute names
+     */
+    Iterator<String> attributeNames();
+
+    /**
+     * Return a flag indicating whether a specified attribute exists
+     * @return <code>true</code> if the specified attribute exists,
+     * <code>false</code> otherwise
+     */
+    boolean containsAttribute(String name);
+
+    /**
+     * Return an attribute's value, given its name or <code>null</code>
+     * if the attribute cannot be found.
+     * @param name   attribute name
+     * @return an attribute's value
+     */
+    String getValue(String name);
+
+    /**
+     * Return an attribute's quote character, given its name or <code>0</code>
+     * if the attribute cannot be found.
+     * @param name   attribute name
+     * @return an attribute's quote character
+     */
+    char getQuoteChar(String name);
+
+    /**
+     * Return an attribute's value, already surrounded with the quotes
+     * originally in place. Returns <code>null</code> if the attribute
+     * cannot be found
+     * @param name   attribute name
+     * @return an attribute's value
+     */
+    String getQuotedValue(String name);
+
+    /**
+     * Set an attribute's value. If the value is <code>null</code>, this
+     * is semantically different to a {@link #removeValue(String)}.
+     *
+     * @param name      attribute name
+     * @param value     attribute value
+     */
+    void setValue(String name, String value);
+
+    /**
+     * Remove an attribute's value.
+     * @param name      attribute name
+     */
+    void removeValue(String name);
+
+    /**
+     * Return a flag indicating whether this object was modified.
+     * @return <code>true</code> if the object was modified
+     *         <code>false</code> otherwise
+     */
+    boolean isModified();
+}
\ No newline at end of file

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/AttributeList.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/DocumentHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/DocumentHandler.java?rev=1642281&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/DocumentHandler.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/DocumentHandler.java Fri Nov 28 10:18:01 2014
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.html.dom;
+
+import java.io.IOException;
+
+
+/**
+ * Invoked by the <code>HTMLParser</code> when elements are scanned.
+ */
+public interface DocumentHandler {
+
+    /**
+     * Receive notification of unparsed character data.
+     */
+    void onCharacters(char[] ch, int off, int len) throws IOException;
+
+    void onComment(String characters) throws IOException;
+
+    /**
+     * Receive notification of the beginning of an element.
+     * @param name     tag name
+     * @param attList  attribute list
+     * @param endSlash flag indicating whether the element is closed with
+     *                 an ending slash (xhtml-compliant)
+     */
+    void onStartElement(String name, AttributeList attList, boolean endSlash)
+    throws IOException;
+
+    /**
+     * Receive notification of the end of an element.
+     * @param name tag name
+     */
+    void onEndElement(String name)
+    throws IOException;
+
+    /**
+     * Receive notification of parsing start.
+     */
+    void onStart() throws IOException;
+
+    /**
+     * Receive notification of parsing end.
+     */
+    void onEnd() throws IOException;
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/html/dom/DocumentHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain