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 2019/01/22 09:41:16 UTC

[sling-org-apache-sling-scripting-sightly-runtime] branch issue/SLING-8228 created (now fe8a9e8)

This is an automated email from the ASF dual-hosted git repository.

radu pushed a change to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git.


      at fe8a9e8  SLING-8228 - Expand Optional objects in the ObjectModel

This branch includes the following new commits:

     new ef2d6e1  SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
     new d735eb7  trivial: corrected link to htl java compiler
     new 1dab5c3  trivial: updated badges
     new 5caa79c  SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
     new ba287f5  trivial: updated badges
     new 081b800  SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
     new f712f4a  [maven-release-plugin] prepare release org.apache.sling.scripting.sightly.runtime-1.0.0-1.4.0
     new 0aaf361  [maven-release-plugin] prepare for next development iteration
     new 3c5f914  trivial: updated findbugs
     new 393ca79  SLING-8205 - Stop using Class.getField() in order to avoid throwing NoSuchFieldException
     new fe8a9e8  SLING-8228 - Expand Optional objects in the ObjectModel

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[sling-org-apache-sling-scripting-sightly-runtime] 11/11: SLING-8228 - Expand Optional objects in the ObjectModel

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit fe8a9e88af508ee8d5f1d1661cc9f25b85b9a97f
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Tue Jan 22 10:34:41 2019 +0100

    SLING-8228 - Expand Optional objects in the ObjectModel
    
    * applied slightly modified patch from #2 (closes #2)
    
    Co-authored-by: Ilyas Turkben <is...@gmail.com>
---
 .../scripting/sightly/render/ObjectModel.java      | 20 +++++++-
 .../scripting/sightly/render/ObjectModelTest.java  | 58 +++++++++++++++++++++-
 2 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
index e3ef0ad..3797e00 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
@@ -31,6 +31,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
@@ -114,6 +115,9 @@ public final class ObjectModel {
         if (resolved == null) {
             String propertyName = toString(property);
             if (StringUtils.isNotEmpty(propertyName)) {
+                if (target instanceof Optional) {
+                    return resolveProperty(((Optional) target).orElse(null), property);
+                }
                 if (target instanceof Map) {
                     resolved = ((Map) target).get(property);
                 }
@@ -177,6 +181,10 @@ public final class ObjectModel {
             return ((Iterator<?>) object).hasNext();
         }
 
+        if (object instanceof Optional) {
+            return toBoolean(((Optional) object).orElse(false));
+        }
+
         return !(object instanceof Object[]) || ((Object[]) object).length > 0;
     }
 
@@ -195,6 +203,10 @@ public final class ObjectModel {
         if (object instanceof Number) {
             return (Number) object;
         }
+        if (object instanceof Optional) {
+            return toNumber(((Optional) object).orElse(null));
+        }
+
         String stringValue = toString(object);
         try {
             return NumberUtils.createNumber(stringValue);
@@ -227,7 +239,10 @@ public final class ObjectModel {
                 output = object.toString();
             } else if (object instanceof Enum) {
                 return ((Enum) object).name();
-            } else {
+            } else if (object instanceof Optional) {
+                return toString(((Optional) object).orElse(EMPTY_STRING));
+            }
+            else {
                 Collection<?> col = toCollection(object);
                 output = collectionToString(col);
             }
@@ -269,6 +284,9 @@ public final class ObjectModel {
             }
             return list;
         }
+        if (object instanceof Optional) {
+            return toCollection(((Optional) object).orElse(Collections.emptyList()));
+        }
         if (object instanceof Collection) {
             return (Collection<Object>) object;
         }
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java b/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java
index 28f88bd..1ec2699 100644
--- a/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Vector;
 
 import org.apache.sling.scripting.sightly.render.testobjects.Person;
@@ -72,6 +73,14 @@ public class ObjectModelTest {
         assertTrue(ObjectModel.toBoolean(new Bag<>(testArray)));
         assertFalse(ObjectModel.toBoolean(new Bag<>(new Integer[]{})));
         assertTrue(ObjectModel.toBoolean(new Date()));
+
+        assertFalse(ObjectModel.toBoolean(Optional.empty()));
+        assertFalse(ObjectModel.toBoolean(Optional.of("")));
+        assertFalse(ObjectModel.toBoolean(Optional.of(false)));
+        assertFalse(ObjectModel.toBoolean(Optional.ofNullable(null)));
+        assertTrue(ObjectModel.toBoolean(Optional.of(true)));
+        assertTrue(ObjectModel.toBoolean(Optional.of("pass")));
+        assertTrue(ObjectModel.toBoolean(Optional.of(1)));
     }
 
     @Test
@@ -80,6 +89,14 @@ public class ObjectModelTest {
         assertEquals(1, ObjectModel.toNumber("1"));
         assertNull(ObjectModel.toNumber(null));
         assertNull(ObjectModel.toNumber("1-2"));
+
+        assertNull(ObjectModel.toNumber(Optional.empty()));
+        assertNull(ObjectModel.toNumber(Optional.of(false)));
+        assertNull(ObjectModel.toNumber(Optional.ofNullable(null)));
+        assertNull(ObjectModel.toNumber(Optional.of(true)));
+        assertNull(ObjectModel.toNumber(Optional.of("pass")));
+        assertEquals(1, ObjectModel.toNumber(Optional.of(1)));
+        assertEquals(1, ObjectModel.toNumber(Optional.of("1")));
     }
 
     @Test
@@ -94,6 +111,14 @@ public class ObjectModelTest {
         assertEquals("1,2,3", ObjectModel.toString(testList));
         assertEquals("1,2,3", ObjectModel.toString(testArray));
         assertEquals("1,2,3", ObjectModel.toString(testPrimitiveArray));
+
+        assertEquals("", ObjectModel.toString(Optional.empty()));
+        assertEquals("false", ObjectModel.toString(Optional.of(false)));
+        assertEquals("", ObjectModel.toString(Optional.ofNullable(null)));
+        assertEquals("true", ObjectModel.toString(Optional.of(true)));
+        assertEquals("pass", ObjectModel.toString(Optional.of("pass")));
+        assertEquals("1", ObjectModel.toString(Optional.of(1)));
+        assertEquals("1", ObjectModel.toString(Optional.of("1")));
     }
 
     @Test
@@ -101,7 +126,7 @@ public class ObjectModelTest {
         assertTrue(ObjectModel.toCollection(null).isEmpty());
         assertTrue(ObjectModel.toCollection(new StringBuilder()).isEmpty());
         Integer[] testArray = new Integer[] {1, 2, 3};
-        int[] testPrimitiveArray = new int[]{1, 2, 3};
+        int[] testPrimitiveArray = new int[] {1, 2, 3};
         List<Integer> testList = Arrays.asList(testArray);
         Map<String, Integer> map = new HashMap<String, Integer>() {{
             put("one", 1);
@@ -121,6 +146,12 @@ public class ObjectModelTest {
         assertTrue(stringCollection.size() == 1 && stringCollection.contains(stringObject));
         Collection numberCollection = ObjectModel.toCollection(numberObject);
         assertTrue(numberCollection.size() == 1 && numberCollection.contains(numberObject));
+
+        List<Object> emptyList = Collections.emptyList();
+        assertEquals(emptyList, ObjectModel.toCollection(Optional.empty()));
+        assertEquals(emptyList, ObjectModel.toCollection(Optional.of(Arrays.asList())));
+        List<Integer> list = Arrays.asList(1, 2, 3);
+        assertEquals(list, ObjectModel.toCollection(Optional.of(list)));
     }
 
     @Test
@@ -176,6 +207,15 @@ public class ObjectModelTest {
         assertNull("Expected null result for public method available on implementation but not exposed by interface.", ObjectModel
                 .resolveProperty(johnDoe, "fullName"));
         assertNull("Expected null result for inexistent method.", ObjectModel.resolveProperty(johnDoe, "nomethod"));
+
+        OptionalTest optionalTest = new OptionalTest();
+        assertEquals(Optional.of("string"), ObjectModel.resolveProperty(optionalTest, "string"));
+        assertEquals(Optional.of(1), ObjectModel.resolveProperty(optionalTest, "int"));
+        assertEquals(Optional.of(1), ObjectModel.resolveProperty(Optional.of(optionalTest), "int"));
+        assertEquals(Optional.of(Integer.valueOf(1)), ObjectModel.resolveProperty(optionalTest, "integer"));
+        assertEquals(Optional.of(Integer.valueOf(1)), ObjectModel.resolveProperty(Optional.of(optionalTest), "integer"));
+        assertEquals(null, ObjectModel.resolveProperty(Optional.empty(), "integer"));
+
     }
 
     @Test
@@ -242,4 +282,20 @@ public class ObjectModelTest {
             };
         }
     }
+
+    public class OptionalTest {
+        public Optional<String> getEmpty() {
+            return Optional.empty();
+        }
+        public Optional<String> getString() {
+            return Optional.of("string");
+        }
+        public Optional<Integer> getInt() {
+            return Optional.of(1);
+        }
+        public Optional<Integer> getInteger() {
+            return Optional.of(Integer.valueOf(1));
+        }
+    }
 }
+


[sling-org-apache-sling-scripting-sightly-runtime] 08/11: [maven-release-plugin] prepare for next development iteration

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 0aaf3617ddade257668ff1b36dee37b4452e52e9
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Wed Oct 31 17:35:51 2018 +0100

    [maven-release-plugin] prepare for next development iteration
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 549cc8d..7193559 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
         The versioning scheme defined here corresponds to SLING-7406 (<module_version>-<htl_specification_version>). Take care when
         releasing to only increase the first part, unless the module provides support for a newer version of the HTL specification.
     -->
-    <version>1.0.0-1.4.0</version>
+    <version>1.0.1-1.4.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Scripting HTL Runtime</name>
@@ -48,7 +48,7 @@
         <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</connection>
         <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-scripting-sightly-runtime.git</url>
-      <tag>org.apache.sling.scripting.sightly.runtime-1.0.0-1.4.0</tag>
+      <tag>HEAD</tag>
   </scm>
 
     <properties>


[sling-org-apache-sling-scripting-sightly-runtime] 10/11: SLING-8205 - Stop using Class.getField() in order to avoid throwing NoSuchFieldException

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 393ca79e458d9cd8172be8b6107d2474101101d1
Author: Nicolas Peltier <np...@apache.org>
AuthorDate: Wed Jan 9 11:48:47 2019 +0100

    SLING-8205 - Stop using Class.getField() in order to avoid throwing NoSuchFieldException
    
    * iterate through Class.getFields; this can still throw an IllegalAccessException,
    but less likely than the previous approach - closes #3
---
 .../sling/scripting/sightly/render/ObjectModel.java       | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
index 6b437d7..e3ef0ad 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
@@ -367,12 +367,17 @@ public final class ObjectModel {
         if (cls.isArray() && "length".equals(fieldName)) {
             return Array.getLength(object);
         }
-        try {
-            Field field = cls.getField(fieldName);
-            return field.get(object);
-        } catch (Exception e) {
-            return null;
+        for (Field field : cls.getFields()){
+            if (field.getName().equals(fieldName)){
+                try {
+                    return field.get(object);
+                }
+                catch (IllegalAccessException e) {
+                    return null;
+                }
+            }
         }
+        return null;
     }
 
     /**


[sling-org-apache-sling-scripting-sightly-runtime] 05/11: trivial: updated badges

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit ba287f54a05ab6c8a7a4c2225b7d42d4dea6d537
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Wed Oct 31 17:31:11 2018 +0100

    trivial: updated badges
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 181d563..81ee313 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 [<img src="http://sling.apache.org/res/logos/sling.png"/>](http://sling.apache.org)
 
- [![Build Status](https://builds.apache.org/buildStatus/icon?job=sling-org-apache-sling-scripting-sightly-runtime-1.8)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8.svg)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8/test_resu [...]
+ [![Build Status](https://builds.apache.org/buildStatus/icon?job=sling-org-apache-sling-scripting-sightly-runtime-1.8)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8.svg)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8/test_resu [...]
 
 # Apache Sling Scripting HTL Runtime
 


[sling-org-apache-sling-scripting-sightly-runtime] 01/11: SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit ef2d6e1ef567e3543de3078ec2251463486b100e
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Thu Oct 18 13:42:40 2018 +0200

    SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
    
    * initial commit
---
 .gitignore                                         |  17 +
 CODE_OF_CONDUCT.md                                 |  22 +
 CONTRIBUTING.md                                    |  24 ++
 LICENSE                                            | 202 +++++++++
 README.md                                          |   9 +
 pom.xml                                            | 192 +++++++++
 .../org/apache/sling/scripting/sightly/Record.java |  51 +++
 .../sling/scripting/sightly/SightlyException.java  |  38 ++
 .../sightly/extension/RuntimeExtension.java        | 170 ++++++++
 .../scripting/sightly/extension/package-info.java  |  22 +
 .../sling/scripting/sightly/package-info.java      |  21 +
 .../apache/sling/scripting/sightly/pojo/Use.java   |  47 ++
 .../sling/scripting/sightly/pojo/package-info.java |  22 +
 .../sightly/render/AbstractRuntimeObjectModel.java | 143 ++++++
 .../scripting/sightly/render/ObjectModel.java      | 480 +++++++++++++++++++++
 .../scripting/sightly/render/RenderContext.java    |  51 +++
 .../sling/scripting/sightly/render/RenderUnit.java | 156 +++++++
 .../sightly/render/RuntimeObjectModel.java         | 121 ++++++
 .../scripting/sightly/render/package-info.java     |  20 +
 .../scripting/sightly/use/ProviderOutcome.java     | 133 ++++++
 .../sling/scripting/sightly/use/UseProvider.java   |  46 ++
 .../sling/scripting/sightly/use/package-info.java  |  22 +
 .../render/AbstractRuntimeObjectModelTest.java     | 168 ++++++++
 .../scripting/sightly/render/ObjectModelTest.java  | 245 +++++++++++
 .../sightly/render/testobjects/Person.java         |  29 ++
 .../sightly/render/testobjects/TestEnum.java       |  25 ++
 .../testobjects/internal/AbstractPerson.java       |  42 ++
 .../sightly/render/testobjects/internal/Adult.java |  32 ++
 .../render/testobjects/internal/AdultFactory.java  |  26 ++
 29 files changed, 2576 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5b783ed
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+/target
+.idea
+.classpath
+.metadata
+.project
+.settings
+.externalToolBuilders
+maven-eclipse.xml
+*.swp
+*.iml
+*.ipr
+*.iws
+*.bak
+.vlt
+.DS_Store
+jcr.log
+atlassian-ide-plugin.xml
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..0fa18e5
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,22 @@
+<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/-->
+Apache Software Foundation Code of Conduct
+====
+
+Being an Apache project, Apache Sling adheres to the Apache Software Foundation's [Code of Conduct](https://www.apache.org/foundation/policies/conduct.html).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..ac82a1a
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/-->
+Contributing
+====
+
+Thanks for choosing to contribute!
+
+You will find all the necessary details about how you can do this at https://sling.apache.org/contributing.html.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9fa5bc8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+[<img src="http://sling.apache.org/res/logos/sling.png"/>](http://sling.apache.org)
+
+ [![Build Status](https://builds.apache.org/buildStatus/icon?job=sling-org-apache-sling-scripting-sightly-runtime-1.8)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8.svg)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8/test_resu [...]
+
+# Apache Sling Scripting HTL Runtime
+
+This module is part of the [Apache Sling](https://sling.apache.org) project.
+
+The Apache Sling Scripting HTL Runtime provides support for executing HTL Java compiled units produced by the [`org.apache.sling.scripting.sightly.compiler.java module`](https://github.com/apache/sling-org-apache-sling-scripting-sightly-runtime).
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0b404db
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <!-- ======================================================================= -->
+    <!-- P A R E N T   P R O J E C T                                             -->
+    <!-- ======================================================================= -->
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>30</version>
+        <relativePath />
+    </parent>
+
+    <!-- ======================================================================= -->
+    <!-- P R O J E C T                                                           -->
+    <!-- ======================================================================= -->
+    <artifactId>org.apache.sling.scripting.sightly.runtime</artifactId>
+    <!--
+        The versioning scheme defined here corresponds to SLING-7406 (<module_version>-<htl_specification_version>). Take care when
+        releasing to only increase the first part, unless the module provides support for a newer version of the HTL specification.
+    -->
+    <version>1.0.0-1.4.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Scripting HTL Runtime</name>
+
+    <description>
+        The Apache Sling Scripting HTL Runtime provides support for executing HTL Java compiled units produced by the org.apache.sling.scripting.sightly.compiler.java module.
+    </description>
+
+    <scm>
+        <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</connection>
+        <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</developerConnection>
+        <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-scripting-sightly-runtime.git</url>
+      <tag>HEAD</tag>
+  </scm>
+
+    <properties>
+        <jacoco.maven.plugin.version>0.7.9</jacoco.maven.plugin.version>
+        <sling.java.version>8</sling.java.version>
+    </properties>
+
+    <!-- ======================================================================= -->
+    <!-- B U I L D                                                               -->
+    <!-- ======================================================================= -->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>scr-metadata</id>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <exportScr>true</exportScr>
+                    <instructions>
+                        <Provide-Capability>
+                            io.sightly.runtime; version:Version=1.0,
+                            io.sightly.runtime; version:Version=1.1,
+                            io.sightly.runtime; version:Version=1.2,
+                            io.sightly.runtime; version:Version=1.3,
+                            io.sightly.runtime; version:Version=1.3.1,
+                            io.sightly.runtime; version:Version=1.4
+                        </Provide-Capability>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>3.0.3</version>
+                <configuration>
+                    <effort>Max</effort>
+                    <xmlOutput>true</xmlOutput>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>find-bugs</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <!-- No javadocs -->
+                    <excludePackageNames>
+                        org.apache.sling.scripting.sightly.java.compiler.impl
+                    </excludePackageNames>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>coverage-report</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.jacoco</groupId>
+                        <artifactId>jacoco-maven-plugin</artifactId>
+                        <version>${jacoco.maven.plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <id>default-prepare-agent</id>
+                                <goals>
+                                    <goal>prepare-agent</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>default-report</id>
+                                <goals>
+                                    <goal>report</goal>
+                                </goals>
+                                <configuration>
+                                    <includes>
+                                        <include>org/apache/sling/scripting/sightly/**/*</include>
+                                    </includes>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <!-- ======================================================================= -->
+    <!-- D E P E N D E N C I E S                                                 -->
+    <!-- ======================================================================= -->
+    <dependencies>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Apache Commons -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/src/main/java/org/apache/sling/scripting/sightly/Record.java b/src/main/java/org/apache/sling/scripting/sightly/Record.java
new file mode 100644
index 0000000..5c8be4a
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/Record.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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;
+
+import java.util.Set;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * A {@code Record} is a key-value immutable object understood by the HTL runtime, used for abstracting complex objects like Sightly
+ * templates (declared with the {@code data-sly-template} block element) or objects that need to be translated from Java to JavaScript
+ * and back.
+ *
+ * @param <T> the type of values for this record
+ */
+@ConsumerType
+public interface Record<T> {
+
+    /**
+     * Gets the value of a specified property.
+     *
+     * @param name the name of the property
+     * @return the value of the property or {@code null} if this record does not have the specified property
+     */
+    T getProperty(String name);
+
+    /**
+     * Gets the set of names for this record's properties.
+     *
+     * @return this record's properties' names
+     */
+    Set<String> getPropertyNames();
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/SightlyException.java b/src/main/java/org/apache/sling/scripting/sightly/SightlyException.java
new file mode 100644
index 0000000..16111ee
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/SightlyException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * Exceptions caused by the HTL engine.
+ */
+public class SightlyException extends RuntimeException {
+
+    public SightlyException() {
+    }
+
+    public SightlyException(String message) {
+        super(message);
+    }
+
+    public SightlyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SightlyException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java b/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java
new file mode 100644
index 0000000..1cfaa0c
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * 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.extension;
+
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * A {@code RuntimeExtension} represents a HTL runtime construct that provides some processing capabilities for the various
+ * {@code data-sly-*} block elements.
+ */
+@ConsumerType
+public interface RuntimeExtension {
+
+    /**
+     * <p>
+     *     The name of the runtime function that will process string
+     *     formatting. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>the format String (e.g. 'Hello {0}, welcome to {1}')</li>
+     *     <li>an array of objects that will replace the format placeholders</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#122-format.
+     * </p>
+     */
+    String FORMAT = "format";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will process
+     *     i18n. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>the String to translate</li>
+     *     <li>optional: locale information</li>
+     *     <li>optional: hint information</li>
+     *     <li>optional (not part of the specification): basename information; for more details see
+     *     {@link java.util.ResourceBundle#getBundle(String, java.util.Locale)}</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#123-i18n.
+     * </p>
+     */
+    String I18N = "i18n";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will process
+     *     join operations on arrays. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>the array of objects to join (e.g. [1, 2, 3])</li>
+     *     <li>the join string (e.g. ';')</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#124-array-join.
+     * </p>
+     */
+    String JOIN = "join";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will provide
+     *     URI manipulation support. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>optional: a URI string to process</li>
+     *     <li>optional: a Map containing URI manipulation options</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#125-uri-manipulation.
+     * </p>
+     */
+    String URI_MANIPULATION = "uriManipulation";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will provide
+     *     XSS escaping and filtering support. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>the original string to escape / filter</li>
+     *     <li>the context to be applied - see {@link org.apache.sling.scripting.sightly.compiler.expression.MarkupContext}</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#121-display-context.
+     * </p>
+     */
+    String XSS = "xss";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will perform
+     *     script execution delegation. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>optional: the relative or absolute path of the script to execute</li>
+     *     <li>optional: a Map of options to perform script include processing</li>
+     * </ol>
+     * <p>
+     *     For more details about the supported options check
+     *     https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#228-include.
+     * </p>
+     */
+    String INCLUDE = "include";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will perform
+     *     resource inclusion in the rendering process. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>optional: a relative or absolute path of the resource to be included</li>
+     *     <li>optional: a Map containing the resource processing options</li>
+     * </ol>
+     * <p>
+     *     For more details about the supported options check
+     *     https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#229-resource.
+     * </p>
+     */
+    String RESOURCE = "includeResource";
+
+    /**
+     * <p>
+     *     The name of the runtime function that will provide
+     *     the support for loading Use-API objects. The function will receive the following parameters:
+     * </p>
+     * <ol>
+     *     <li>an identifier that allows to discover the Use-API object that needs to be loaded</li>
+     *     <li>optional: a Map of the arguments that are passed to the Use-API object for initialisation or to provide context</li>
+     * </ol>
+     * <p>
+     *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#221-use.
+     * </p>
+     */
+    String USE = "use";
+
+    /**
+     * For OSGi environments this is the name of the service registration property indicating the {@code RuntimeExtension} name.
+     */
+    String NAME = "org.apache.sling.scripting.sightly.extension.name";
+
+    /**
+     * Call the {@code RuntimeExtension}
+     *
+     * @param renderContext the runtime context
+     * @param arguments     the call arguments
+     * @return an extension instance
+     */
+    Object call(RenderContext renderContext, Object... arguments);
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/extension/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/extension/package-info.java
new file mode 100644
index 0000000..1bbe78a
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/extension/package-info.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+@Version("1.1.0")
+package org.apache.sling.scripting.sightly.extension;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/sightly/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/package-info.java
new file mode 100644
index 0000000..f2af1f3
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/package-info.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+
+@Version("2.0.0")
+package org.apache.sling.scripting.sightly;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/sightly/pojo/Use.java b/src/main/java/org/apache/sling/scripting/sightly/pojo/Use.java
new file mode 100644
index 0000000..722b79a
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/pojo/Use.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.pojo;
+
+import javax.script.Bindings;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * The <code>Use</code> interface can be implemented by Java objects which are instantiated as part of processing {@code data-sly-use}
+ * attributes.
+ *
+ * @see <a href="https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/master/SPECIFICATION.md#221-use">HTL Block Statements - Use</a>
+ */
+@ConsumerType
+public interface Use {
+
+    /**
+     * <p>
+     *     Called to initialize the Java object with the current Java Scripting API bindings.
+     * </p>
+     * <p>
+     *     This method is called only if the object has been instantiated by HTL as part of processing the {@code data-sly-use}
+     *     attribute. The Java Scripting API bindings provide all the global variables known to a script being executed.
+     * </p>
+     *
+     * @param bindings The Java Scripting API bindings.
+     */
+    void init(Bindings bindings);
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/pojo/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/pojo/package-info.java
new file mode 100644
index 0000000..746ab8f
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/pojo/package-info.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+@Version("1.0.1")
+package org.apache.sling.scripting.sightly.pojo;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModel.java b/src/main/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModel.java
new file mode 100644
index 0000000..858693e
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModel.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * 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.render;
+
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.sling.scripting.sightly.Record;
+
+/**
+ * Default abstract implementation of {@link RuntimeObjectModel}.
+ */
+public abstract class AbstractRuntimeObjectModel implements RuntimeObjectModel {
+
+    @Override
+    public boolean isPrimitive(Object obj) {
+        return ObjectModel.isPrimitive(obj);
+    }
+
+    @Override
+    public boolean isDate(Object target) {
+        return (target instanceof Date || target instanceof Calendar);
+    }
+
+    @Override
+    public boolean isNumber(Object target) {
+        if (target == null) {
+            return false;
+        }
+        if (target instanceof Number) {
+            return true;
+        }
+        String value = toString(target);
+        return NumberUtils.isCreatable(value);
+    }
+
+    @Override
+    public boolean isCollection(Object target) {
+        return (target instanceof Collection) || (target instanceof Object[]) || (target instanceof Iterable) ||
+                (target instanceof Iterator);
+    }
+
+    @Override
+    public Object resolveProperty(Object target, Object property) {
+        if (target == null || property == null) {
+            return null;
+        }
+        Object resolved = null;
+        if (property instanceof Number) {
+            resolved = ObjectModel.getIndex(target, ((Number) property).intValue());
+        }
+        if (resolved == null) {
+            resolved = getProperty(target, property);
+        }
+        return resolved;
+    }
+
+    @Override
+    public boolean toBoolean(Object object) {
+        return ObjectModel.toBoolean(object);
+    }
+
+    @Override
+    public Number toNumber(Object object) {
+        return ObjectModel.toNumber(object);
+    }
+
+    @Override
+    public Date toDate(Object object) {
+        if (object instanceof Date) {
+            return (Date)object;
+        } else if (object instanceof Calendar) {
+            return ((Calendar)object).getTime();
+        }
+        return null;
+    }
+
+    @Override
+    public String toString(Object target) {
+        return ObjectModel.toString(target);
+    }
+
+    @Override
+    public Collection<Object> toCollection(Object object) {
+        if (object instanceof Record) {
+            return ((Record) object).getPropertyNames();
+        }
+        return ObjectModel.toCollection(object);
+    }
+
+    @Override
+    public Map toMap(Object object) {
+        if (object instanceof Map) {
+            return (Map) object;
+        } else if (object instanceof Record) {
+            Map<String, Object> map = new HashMap<>();
+            Record record = (Record) object;
+            Set<String> properties = record.getPropertyNames();
+            for (String property : properties) {
+                map.put(property, record.getProperty(property));
+            }
+            return map;
+        }
+        return Collections.emptyMap();
+    }
+
+    protected Object getProperty(Object target, Object propertyObj) {
+        if (target == null || propertyObj == null) {
+            return null;
+        }
+        String property = ObjectModel.toString(propertyObj);
+        Object result = null;
+        if (target instanceof Record) {
+            result = ((Record) target).getProperty(property);
+        }
+        if (result == null) {
+            result = ObjectModel.resolveProperty(target, propertyObj);
+        }
+        return result;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
new file mode 100644
index 0000000..6b437d7
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/ObjectModel.java
@@ -0,0 +1,480 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render;
+
+import java.lang.reflect.Array;
+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.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@code ObjectModel} class provides various static models for object conversion and object property resolution.
+ */
+public final class ObjectModel {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ObjectModel.class);
+    private static final String EMPTY_STRING = "";
+
+    /**
+     * A {@link Set} that stores all the supported primitive classes.
+     */
+    private static final Set<Class<?>> PRIMITIVE_CLASSES;
+
+    static {
+        Set<Class<?>> primitivesBuilder = new HashSet<>();
+        primitivesBuilder.add(Boolean.class);
+        primitivesBuilder.add(Character.class);
+        primitivesBuilder.add(Byte.class);
+        primitivesBuilder.add(Short.class);
+        primitivesBuilder.add(Integer.class);
+        primitivesBuilder.add(Long.class);
+        primitivesBuilder.add(Float.class);
+        primitivesBuilder.add(Double.class);
+        primitivesBuilder.add(Void.class);
+        PRIMITIVE_CLASSES = Collections.unmodifiableSet(primitivesBuilder);
+    }
+
+
+    private static final String TO_STRING_METHOD = "toString";
+
+    private ObjectModel() {}
+
+    /**
+     * Checks if the provided {@code object} is an instance of a primitive class.
+     *
+     * @param object the {@code Object} to check
+     * @return {@code true} if the {@code object} is a primitive, {@code false} otherwise
+     */
+    public static boolean isPrimitive(Object object) {
+        return PRIMITIVE_CLASSES.contains(object.getClass());
+    }
+
+    /**
+     * <p>
+     *      Given the {@code target} object, this method attempts to resolve and return the value of the passed {@code property}.
+     * </p>
+     * <p>
+     *      The property can be either an index or a name:
+     * </p>
+     * <ul>
+     *      <li>index: the property is considered an index if its value is an integer number and in this case the {@code target}
+     *      will be assumed to be either an array or it will be converted to a {@link Collection}; a fallback to {@link Map} will be
+     *      made in case the previous two attempts failed
+     *      </li>
+     *      <li>name: the {@code property} will be converted to a {@link String} (see {@link #toString(Object)}); the {@code target}
+     *      will be assumed to be either a {@link Map} or an object; if the {@link Map} attempt fails, the {@code property} will be
+     *      used to check if the {@code target} has a publicly accessible field with this name or a publicly accessible method with no
+     *      parameters with this name or a combination of the "get" or "is" prefixes plus the capitalised name (see
+     *      {@link #invokeBeanMethod(Object, String)})</li>
+     * </ul>
+     *
+     * @param target   the target object
+     * @param property the property to be resolved
+     * @return the value of the property or {@code null}
+     */
+    public static Object resolveProperty(Object target, Object property) {
+        if (target == null || property == null) {
+            return null;
+        }
+        Object resolved = null;
+        if (property instanceof Number) {
+            resolved = getIndex(target, ((Number) property).intValue());
+        }
+        if (resolved == null) {
+            String propertyName = toString(property);
+            if (StringUtils.isNotEmpty(propertyName)) {
+                if (target instanceof Map) {
+                    resolved = ((Map) target).get(property);
+                }
+                if (resolved == null) {
+                    resolved = getField(target, propertyName);
+                }
+                if (resolved == null) {
+                    resolved = invokeBeanMethod(target, propertyName);
+                }
+            }
+        }
+        return resolved;
+    }
+
+    /**
+     * Converts the given {@code object} to a boolean value, applying the following rules:
+     *
+     * <ul>
+     *     <li>if the {@code object} is {@code null} the returned value is {@code false}</li>
+     *     <li>if the {@code object} is a {@link Number} the method will return {@code false} only if the number's value is 0</li>
+     *     <li>if the {@link String} representation of the {@code object} is equal irrespective of its casing to "true", the method will
+     *     return {@code true}</li>
+     *     <li>if the {@code object} is a {@link Collection} or a {@link Map}, the method will return {@code true} only if the collection /
+     *     map is not empty</li>
+     *     <li>if the object is an array, the method will return {@code true} only if the array is not empty</li>
+     * </ul>
+     *
+     * @param object the target object
+     * @return the boolean representation of the {@code object} according to the conversion rules
+     */
+    public static boolean toBoolean(Object object) {
+        if (object == null) {
+            return false;
+        }
+
+        if (object instanceof Number) {
+            Number number = (Number) object;
+            return !(number.doubleValue() == 0.0);
+        }
+
+        String s = object.toString().trim();
+        if (EMPTY_STRING.equals(s)) {
+            return false;
+        } else if ("true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) {
+            return Boolean.parseBoolean(s);
+        }
+
+        if (object instanceof Collection) {
+            return ((Collection) object).size() > 0;
+        }
+
+        if (object instanceof Map) {
+            return ((Map) object).size() > 0;
+        }
+
+        if (object instanceof Iterable<?>) {
+            return ((Iterable<?>) object).iterator().hasNext();
+        }
+
+        if (object instanceof Iterator<?>) {
+            return ((Iterator<?>) object).hasNext();
+        }
+
+        return !(object instanceof Object[]) || ((Object[]) object).length > 0;
+    }
+
+    /**
+     * Coerces the passed {@code object} to a numeric value. If the passed value is a {@link String} the conversion rules are those of
+     * {@link NumberUtils#createNumber(String)}.
+     *
+     * @param object the target object
+     * @return the numeric representation if one can be determined or {@code null}
+     * @see NumberUtils#createNumber(String)
+     */
+    public static Number toNumber(Object object) {
+        if (object == null) {
+            return null;
+        }
+        if (object instanceof Number) {
+            return (Number) object;
+        }
+        String stringValue = toString(object);
+        try {
+            return NumberUtils.createNumber(stringValue);
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Converts the passed {@code object} to a {@link String}. The following rules apply:
+     *
+     * <ul>
+     *     <li>if the {@code object} is {@code null} an empty string will be returned</li>
+     *     <li>if the {@code object} is an instance of a {@link String} the object itself will be returned</li>
+     *     <li>if the object is a primitive (see {@link #isPrimitive(Object)}), its {@link String} representation will be returned</li>
+     *     <li>if the object is an {@link Enum} its name will be returned (see {@link Enum#name()})</li>
+     *     <li>otherwise an attempt to convert the object to a {@link Collection} will be made and then the output of
+     *     {@link #collectionToString(Collection)} will be returned</li>
+     * </ul>
+     *
+     * @param object the target object
+     * @return the string representation of the object or an empty string
+     */
+    public static String toString(Object object) {
+        String output = EMPTY_STRING;
+        if (object != null) {
+            if (object instanceof String) {
+                output = (String) object;
+            } else if (isPrimitive(object)) {
+                output = object.toString();
+            } else if (object instanceof Enum) {
+                return ((Enum) object).name();
+            } else {
+                Collection<?> col = toCollection(object);
+                output = collectionToString(col);
+            }
+        }
+        return output;
+    }
+
+    /**
+     * Forces the conversion of the passed {@code object} to a collection, according to the following rules:
+     *
+     * <ul>
+     *     <li>if the {@code object} is {@code null} an empty collection will be returned</li>
+     *     <li>if the {@code object} is an array a list transformation of the array will be returned</li>
+     *     <li>if the {@code object} is a {@link Collection} the object itself will be returned</li>
+     *     <li>if the {@code object} is an instance of a {@link Map} the map's key set will be returned (see {@link Map#keySet()})</li>
+     *     <li>if the {@code object} is an instance of an {@link Enumeration} a list transformation will be returned</li>
+     *     <li>if the {@code object} is an instance of an {@link Iterator} or {@link Iterable} the result of {@link #fromIterator(Iterator)}
+     *     will be returned</li>
+     *     <li>if the {@code object} is an instance of a {@link String} or {@link Number} a {@link Collection} containing only this
+     *     object will be returned</li>
+     *     <li>any other case not covered by the previous rules will result in an empty {@link Collection}</li>
+     * </ul>
+     *
+     * @param object the target object
+     * @return the collection representation of the object
+     */
+    public static Collection<Object> toCollection(Object object) {
+        if (object == null) {
+            return Collections.emptyList();
+        }
+        if (object instanceof Object[]) {
+            return Arrays.asList((Object[]) object);
+        }
+        if (object.getClass().isArray()) {
+            int length = Array.getLength(object);
+            Collection<Object> list = new ArrayList<>();
+            for (int i = 0; i < length; i++) {
+                list.add(Array.get(object, i));
+            }
+            return list;
+        }
+        if (object instanceof Collection) {
+            return (Collection<Object>) object;
+        }
+        if (object instanceof Map) {
+            return ((Map) object).keySet();
+        }
+        if (object instanceof Enumeration) {
+            return Collections.list((Enumeration<Object>) object);
+        }
+        if (object instanceof Iterator) {
+            return fromIterator((Iterator<Object>) object);
+        }
+        if (object instanceof Iterable) {
+            Iterable<Object> iterable = (Iterable<Object>) object;
+            return fromIterator(iterable.iterator());
+        }
+        if (object instanceof String || object instanceof Number) {
+            Collection<Object> list = new ArrayList<>();
+            list.add(object);
+            return list;
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Converts the passed {@code collection} to a comma separated values {@link String} representation.
+     *
+     * @param collection the collection to be converted to CSV
+     * @return the CSV; if the {@code collection} is empty then an empty string will be returned
+     */
+    public static String collectionToString(Collection<?> collection) {
+        if (collection == null) {
+            return EMPTY_STRING;
+        }
+        StringBuilder builder = new StringBuilder();
+        String prefix = EMPTY_STRING;
+        for (Object o : collection) {
+            builder.append(prefix).append(toString(o));
+            prefix = ",";
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Given an {@code iterator}, this method will return a {@link Collection}.
+     *
+     * @param iterator the iterator to be transformed into a {@code collection}
+     * @return a collection with the iterator's elements
+     */
+    public static Collection<Object> fromIterator(Iterator<Object> iterator) {
+        if (iterator == null) {
+            return Collections.EMPTY_LIST;
+        }
+        ArrayList<Object> result = new ArrayList<>();
+        while (iterator.hasNext()) {
+            result.add(iterator.next());
+        }
+        return result;
+    }
+
+    /**
+     * Given an indexable {@code object} (i.e. an array or a collection), this method will return the value available at the {@code
+     * index} position.
+     *
+     * @param object the indexable object
+     * @param index  the index
+     * @return the value stored at the {@code index} or {@code null}
+     */
+    public static Object getIndex(Object object, int index) {
+        if (object == null) {
+            return null;
+        }
+        Class<?> cls = object.getClass();
+        if (cls.isArray() && index >= 0 && index < Array.getLength(object)) {
+            return Array.get(object, index);
+        }
+        Collection collection = toCollection(object);
+        if (collection instanceof List && index >= 0 && index < collection.size()) {
+            return ((List) collection).get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Given an {@code object}, this method will return the value of the public field identified by {@code fieldName}.
+     *
+     * @param object    the target object
+     * @param fieldName the name of the field
+     * @return the value of the field or {@code null} if the field was not found
+     */
+    public static Object getField(Object object, String fieldName) {
+        if (object == null || StringUtils.isEmpty(fieldName)) {
+            return null;
+        }
+        Class<?> cls = object.getClass();
+        if (cls.isArray() && "length".equals(fieldName)) {
+            return Array.getLength(object);
+        }
+        try {
+            Field field = cls.getField(fieldName);
+            return field.get(object);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * Given a bean {@code object}, this method will invoke the public method without parameters identified by {@code methodName} and
+     * return the invocation's result.
+     *
+     * @param object     the target object
+     * @param methodName the name of the public method without parameters to invoke
+     * @return the invocation's result or {@code null} if such a method cannot be found
+     */
+    public static Object invokeBeanMethod(Object object, String methodName) {
+        if (object == null || StringUtils.isEmpty(methodName)) {
+            return null;
+        }
+        Class<?> cls = object.getClass();
+        Method method = findBeanMethod(cls, methodName);
+        if (method != null) {
+            try {
+                method = extractMethodInheritanceChain(cls, method);
+                return method.invoke(object);
+            } catch (Exception e) {
+                LOGGER.error("Cannot access method " + methodName + " on object " + object.toString(), e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Given a bean class and a base method name, this method will try to find a public method without parameters that is named:
+     * <ol>
+     *      <li>{@code baseName}</li>
+     *      <li>get + {@code BaseName}</li>
+     *      <li>is + {@code BaseName}</li>
+     * </ol>
+     *
+     * @param cls      the class into which to search for the method
+     * @param baseName the base method name
+     * @return a method that matches the criteria or {@code null}
+     */
+    public static Method findBeanMethod(Class<?> cls, String baseName) {
+        if (cls == null || StringUtils.isEmpty(baseName)) {
+            return null;
+        }
+        Method[] publicMethods = cls.getMethods();
+        String capitalized = StringUtils.capitalize(baseName);
+        for (Method method : publicMethods) {
+            if (method.getParameterTypes().length == 0) {
+                String methodName = method.getName();
+                if (baseName.equals(methodName) || ("get" + capitalized).equals(methodName) || ("is" + capitalized).equals(methodName)) {
+                    if (isMethodAllowed(method)) {
+                        return method;
+                    }
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if the method is not one of the {@link Object}'s class declared methods, with the exception of
+     * {@link Object#toString()}.
+     *
+     * @param method the method to check
+     * @return {@code true} if the method is not one of the {@link Object}'s class declared methods, with the exception of
+     * {@link Object#toString()}, {@code false} otherwise
+     */
+    public static boolean isMethodAllowed(Method method) {
+        if (method == null) {
+            return false;
+        }
+        Class<?> declaringClass = method.getDeclaringClass();
+        return declaringClass != Object.class || TO_STRING_METHOD.equals(method.getName());
+    }
+
+    private static Method extractMethodInheritanceChain(Class type, Method method) {
+        if (method == null || Modifier.isPublic(type.getModifiers())) {
+            return method;
+        }
+        Class[] interfaces = type.getInterfaces();
+        Method parentMethod;
+        for (Class<?> iface : interfaces) {
+            parentMethod = getClassMethod(iface, method);
+            if (parentMethod != null) {
+                return parentMethod;
+            }
+        }
+        return getClassMethod(type.getSuperclass(), method);
+    }
+
+    private static Method getClassMethod(Class<?> type, Method method) {
+        try {
+            Method parentMethod = type.getMethod(method.getName(), method.getParameterTypes());
+            parentMethod = extractMethodInheritanceChain(parentMethod.getDeclaringClass(), parentMethod);
+            if (parentMethod != null) {
+                return parentMethod;
+            }
+        } catch (NoSuchMethodException e) {
+            // ignore - maybe we don't have access to that method or the method does not belong to the current type
+        }
+        return null;
+    }
+
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/RenderContext.java b/src/main/java/org/apache/sling/scripting/sightly/render/RenderContext.java
new file mode 100644
index 0000000..d57e4c8
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/RenderContext.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.render;
+
+import javax.script.Bindings;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * The {@code RenderContext} defines the context for executing HTL scripts.
+ */
+@ProviderType
+public interface RenderContext {
+
+    /**
+     * Provides the {@link RuntimeObjectModel} that will be used for resolving objects' properties or type conversion / coercion.
+     *
+     * @return the RuntimeObjectModel
+     */
+    RuntimeObjectModel getObjectModel();
+
+    /**
+     * Returns the map of script bindings available to HTL scripts.
+     *
+     * @return the global bindings for a script
+     */
+    Bindings getBindings();
+
+    /**
+     * Call one of the registered {@link org.apache.sling.scripting.sightly.extension.RuntimeExtension}s.
+     *
+     * @param functionName the name under which the extension is registered
+     * @param arguments    the extension's arguments
+     * @return the {@link org.apache.sling.scripting.sightly.extension.RuntimeExtension}'s result
+     */
+    Object call(String functionName, Object... arguments);
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/RenderUnit.java b/src/main/java/org/apache/sling/scripting/sightly/render/RenderUnit.java
new file mode 100644
index 0000000..617565f
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/RenderUnit.java
@@ -0,0 +1,156 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render;
+
+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.scripting.sightly.Record;
+
+/**
+ * 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<>();
+
+    private Map<String, RenderUnit> siblings;
+
+    /**
+     * Render the main script template
+     *
+     * @param out           the {@link PrintWriter} to which the commands are written
+     * @param renderContext the rendering context
+     * @param arguments     the arguments for this unit
+     */
+    public final void render(PrintWriter out, RenderContext renderContext, Bindings arguments) {
+        Bindings globalBindings = renderContext.getBindings();
+        render(out, buildGlobalScope(globalBindings), new CaseInsensitiveBindings(arguments), renderContext);
+    }
+
+    @Override
+    public RenderUnit getProperty(String name) {
+        return subTemplates.get(name.toLowerCase());
+    }
+
+    @Override
+    public Set<String> getPropertyNames() {
+        return subTemplates.keySet();
+    }
+
+    protected abstract void render(PrintWriter out,
+                                   Bindings bindings,
+                                   Bindings arguments,
+                                   RenderContext renderContext);
+
+    @SuppressWarnings({"unused", "unchecked"})
+    protected void callUnit(PrintWriter out, RenderContext renderContext, Object templateObj, Object argsObj) {
+        if (!(templateObj instanceof RenderUnit)) {
+            if (templateObj == null) {
+                throw new RuntimeException("data-sly-call: expression evaluates to null.");
+            }
+            if (renderContext.getObjectModel().isPrimitive(templateObj)) {
+                throw new RuntimeException(
+                        "data-sly-call: primitive \"" + templateObj.toString() + "\" does not represent a HTL template.");
+            } else if (templateObj instanceof String) {
+                throw new RuntimeException(
+                        "data-sly-call: String '" + templateObj.toString() + "' does not represent a HTL template.");
+            }
+            throw new RuntimeException(
+                    "data-sly-call: " + templateObj.getClass().getName() + " does not represent a HTL template.");
+        }
+        RenderUnit unit = (RenderUnit) templateObj;
+        Map<String, Object> argumentsMap = renderContext.getObjectModel().toMap(argsObj);
+        Bindings arguments = new SimpleBindings(Collections.unmodifiableMap(argumentsMap));
+        unit.render(out, renderContext, arguments);
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected FluentMap obj() {
+        return new FluentMap();
+    }
+
+    @SuppressWarnings("unused")
+    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 (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());
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/RuntimeObjectModel.java b/src/main/java/org/apache/sling/scripting/sightly/render/RuntimeObjectModel.java
new file mode 100644
index 0000000..f386634
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/RuntimeObjectModel.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * 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.render;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * The {@code RuntimeObjectModel} provides various utility object inspection &amp; conversion methods that can be applied to runtime
+ * objects when executing HTL scripts.
+ */
+@ProviderType
+public interface RuntimeObjectModel {
+
+    /**
+     * Checks if the provided object represents a primitive data type or not.
+     *
+     * @param obj the target object
+     * @return {@code true} if the {@code target} is a primitive, {@code false} otherwise
+     */
+    boolean isPrimitive(Object obj);
+
+    /**
+     * Checks if an object is a {@link Collection} or is backed by one.
+     *
+     * @param target the target object
+     * @return {@code true} if the {@code target} is a collection or is backed by one, {@code false} otherwise
+     */
+    boolean isCollection(Object target);
+
+    /**
+     * Checks if the provided object represents a number or not.
+     *
+     * @param target the target object
+     * @return {@code true} if the {@code target} is a number, {@code false} otherwise
+     */
+    boolean isNumber(Object target);
+
+    /**
+     * Checks if the provided object represents a date or calendar.
+     *
+     * @param target the target object
+     * @return {@code true} if the {@code target} is a date or calendar, {@code false} otherwise
+     */
+    boolean isDate(Object target);
+
+    /**
+     * Resolve a property of a target object and return its value. The property can
+     * be either an index or a name
+     *
+     * @param target   the target object
+     * @param property the property to be resolved
+     * @return the value of the property
+     */
+    Object resolveProperty(Object target, Object property);
+
+    /**
+     * Convert the given object to a boolean value
+     *
+     * @param object the target object
+     * @return the boolean representation of that object
+     */
+    boolean toBoolean(Object object);
+
+    /**
+     * Coerce the object to a numeric value
+     *
+     * @param object the target object
+     * @return the numeric representation
+     */
+    Number toNumber(Object object);
+
+    /**
+     * Convert the given object to a {@link Date} object
+     *
+     * @param object the target object
+     * @return the date represented by the {@code object}
+     */
+    Date toDate(Object object);
+
+    /**
+     * Convert the given object to a string.
+     *
+     * @param target the target object
+     * @return the string representation of the object
+     */
+    String toString(Object target);
+
+    /**
+     * Force the conversion of the object to a collection
+     *
+     * @param object the target object
+     * @return the collection representation of the object
+     */
+    Collection<Object> toCollection(Object object);
+
+    /**
+     * Force the conversion of the target object to a map
+     *
+     * @param object the target object
+     * @return a map representation of the object. Default is an empty map
+     */
+    Map toMap(Object object);
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/render/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/render/package-info.java
new file mode 100644
index 0000000..3afbfb9
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/render/package-info.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+@Version("3.0.0")
+package org.apache.sling.scripting.sightly.render;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/sightly/use/ProviderOutcome.java b/src/main/java/org/apache/sling/scripting/sightly/use/ProviderOutcome.java
new file mode 100644
index 0000000..83fb379
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/use/ProviderOutcome.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * 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.use;
+
+/**
+ * Result returned by a {@link UseProvider}.
+ */
+public final class ProviderOutcome {
+
+    // a generic failure without a cause returned by #failure()
+    private static final ProviderOutcome GENERIC_FAILURE = new ProviderOutcome(false, null, null);
+
+    // whether this is a success or failure
+    private final boolean success;
+
+    // the result value in case of success (may be null)
+    private final Object result;
+
+    // the reason for failure in case of failure (may be null)
+    private final Throwable cause;
+
+    /**
+     * Creates an outcome instance
+     *
+     * @param success {@code true} to indicate success or {@code false} to indicate failure
+     * @param result  optional result value in case of success, may be {@code null}
+     * @param cause   optional cause in case of failure, may be {@code null}
+     */
+    private ProviderOutcome(boolean success, Object result, Throwable cause) {
+        this.success = success;
+        this.result = result;
+        this.cause = cause;
+    }
+
+    /**
+     * Create a successful outcome
+     *
+     * @param result the result
+     * @return a successful result
+     */
+    public static ProviderOutcome success(Object result) {
+        return new ProviderOutcome(true, result, null);
+    }
+
+    /**
+     * Create a failed outcome without a specific {@link #getCause() cause}. This method must be used for creating outcomes that don't
+     * signal an error but rather the fact that the {@link UseProvider} is not capable of fulfilling the request.
+     *
+     * @return a failed outcome
+     */
+    public static ProviderOutcome failure() {
+        return GENERIC_FAILURE;
+    }
+
+    /**
+     * Create a failed outcome with the given {@link #getCause() cause}. This method must be used when the {@link UseProvider} is
+     * capable of fulfilling the request but an error condition prevents the provider from doing so.
+     *
+     * @param cause The reason for this failure, which may be {@code null}
+     * @return a failed outcome
+     */
+    public static ProviderOutcome failure(Throwable cause) {
+        return new ProviderOutcome(false, null, cause);
+    }
+
+    /**
+     * If the given obj is not {@code null} return a {@link #success(Object) successful outcome}, with the given result. Otherwise, return
+     * {@link #failure()}.
+     *
+     * @param obj the result
+     * @return an outcome based on whether the parameter is null or not
+     */
+    public static ProviderOutcome notNullOrFailure(Object obj) {
+        return (obj == null) ? failure() : success(obj);
+    }
+
+    /**
+     * Check if the outcome has been successful
+     *
+     * @return the outcome success status
+     */
+    public boolean isSuccess() {
+        return success;
+    }
+
+    /**
+     * Check whether the outcome is a failure
+     *
+     * @return the outcome failure status
+     */
+    public boolean isFailure() {
+        return !isSuccess();
+    }
+
+    /**
+     * Get the result in this outcome.
+     *
+     * @return the result of the container
+     * @throws IllegalStateException if the outcome is a failure
+     */
+    public Object getResult() {
+        if (!success) {
+            throw new IllegalStateException("Outcome has not been successful");
+        }
+        return result;
+    }
+
+    /**
+     * Returns the cause for this failure outcome or {@code null} if this outcome is a success or no cause has been defined with the
+     * {@link #failure(Throwable)} method.
+     *
+     * @return the cause for this failure outcome.
+     */
+    public Throwable getCause() {
+        return cause;
+    }
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/use/UseProvider.java b/src/main/java/org/apache/sling/scripting/sightly/use/UseProvider.java
new file mode 100644
index 0000000..14a78ba
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/use/UseProvider.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+
+package org.apache.sling.scripting.sightly.use;
+
+import javax.script.Bindings;
+
+import org.apache.sling.scripting.sightly.render.RenderContext;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * <p>
+ * A {@code UseProvider} instantiates objects for the Use-API.
+ * </p>
+ */
+@ConsumerType
+public interface UseProvider {
+
+    /**
+     * Provide an instance based on the given identifier
+     *
+     * @param identifier    the identifier of the dependency
+     * @param renderContext the current rendering context
+     * @param arguments     specific arguments provided by the use plugin
+     * @return a container with the instance that corresponds to the identifier; if the identifier cannot be
+     * handled by this provider, a failed outcome is returned.
+     */
+    ProviderOutcome provide(String identifier, RenderContext renderContext, Bindings arguments);
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/use/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/use/package-info.java
new file mode 100644
index 0000000..0dfe431
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/use/package-info.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+@Version("1.0.1")
+package org.apache.sling.scripting.sightly.use;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModelTest.java b/src/test/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModelTest.java
new file mode 100644
index 0000000..ab9c07b
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/AbstractRuntimeObjectModelTest.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * 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.render;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.sling.scripting.sightly.Record;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class AbstractRuntimeObjectModelTest {
+
+    private AbstractRuntimeObjectModel runtimeObjectModel = new AbstractRuntimeObjectModel() {};
+
+    @Test
+    public void testResolveProperty() {
+        assertNull(runtimeObjectModel.resolveProperty(null, null));
+        assertNull(runtimeObjectModel.resolveProperty(this, null));
+        assertNull(runtimeObjectModel.resolveProperty(this, ""));
+        assertEquals(0, runtimeObjectModel.resolveProperty(Collections.EMPTY_LIST, "size"));
+        assertNull(runtimeObjectModel.resolveProperty(null, null));
+        int[] ints = new int[] {1, 2, 3};
+        assertEquals(ints.length, runtimeObjectModel.resolveProperty(ints, "length"));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        assertEquals(testArray.length, runtimeObjectModel.resolveProperty(testArray, "length"));
+        assertEquals(2, runtimeObjectModel.resolveProperty(testArray, 1));
+        assertNull(runtimeObjectModel.resolveProperty(testArray, 3));
+        assertNull(runtimeObjectModel.resolveProperty(testArray, -1));
+        List<Integer> testList = Arrays.asList(testArray);
+        assertEquals(2, runtimeObjectModel.resolveProperty(testList, 1));
+        assertNull(runtimeObjectModel.resolveProperty(testList, 3));
+        assertNull(runtimeObjectModel.resolveProperty(testList, -1));
+        Map<String, Integer> map = new HashMap<String, Integer>() {{
+            put("one", 1);
+            put("two", 2);
+        }};
+        assertEquals(1, runtimeObjectModel.resolveProperty(map, "one"));
+        assertNull(runtimeObjectModel.resolveProperty(map, null));
+        assertNull(runtimeObjectModel.resolveProperty(map, ""));
+        Map<Integer, String> stringMap = new HashMap<Integer, String>(){{
+            put(1, "one");
+            put(2, "two");
+        }};
+        assertEquals("one", runtimeObjectModel.resolveProperty(stringMap, 1));
+        assertEquals("two", runtimeObjectModel.resolveProperty(stringMap, 2));
+        Map<String, String> strings = new HashMap<String, String>(){{
+            put("a", "one");
+            put("b", "two");
+        }};
+        Record<String> record = new Record<String>() {
+            @Override
+            public String getProperty(String name) {
+                return strings.get(name);
+            }
+
+            @Override
+            public Set<String> getPropertyNames() {
+                return strings.keySet();
+            }
+        };
+        assertEquals("one", runtimeObjectModel.resolveProperty(record, "a"));
+    }
+
+    @Test
+    public void testToDate() {
+        assertNull(runtimeObjectModel.toDate(null));
+        Date testDate = new Date();
+        assertEquals(testDate, runtimeObjectModel.toDate(testDate));
+        Calendar testCalendar = Calendar.getInstance();
+        assertEquals(testCalendar.getTime(), runtimeObjectModel.toDate(testCalendar));
+    }
+
+    @Test
+    public void testGetPropertyNullChecks() {
+        assertNull(runtimeObjectModel.getProperty(null, null));
+        assertNull(runtimeObjectModel.getProperty(this, null));
+        assertNull(runtimeObjectModel.getProperty(this, ""));
+    }
+
+    @Test
+    public void testIsDate() {
+        assertFalse(runtimeObjectModel.isDate(null));
+        assertTrue(runtimeObjectModel.isDate(new Date()));
+        assertTrue(runtimeObjectModel.isDate(Calendar.getInstance()));
+    }
+
+    @Test
+    public void testIsNumber() {
+        assertFalse(runtimeObjectModel.isNumber(null));
+        assertFalse(runtimeObjectModel.isNumber(""));
+        assertTrue(runtimeObjectModel.isNumber(0));
+        assertTrue(runtimeObjectModel.isNumber(0.5));
+        assertTrue(runtimeObjectModel.isNumber("0"));
+        assertTrue(runtimeObjectModel.isNumber("0.5"));
+    }
+
+    @Test
+    public void testToCollection() {
+        assertTrue(runtimeObjectModel.toCollection(null).isEmpty());
+        Record<String> record = new Record<String>() {
+
+            private Map<String, String> properties = new HashMap<String, String>() {{
+                put("a", "1");
+                put("b", "2");
+            }};
+
+            @Override
+            public String getProperty(String name) {
+                return properties.get(name);
+            }
+
+            @Override
+            public Set<String> getPropertyNames() {
+                return properties.keySet();
+            }
+        };
+        Collection testCollection = runtimeObjectModel.toCollection(record);
+        assertEquals(2, testCollection.size());
+        assertTrue(testCollection.contains("a"));
+        assertTrue(testCollection.contains("b"));
+    }
+
+    @Test
+    public void testToMap() {
+        final Map<String, String> properties = new HashMap<String, String>() {{
+            put("a", "1");
+            put("b", "2");
+        }};
+        assertEquals(properties, runtimeObjectModel.toMap(properties));
+        Record<String> record = new Record<String>() {
+            @Override
+            public String getProperty(String name) {
+                return properties.get(name);
+            }
+
+            @Override
+            public Set<String> getPropertyNames() {
+                return properties.keySet();
+            }
+        };
+        assertEquals(properties, runtimeObjectModel.toMap(record));
+        assertTrue(runtimeObjectModel.toMap(null).isEmpty());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java b/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java
new file mode 100644
index 0000000..28f88bd
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/ObjectModelTest.java
@@ -0,0 +1,245 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sling.scripting.sightly.render.testobjects.Person;
+import org.apache.sling.scripting.sightly.render.testobjects.TestEnum;
+import org.apache.sling.scripting.sightly.render.testobjects.internal.AdultFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class ObjectModelTest {
+
+    @Test
+    public void testToBoolean() {
+        assertFalse(ObjectModel.toBoolean(null));
+        assertFalse(ObjectModel.toBoolean(0));
+        assertTrue(ObjectModel.toBoolean(123456));
+        assertFalse(ObjectModel.toBoolean(""));
+        assertFalse(ObjectModel.toBoolean("FalSe"));
+        assertFalse(ObjectModel.toBoolean("false"));
+        assertFalse(ObjectModel.toBoolean("FALSE"));
+        assertTrue(ObjectModel.toBoolean("true"));
+        assertTrue(ObjectModel.toBoolean("TRUE"));
+        assertTrue(ObjectModel.toBoolean("TrUE"));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        int[] testPrimitiveArray = new int[] {1, 2, 3};
+        List testList = Arrays.asList(testArray);
+        assertTrue(ObjectModel.toBoolean(testArray));
+        assertTrue(ObjectModel.toBoolean(testPrimitiveArray));
+        assertFalse(ObjectModel.toBoolean(new Integer[]{}));
+        assertTrue(ObjectModel.toBoolean(testList));
+        assertFalse(ObjectModel.toBoolean(Collections.emptyList()));
+        Map<String, Integer> map = new HashMap<String, Integer>() {{
+            put("one", 1);
+            put("two", 2);
+        }};
+        assertTrue(ObjectModel.toBoolean(map));
+        assertFalse(ObjectModel.toBoolean(Collections.EMPTY_MAP));
+        assertTrue(ObjectModel.toBoolean(testList.iterator()));
+        assertFalse(ObjectModel.toBoolean(Collections.EMPTY_LIST.iterator()));
+        assertTrue(ObjectModel.toBoolean(new Bag<>(testArray)));
+        assertFalse(ObjectModel.toBoolean(new Bag<>(new Integer[]{})));
+        assertTrue(ObjectModel.toBoolean(new Date()));
+    }
+
+    @Test
+    public void testToNumber() {
+        assertEquals(1, ObjectModel.toNumber(1));
+        assertEquals(1, ObjectModel.toNumber("1"));
+        assertNull(ObjectModel.toNumber(null));
+        assertNull(ObjectModel.toNumber("1-2"));
+    }
+
+    @Test
+    public void testToString() {
+        assertEquals("", ObjectModel.toString(null));
+        assertEquals("1", ObjectModel.toString("1"));
+        assertEquals("1", ObjectModel.toString(1));
+        assertEquals("CONSTANT", ObjectModel.toString(TestEnum.CONSTANT));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        int[] testPrimitiveArray = new int[] {1, 2, 3};
+        List testList = Arrays.asList(testArray);
+        assertEquals("1,2,3", ObjectModel.toString(testList));
+        assertEquals("1,2,3", ObjectModel.toString(testArray));
+        assertEquals("1,2,3", ObjectModel.toString(testPrimitiveArray));
+    }
+
+    @Test
+    public void testToCollection() {
+        assertTrue(ObjectModel.toCollection(null).isEmpty());
+        assertTrue(ObjectModel.toCollection(new StringBuilder()).isEmpty());
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        int[] testPrimitiveArray = new int[]{1, 2, 3};
+        List<Integer> testList = Arrays.asList(testArray);
+        Map<String, Integer> map = new HashMap<String, Integer>() {{
+            put("one", 1);
+            put("two", 2);
+        }};
+        assertEquals(testList, ObjectModel.toCollection(testArray));
+        assertEquals(testList, ObjectModel.toCollection(testPrimitiveArray));
+        assertEquals(testList, ObjectModel.toCollection(testList));
+        assertEquals(map.keySet(), ObjectModel.toCollection(map));
+        Vector<Integer> vector = new Vector<>(testList);
+        assertEquals(testList, ObjectModel.toCollection(vector.elements()));
+        assertEquals(testList, ObjectModel.toCollection(testList.iterator()));
+        assertEquals(testList, ObjectModel.toCollection(new Bag<>(testArray)));
+        String stringObject = "test";
+        Integer numberObject = 1;
+        Collection stringCollection = ObjectModel.toCollection(stringObject);
+        assertTrue(stringCollection.size() == 1 && stringCollection.contains(stringObject));
+        Collection numberCollection = ObjectModel.toCollection(numberObject);
+        assertTrue(numberCollection.size() == 1 && numberCollection.contains(numberObject));
+    }
+
+    @Test
+    public void testCollectionToString() {
+        assertEquals("", ObjectModel.collectionToString(null));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        List testList = Arrays.asList(testArray);
+        assertEquals("1,2,3", ObjectModel.collectionToString(testList));
+    }
+
+    @Test
+    public void testFromIterator() {
+        assertTrue(ObjectModel.fromIterator(null).isEmpty());
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        List testList = Arrays.asList(testArray);
+        assertEquals(testList, ObjectModel.fromIterator(testList.iterator()));
+    }
+
+    @Test
+    public void testResolveProperty() {
+        assertNull(ObjectModel.resolveProperty(null, 0));
+        assertNull(ObjectModel.resolveProperty(this, null));
+        assertNull(ObjectModel.resolveProperty(null, null));
+        assertEquals(0, ObjectModel.resolveProperty(Collections.EMPTY_LIST, "size"));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        assertEquals(2, ObjectModel.resolveProperty(testArray, 1));
+        assertNull(ObjectModel.resolveProperty(testArray, 3));
+        assertNull(ObjectModel.resolveProperty(testArray, -1));
+        List<Integer> testList = Arrays.asList(testArray);
+        assertEquals(2, ObjectModel.resolveProperty(testList, 1));
+        assertNull(ObjectModel.resolveProperty(testList, 3));
+        assertNull(ObjectModel.resolveProperty(testList, -1));
+        Map<String, Integer> map = new HashMap<String, Integer>() {{
+            put("one", 1);
+            put("two", 2);
+        }};
+        assertEquals(1, ObjectModel.resolveProperty(map, "one"));
+        assertNull(ObjectModel.resolveProperty(map, null));
+        assertNull(ObjectModel.resolveProperty(map, ""));
+        Map<Integer, String> stringMap = new HashMap<Integer, String>(){{
+            put(1, "one");
+            put(2, "two");
+        }};
+        assertEquals("one", ObjectModel.resolveProperty(stringMap, 1));
+        assertEquals("two", ObjectModel.resolveProperty(stringMap, 2));
+        Person johnDoe = AdultFactory.createAdult("John", "Doe");
+        assertEquals("Expected to be able to access public static final constants.", 1l, ObjectModel.resolveProperty(johnDoe, "CONSTANT"));
+        assertNull("Did not expect to be able to access public fields from package protected classes.", ObjectModel.resolveProperty(johnDoe,
+                "TODAY"));
+        assertEquals("Expected to be able to access an array's length property.", 3, ObjectModel.resolveProperty(testArray, "length"));
+        assertNotNull("Expected not null result for invocation of interface method on implementation class.",
+                ObjectModel.resolveProperty(johnDoe, "lastName"));
+        assertNull("Expected null result for public method available on implementation but not exposed by interface.", ObjectModel
+                .resolveProperty(johnDoe, "fullName"));
+        assertNull("Expected null result for inexistent method.", ObjectModel.resolveProperty(johnDoe, "nomethod"));
+    }
+
+    @Test
+    public void testGetIndex() {
+        assertNull(ObjectModel.getIndex(null, 0));
+        Integer[] testArray = new Integer[] {1, 2, 3};
+        assertEquals(2, ObjectModel.getIndex(testArray, 1));
+        assertNull(ObjectModel.getIndex(testArray, 3));
+        assertNull(ObjectModel.getIndex(testArray, -1));
+        List<Integer> testList = Arrays.asList(testArray);
+        assertEquals(2, ObjectModel.getIndex(testList, 1));
+        assertNull(ObjectModel.getIndex(testList, 3));
+        assertNull(ObjectModel.getIndex(testList, -1));
+        Map<Integer, String> stringMap = new HashMap<Integer, String>(){{
+            put(1, "one");
+            put(2, "two");
+        }};
+        assertNull(ObjectModel.getIndex(stringMap, 1));
+        assertNull(ObjectModel.getIndex(stringMap, 2));
+    }
+
+    @Test
+    public void testClassBasedMethodsForNulls() {
+        assertNull(ObjectModel.getField(null, null));
+        assertNull(ObjectModel.getField("", null));
+        assertNull(ObjectModel.getField(this, ""));
+        assertNull(ObjectModel.findBeanMethod(null, null));
+        assertNull(ObjectModel.findBeanMethod(this.getClass(), null));
+        assertNull(ObjectModel.findBeanMethod(this.getClass(), ""));
+        assertNull(ObjectModel.invokeBeanMethod(null, null));
+        assertNull(ObjectModel.invokeBeanMethod(this, null));
+        assertNull(ObjectModel.invokeBeanMethod(this, ""));
+    }
+
+
+    private class Bag<T> implements Iterable<T> {
+
+        private T[] backingArray;
+
+        public Bag(T[] array) {
+            this.backingArray = array;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return new Iterator<T>() {
+
+                int index = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return index < backingArray.length;
+                }
+
+                @Override
+                public T next() {
+                    return backingArray[index++];
+                }
+
+                @Override
+                public void remove() {
+
+                }
+            };
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/Person.java b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/Person.java
new file mode 100644
index 0000000..fc0c3f8
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/Person.java
@@ -0,0 +1,29 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render.testobjects;
+
+public interface Person {
+
+    long CONSTANT = 1;
+
+    String getFirstName();
+
+    String getLastName();
+    
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/TestEnum.java b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/TestEnum.java
new file mode 100644
index 0000000..49c4072
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/TestEnum.java
@@ -0,0 +1,25 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render.testobjects;
+
+public enum TestEnum {
+
+    CONSTANT
+
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AbstractPerson.java b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AbstractPerson.java
new file mode 100644
index 0000000..121cd8e
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AbstractPerson.java
@@ -0,0 +1,42 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render.testobjects.internal;
+
+import org.apache.sling.scripting.sightly.render.testobjects.Person;
+
+abstract class AbstractPerson implements Person {
+
+    private String firstName;
+    private String lastName;
+
+    public AbstractPerson(String firstName, String lastName) {
+        this.firstName = firstName;
+        this.lastName = lastName;
+    }
+
+    @Override
+    public String getFirstName() {
+        return firstName;
+    }
+
+    @Override
+    public String getLastName() {
+        return lastName;
+    }
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/Adult.java b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/Adult.java
new file mode 100644
index 0000000..10df9b0
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/Adult.java
@@ -0,0 +1,32 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render.testobjects.internal;
+
+class Adult extends AbstractPerson {
+
+    public static final long TODAY = System.currentTimeMillis();
+
+    Adult(String firstName, String lastName) {
+        super(firstName, lastName);
+    }
+
+    public String getFullName() {
+        return getFirstName() + ", " + getLastName();
+    }
+}
diff --git a/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AdultFactory.java b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AdultFactory.java
new file mode 100644
index 0000000..b2f879b
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/render/testobjects/internal/AdultFactory.java
@@ -0,0 +1,26 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.render.testobjects.internal;
+
+public class AdultFactory {
+
+    public static Adult createAdult(String firstName, String lastName) {
+        return new Adult(firstName, lastName);
+    }
+}


[sling-org-apache-sling-scripting-sightly-runtime] 07/11: [maven-release-plugin] prepare release org.apache.sling.scripting.sightly.runtime-1.0.0-1.4.0

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit f712f4a86ba836068598abd620ad8f879d7443b0
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Wed Oct 31 17:35:31 2018 +0100

    [maven-release-plugin] prepare release org.apache.sling.scripting.sightly.runtime-1.0.0-1.4.0
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5c9e46f..549cc8d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
         The versioning scheme defined here corresponds to SLING-7406 (<module_version>-<htl_specification_version>). Take care when
         releasing to only increase the first part, unless the module provides support for a newer version of the HTL specification.
     -->
-    <version>1.0.0-1.4.0-SNAPSHOT</version>
+    <version>1.0.0-1.4.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Scripting HTL Runtime</name>
@@ -48,7 +48,7 @@
         <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</connection>
         <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-scripting-sightly-runtime.git</url>
-      <tag>HEAD</tag>
+      <tag>org.apache.sling.scripting.sightly.runtime-1.0.0-1.4.0</tag>
   </scm>
 
     <properties>


[sling-org-apache-sling-scripting-sightly-runtime] 02/11: trivial: corrected link to htl java compiler

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit d735eb7d516abf99da7015e0155da81b60f8267f
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Thu Oct 18 13:53:22 2018 +0200

    trivial: corrected link to htl java compiler
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 9fa5bc8..0efd350 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,4 @@
 
 This module is part of the [Apache Sling](https://sling.apache.org) project.
 
-The Apache Sling Scripting HTL Runtime provides support for executing HTL Java compiled units produced by the [`org.apache.sling.scripting.sightly.compiler.java module`](https://github.com/apache/sling-org-apache-sling-scripting-sightly-runtime).
+The Apache Sling Scripting HTL Runtime provides support for executing HTL Java compiled units produced by the [`org.apache.sling.scripting.sightly.compiler.java module`](https://github.com/apache/sling-org-apache-sling-scripting-sightly-compiler-java).


[sling-org-apache-sling-scripting-sightly-runtime] 03/11: trivial: updated badges

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 1dab5c3423e8908a25706baa1d4224e71ba074ef
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Thu Oct 18 14:06:15 2018 +0200

    trivial: updated badges
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 0efd350..181d563 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 [<img src="http://sling.apache.org/res/logos/sling.png"/>](http://sling.apache.org)
 
- [![Build Status](https://builds.apache.org/buildStatus/icon?job=sling-org-apache-sling-scripting-sightly-runtime-1.8)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8.svg)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8/test_resu [...]
+ [![Build Status](https://builds.apache.org/buildStatus/icon?job=sling-org-apache-sling-scripting-sightly-runtime-1.8)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8) [![Test Status](https://img.shields.io/jenkins/t/https/builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8.svg)](https://builds.apache.org/view/S-Z/view/Sling/job/sling-org-apache-sling-scripting-sightly-runtime-1.8/test_resu [...]
 
 # Apache Sling Scripting HTL Runtime
 


[sling-org-apache-sling-scripting-sightly-runtime] 09/11: trivial: updated findbugs

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 3c5f914fdb6304d8b9986ddd5a488de80d1cd306
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Wed Jan 9 12:44:20 2019 +0200

    trivial: updated findbugs
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 7193559..8be06d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,7 +90,7 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>findbugs-maven-plugin</artifactId>
-                <version>3.0.3</version>
+                <version>3.0.5</version>
                 <configuration>
                     <effort>Max</effort>
                     <xmlOutput>true</xmlOutput>


[sling-org-apache-sling-scripting-sightly-runtime] 06/11: SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 081b800d54415d59ce7f846a7688e23b1001a602
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Wed Oct 31 17:34:35 2018 +0100

    SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
    
    * removed reference to HTL compiler
---
 .../org/apache/sling/scripting/sightly/extension/RuntimeExtension.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java b/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java
index 1cfaa0c..0348e5f 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/extension/RuntimeExtension.java
@@ -99,7 +99,7 @@ public interface RuntimeExtension {
      * </p>
      * <ol>
      *     <li>the original string to escape / filter</li>
-     *     <li>the context to be applied - see {@link org.apache.sling.scripting.sightly.compiler.expression.MarkupContext}</li>
+     *     <li>the context to be applied</li>
      * </ol>
      * <p>
      *     For more details check https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/1.2/SPECIFICATION.md#121-display-context.


[sling-org-apache-sling-scripting-sightly-runtime] 04/11: SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-8228
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-runtime.git

commit 5caa79c78fb9b81a0b6805ce23b6ba255447cd6b
Author: Radu Cotescu <co...@adobe.com>
AuthorDate: Wed Oct 31 17:11:14 2018 +0100

    SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
    
    * updated dependencies
---
 pom.xml | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 0b404db..5c9e46f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>30</version>
+        <version>34</version>
         <relativePath />
     </parent>
 
@@ -160,6 +160,13 @@
     <!-- ======================================================================= -->
     <dependencies>
 
+        <!-- OSGi -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.annotation.versioning</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
         <!-- Logging -->
         <dependency>
             <groupId>org.slf4j</groupId>