You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2017/03/24 15:09:47 UTC

svn commit: r1788464 [1/2] - in /sling/trunk/contrib/scripting/esx: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/scripting/ src/main/java/org/apache/sling/s...

Author: bdelacretaz
Date: Fri Mar 24 15:09:46 2017
New Revision: 1788464

URL: http://svn.apache.org/viewvc?rev=1788464&view=rev
Log:
SLING-6680 - new esx/Nashorn script engine, contributed by Senol Tas, thanks!

Added:
    sling/trunk/contrib/scripting/esx/   (with props)
    sling/trunk/contrib/scripting/esx/README.md
    sling/trunk/contrib/scripting/esx/pom.xml
    sling/trunk/contrib/scripting/esx/src/
    sling/trunk/contrib/scripting/esx/src/main/
    sling/trunk/contrib/scripting/esx/src/main/java/
    sling/trunk/contrib/scripting/esx/src/main/java/org/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngine.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngineFactory.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Module.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ModuleScript.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Require.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ScriptModuleCache.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/globals/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/ConsoleLog.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResource.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResourceAdapterFactory.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/ScriptModuleCache.java
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/
    sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/RepositoryModuleCache.java
    sling/trunk/contrib/scripting/esx/src/main/resources/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/README.md
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/content.html
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/layout.html
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/pathinfo/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/pathinfo/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/page.esx
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/templates/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/templates/listing.html
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/templates/mobile.html
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/post/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/post/post.esx
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/post/templates/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/post/templates/detail.html
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/content/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/content/demo.xml
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/esx_modules/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/package.json
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/fs/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/fs/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/path/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/path/index.js
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/url/
    sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/esx_modules/url/index.js
    sling/trunk/contrib/scripting/esx/src/test/
    sling/trunk/contrib/scripting/esx/src/test/java/

Propchange: sling/trunk/contrib/scripting/esx/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Mar 24 15:09:46 2017
@@ -0,0 +1,5 @@
+target
+.settings
+.classpath
+.project
+node_modules

Added: sling/trunk/contrib/scripting/esx/README.md
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/README.md?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/README.md (added)
+++ sling/trunk/contrib/scripting/esx/README.md Fri Mar 24 15:09:46 2017
@@ -0,0 +1,141 @@
+<!--
+/*
+ * 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 Sling ESX Scripting Engine
+
+A Node JS (like) module loader for Apache Sling.
+
+## Description
+This module implements a Nashorn Apache Sling Script Engine for the "esx" extension.
+
+It requires a function named `render` in the `esx` script that processes the request.
+
+To activate this script engine you must first **enable Nashorn support** in the 
+`sling.properties` file of your Sling instance:
+
+```
+jre-1.8=jdk.nashorn.api.scripting;version\="0.0.0.1_008_JavaSE"
+```
+**attention**
+> currently this implementation only works with java version "1.8.0_92" and higher
+
+Once the bundle is active, you can try the engine with this minimal (and not very interesting) example:
+
+First create a node with some content:
+
+    curl -u admin:admin \
+      -F"sling:resourceType=foo" \
+	  -Ftitle="Hello ESX" \
+	  -Ftext="Here's some example text" \
+	  http://localhost:8080/apps/foo
+	  
+Then create an ESX script to render it:
+
+    $ cat << EOF > /tmp/foo.esx
+    var foo = {
+      render: function () {
+        var output  = "<h1>" + currentNode.properties.title + "</h1>";             
+        output += currentNode.properties.text;
+        return output;     
+      }
+    }  
+    module.exports = foo;
+    EOF
+	
+    $ curl -u admin:admin -T /tmp/foo.esx http://localhost:8080/apps/foo/foo.esx
+   
+    $ curl http://localhost:8080/apps/foo.html
+    <h1>Hello ESX</h1>Here's some example text
+  	  
+
+An ESX file is a regular java script file. 
+
+The NodeJS module resolution (https://nodejs.org/api/modules.html) is implemented to give access to the
+rich collection of Node modules.
+
+There's currently no priority handling of global modules.
+
+The engine searches for scripts in the following order, if the regular module resolution does not find a module:
+        - /apps/esx/node_modules
+        - /apps/esx/esx_modules
+        - /libs/esx/node_modules
+        - /libs/esx/esx_modules
+
+Additionally, ESX will try to resolve the folder *esx_modules* prior to *node_modules*.
+
+### Special Loaders
+Require Extensions are deprecated (see https://nodejs.org/api/globals.html#globals_require_extensions), therefore we have not implemented/used the extension loaders api and .bin extension cannot be used.
+
+We have borrowed the requirejs loader plugin syntax instead (see http://requirejs.org/docs/api.html#text). Additionally to the standard JS loader following two loaders are existing:
+
+- text (e.g. ```require("text!./templates/header.html"))```)
+  - will return a javascript native string containing the content of the file
+- resource  (e.g. ```require("resource!./content/blogposts)```)
+  following will be exposed:
+  - properties (resource valuemap)
+  - path (jcr path)  
+  - simpleResource (has getChildren method with resolved simpleresoruce in an array)
+  - array with list of children (simpleResource)
+
+- json loader  (e.g. ```require("./dict/en.json```)
+  - the json as a whole will be exported as a javascript Object
+
+## Installing Demo Application
+Currently the demo application is bundles with the engine bundle. To install the engine with the demo application, follow this steps:
+- switch to directory src/main/resources/libs/esx/demo
+- run: npm install
+- go back to package root directory
+- run mvn clean install sling:install´
+
+open http://localhost:8080/libs/esx/demo/content/demo.html
+
+### Writing a module
+You can actually follow the NODE JS description on https://nodejs.org/api/modules.html for more detailed explanation.
+
+A module has access to following variables:
+- __filename
+- __dirname
+- console (console.log is a log4j logger registered to the resolved module path and is not a 1:1 console.log implementation for now)
+- properties (valuemap)
+- simpleResource
+- currentNode
+ - currentNode.path
+ - currentNode.resource
+ - currentNode.properties
+- sling (SlingScriptHelper)
+
+
+# Example
+## Caluclator Module
+Path: /apps/demo/components/test/helper/calculator/index.js
+```javascript
+function calculate(a, b) {
+  return a + b;
+}
+exports.math = calculate;
+```
+
+## Test components
+Path: /apps/demo/components/test/test.esx
+```javascript
+var calculator = require("./helper/calculator");
+
+exports.render = function () {
+  return calculator.math(2,2);
+}
+```
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/pom.xml?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/pom.xml (added)
+++ sling/trunk/contrib/scripting/esx/pom.xml Fri Mar 24 15:09:46 2017
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  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>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>29</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.apache.sling</groupId>
+    <artifactId>org.apache.sling.scripting.esx</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <name>Apache Sling Scripting ESX</name>
+    <description>Support NodeJS like scripting and module resolution</description>
+
+    <build>
+        <resources>
+            <!-- filter meta information to get some properties into the files -->
+            <resource>
+                <directory>${basedir}/src/main/resources</directory>
+                <targetPath>resources</targetPath>
+            </resource>
+        </resources>        
+        <plugins>           
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                    <configuration>
+                        <ignores>
+                            <ignore>jdk.nashorn.*</ignore>
+                        </ignores>
+                    </configuration>
+           </plugin>
+           <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>src/main/resources/libs/esx/demo/node_modules/**</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <version>1.21.0</version>
+                <executions>
+                    <execution>
+                        <id>generate-scr-descriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>            
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>3.0.0</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.sling.scripting.esx.*
+                        </Export-Package>
+                        <Private-Package></Private-Package>      
+                        <Include-Resource>{maven-resources}</Include-Resource>   
+                        <Sling-Initial-Content>
+                            resources/libs/esx;overwrite:=true;path:=/libs/esx;ignoreImportProviders:=json
+                        </Sling-Initial-Content>               
+                    </instructions>                                      
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.3</version>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                    <showDeprecation>false</showDeprecation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>4.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>4.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.event</artifactId>
+            <version>4.2.0</version>
+        </dependency>        
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.0.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.9.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.api</artifactId>
+            <version>2.1.8</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.19-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>1.9.12</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.jackrabbit.server</artifactId>
+            <version>2.1.0</version>
+            <type>jar</type>
+        </dependency>
+    </dependencies>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <sling.java.version>8</sling.java.version>
+    </properties>
+    <profiles>
+        <profile>
+            <id>autoInstallBundle</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.sling</groupId>
+                        <artifactId>maven-sling-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>install-bundle</id>
+                                <goals>
+                                    <goal>install</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>                    
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngine.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngine.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngine.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngine.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,73 @@
+/*
+ * 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.esx;
+
+import java.io.IOException;
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EsxScriptEngine extends AbstractSlingScriptEngine {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    public EsxScriptEngine(EsxScriptEngineFactory scriptEngineFactory) {
+        super(scriptEngineFactory);
+    }
+
+    @Override
+    public Object eval(Reader reader, ScriptContext context) throws ScriptException {
+        log.debug("starting to eval ESX Script");
+        Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
+        SlingScriptHelper scriptHelper = (SlingScriptHelper) bindings.get("sling");
+        Resource scriptResource = scriptHelper.getScript().getScriptResource();
+        Resource resource = scriptHelper.getRequest().getResource();
+
+        ModuleScript moduleScript = new ModuleScript(ModuleScript.JS_FILE, scriptResource);
+        //public Module (EsxScriptEngineFactory factory, Resource resource, ModuleScript moduleScript, String id, Module parent, SlingScriptHelper scriptHelper) throws ScriptException {
+
+        Module module = new Module(
+                (EsxScriptEngineFactory) getFactory(),
+                resource, moduleScript, scriptResource.getPath(), null,
+                scriptHelper,
+                Module.LOADER_JS
+        );
+        
+        try {
+            Object moduleResults = module.require(scriptResource.getPath());
+            
+            String result = ((EsxScriptEngineFactory) getFactory()).getNashornEngine().eval(
+                    "if(exports.render && typeof exports.render === 'function') { exports.render('test'); }"
+                  + " else if(typeof exports === 'class') { new exports().render('function') } else {"
+                            + "'You need to define either a render function or export an object with a render method'; }", module).toString();
+            
+            context.getWriter().write(result);
+            
+        } catch (IOException ex) {
+            throw new ScriptException(ex);
+        }        
+               
+        return null;
+    }
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngineFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngineFactory.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngineFactory.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/EsxScriptEngineFactory.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,101 @@
+/*
+ * 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.esx;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@Component(label = "ESX Scripting Engine Factory", description = "", metatype = true)
+@Service
+@Properties({
+    @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation")
+    ,
+        @Property(name = Constants.SERVICE_DESCRIPTION, value = "Scripting Engine for Ecmas Script using Node JS like module loader")
+    ,
+        @Property(name = "compatible.javax.script.name", value = "esx")
+})
+public class EsxScriptEngineFactory extends AbstractScriptEngineFactory {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private ScriptEngine nashornScriptEngine;
+    
+    @Reference
+    ScriptModuleCache moduleCache;
+
+    public EsxScriptEngineFactory() {
+        setNames("esx", "ESX");
+        setExtensions("esx", "ESX");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "ESX";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new EsxScriptEngine(this);
+    }
+
+    /**
+     * 
+     * @return 
+     */
+    public ScriptModuleCache getModuleCache() {
+        return moduleCache;        
+    }
+    
+    /**
+     *
+     * @return
+     */
+    public ScriptEngine getNashornEngine() {
+        return nashornScriptEngine;
+    }
+
+    @Deactivate
+    private void deactivate() {
+        log.debug("Deactivating Engine");
+    }
+
+    @Activate
+    protected void activate(ComponentContext context) {
+        log.debug("Starting Engine");
+        // create one script engine
+        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+        this.nashornScriptEngine = factory.getScriptEngine();
+        log.debug("Engine started");
+    }
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Module.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Module.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Module.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Module.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,657 @@
+/*
+ * 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.esx;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.scripting.esx.plugins.ConsoleLog;
+import org.apache.sling.scripting.esx.plugins.SimpleResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Module extends SimpleBindings implements Require {
+
+    public static final String CONTEXT_FIELD_SLING = "sling";
+    public static final String CONTEXT_FIELD_PARENT = "parent";
+    public static final String CONTEXT_FIELD_ID = "id";
+    public static final String CONTEXT_FIELD_MAIN = "main";
+    public static final String CONTEXT_FIELD_IS_LOADED = "isLoaded";
+    public static final String CONTEXT_FIELD_FILENAME = "filename";
+    public static final String CONTEXT_FIELD_RESOURCE = "resource";
+    public static final String CONTEXT_FIELD_CHILDREN = "children";
+    public static final String CONTEXT_FIELD_MODULE_RESOURCE = "moduleResource";
+    public static final String CONTEXT_FIELD_EXPORTS = "exports";
+    public static final String CONTEXT_FIELD_CONSOLE = "console";
+    public static final String LOADER_TEXT = "text!";
+    public static final String LOADER_RESOURCE = "resource!";
+    public static final String LOADER_JS = "js!";
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private SlingScriptHelper scriptHelper;
+    private final EsxScriptEngineFactory factory;
+    private ModuleScript moduleScript;
+    private boolean isLoaded = false;
+    private final List<Module> children = new ArrayList();
+    private String loader;
+
+    /**
+     *
+     * @param factory
+     * @param resource
+     * @param moduleScript
+     * @param id
+     * @param parent
+     * @param scriptHelper
+     * @throws ScriptException
+     */
+    public Module(EsxScriptEngineFactory factory, Resource resource,
+            ModuleScript moduleScript, String id, Module parent,
+            SlingScriptHelper scriptHelper,
+            String loader) throws ScriptException {
+        this.factory = factory;
+        this.scriptHelper = scriptHelper;
+        this.moduleScript = moduleScript;
+        this.loader = loader;
+
+        put(CONTEXT_FIELD_PARENT, parent);
+        put(CONTEXT_FIELD_SLING, scriptHelper);
+
+        put(CONTEXT_FIELD_ID, id);
+        put(CONTEXT_FIELD_MAIN, (parent == null) ? this : (Module) parent.get(CONTEXT_FIELD_PARENT));
+        put(CONTEXT_FIELD_IS_LOADED, isLoaded);
+        put(CONTEXT_FIELD_FILENAME, moduleScript.getResource().getPath());
+        put(CONTEXT_FIELD_RESOURCE, resource);
+        put(CONTEXT_FIELD_CHILDREN, children);
+        put(CONTEXT_FIELD_MODULE_RESOURCE, moduleScript.getResource());
+
+        put(CONTEXT_FIELD_EXPORTS, ((JSObject) factory.getNashornEngine().eval("Object")).newObject());
+
+        log.debug("this is the main script: " + (get(CONTEXT_FIELD_MAIN) == this));
+
+        put(CONTEXT_FIELD_CONSOLE, new ConsoleLog((String) get(CONTEXT_FIELD_FILENAME)));
+    }
+
+    /**
+     *
+     * @param source
+     * @return
+     * @throws ScriptException
+     */
+    private ScriptObjectMirror decoreateScript(String source)
+            throws ScriptException {
+
+        String polyfill = "";
+
+        if ("polyfill".equals(get(CONTEXT_FIELD_ID))) {
+            //polyfill = "require('/libs/esx/esx_modules/polyfills/index.js')(this).bind(this)";
+        }
+        source = "//@sourceURL=" + (String) get("filename") + "\n"
+                + "(function (exports, require, module, __filename,"
+                + " __dirname, currentNode, console, properties, sling, simpleResource) { "
+                + "var window = this;"
+                + "var global = this;"
+                + source
+                + "})";
+
+        // use load + filenane for older JDK versions, @sourceURL is working for latest JDK version
+        source = "load( { name : \"" + get("filename") + "\","
+                + " script: \""
+                + StringEscapeUtils.escapeEcmaScript(source)
+                + "\" } )";
+
+        ScriptObjectMirror function = null;
+        try {
+            function = (ScriptObjectMirror) factory.getNashornEngine().eval(
+                    source
+            );
+            if (function == null) {
+                log.error("Function is null !");
+            }
+        } catch (ScriptException ex) {
+            // todo: better handling in future
+            throw ex;
+        }
+        return function;
+    }
+
+    /**
+     *
+     * @return @throws ScriptException
+     */
+    public Object runScript() throws ScriptException {
+        log.debug("run script with id {}", get("id"));
+        ScriptObjectMirror function = factory.getModuleCache().get((String) get(CONTEXT_FIELD_FILENAME));
+
+        Resource moduleResource = (Resource) get(CONTEXT_FIELD_MODULE_RESOURCE);
+        Resource resource = (Resource) get(CONTEXT_FIELD_RESOURCE);
+
+        if (function == null) {
+            if (moduleScript.isJsFile()) {
+                function = decoreateScript(
+                        //readScript(moduleResource)//  
+                        readScript(moduleResource)
+                );
+            }
+
+            if (moduleScript.isJsonFile()) {
+                String jsonfile = readScript(moduleResource);
+                function = decoreateScript(
+                        "module.exports = " + jsonfile
+                );
+            }
+
+            if (moduleScript.isResourceFile()) {
+                Iterator<Resource> resChildren = moduleResource.listChildren();
+                ArrayList<Resource> children = new ArrayList<Resource>();
+                resChildren.forEachRemaining(children::add);
+
+                put("children", children);
+
+                ValueMap map = moduleResource.adaptTo(ValueMap.class);
+
+                JSONObject values = new JSONObject(map);
+
+                String jsonprop = values.toString();
+
+                SimpleResource simpleResource = moduleResource.adaptTo(SimpleResource.class);
+                put("simpleResource", simpleResource);
+
+                String source = "exports.properties =  " + jsonprop + ";"
+                        + "exports.path = currentNode.resource.path;"
+                        + "exports.simpleResource = this.simpleResource;"
+                        + "exports.children = this.children;";
+
+                function = decoreateScript(source);
+            }
+            if (!moduleScript.isResourceFile()) {
+                factory.getModuleCache().put(moduleScript.getResource().getPath(), function);
+            }
+        } else {
+            log.debug("module " + get(CONTEXT_FIELD_ID) + " received from cache");
+        }
+
+        if (moduleScript.isTextFile()) {
+            log.debug("is textfile loaidng file");
+            String source = StringEscapeUtils.escapeEcmaScript(readScript(moduleResource));
+            log.debug("sourcE: ");
+            source = "module.exports = \"" + source + "\";";
+            log.debug(source);
+            function = decoreateScript(source);
+            factory.getModuleCache().put(moduleScript.getResource().getPath(), function);
+        }
+        JSObject process = (JSObject) factory.getNashornEngine().eval("Object");
+        process.setMember("domain", log);
+
+        if (function != null) {
+            SimpleBindings currentNode = new SimpleBindings();
+            if (resource != null) {
+                currentNode.put("resource", resource);
+                currentNode.put("properties", resource.adaptTo(ValueMap.class));
+            } else {
+                log.debug("module id {} resource is null", get(CONTEXT_FIELD_ID));
+            }
+
+            function.call(this, get(CONTEXT_FIELD_EXPORTS), (Require) this::require, this, get(CONTEXT_FIELD_FILENAME),
+                    ((Resource) get(CONTEXT_FIELD_MODULE_RESOURCE)).getParent().getPath(), currentNode,
+                    (ConsoleLog) get(CONTEXT_FIELD_CONSOLE),
+                    null,
+                    (SlingScriptHelper) get(CONTEXT_FIELD_SLING),
+                    resource.adaptTo(SimpleResource.class)
+            );
+
+        } else {
+            log.warn("function not called because it is null");
+        }
+
+        put(CONTEXT_FIELD_EXPORTS, get(CONTEXT_FIELD_EXPORTS));
+
+        return get(CONTEXT_FIELD_EXPORTS);
+    }
+
+    /**
+     *
+     * @param script
+     * @return
+     */
+    public String readScript(Resource script) throws ScriptException {
+        InputStream is = script.getChild("jcr:content").adaptTo(InputStream.class);
+        BufferedReader esxScript = new BufferedReader(new InputStreamReader(is));
+        StringBuilder buffer = new StringBuilder();
+        String temp;
+        try {
+            while ((temp = esxScript.readLine()) != null) {
+                buffer.append(temp).append("\r\n");
+            }
+            return buffer.toString();
+        } catch (IOException ioex) {
+            throw new ScriptException(ioex);
+        }
+    }
+
+    /**
+     *
+     * @param path
+     * @return
+     */
+    private boolean isLocalModule(String path) {
+        return (path.startsWith("./") == true
+                || path.startsWith("/") == true
+                || path.startsWith("../") == true);
+    }
+
+    /**
+     *
+     * @param path
+     * @param basePath
+     * @return
+     */
+    private String normalizePath(String path, String basePath) {
+        path = StringUtils.removeStart(cleanModulePathFromLoaders(path), basePath);
+        return ResourceUtil.normalize(basePath + "/" + path);
+    }
+
+    /**
+     * not implemented yet
+     *
+     * @param path
+     * @return
+     */
+    private boolean isGlobalModule(String path) {
+        return false;
+    }
+
+    /**
+     *
+     * @param file
+     * @param type
+     * @return
+     * @throws ScriptException
+     */
+    private ModuleScript createModuleScript(Resource file, int type) throws ScriptException {
+        log.debug("module created. " + file.getPath());
+        Node currentNode = file.adaptTo(Node.class);
+        if (currentNode != null) {
+            log.debug("currentNode !) null = " + (currentNode != null));
+            try {
+                boolean isFile = currentNode.isNodeType(NodeType.NT_FILE);
+                log.debug("isFile: " + isFile);
+                if (isFile) {
+                    return new ModuleScript(type, file);
+                }
+                log.debug("not a file " + currentNode.getMixinNodeTypes().toString());
+            } catch (RepositoryException ex) {
+                throw new ScriptException("cannot load file " + file.getPath());
+            }
+        }
+        return null;
+
+    }
+
+    /**
+     *
+     * @param module
+     * @param path
+     * @param currentResource
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadAsFile(String module, String path,
+            Resource currentResource, String loader) throws ScriptException {
+        int type = ModuleScript.JS_FILE;
+
+        // this is need to be refactored, it is this way because I followed the
+        // node.js extension handling at first but switched over to requirejs
+        // loader notation        
+        Resource file = currentResource.getResourceResolver().getResource(path);
+
+        // require.extensions is deprecated, however to implement this might 
+        // be a good way to handle .resource loading or to implemend loader 
+        // like in requirejs e.g. similar to https://github.com/requirejs/text
+        // "text!some/module.html" 
+        // or require("resource!/content/homepage/jcr:content")
+        if (LOADER_RESOURCE.equals(loader) && file != null) {
+            return new ModuleScript(ModuleScript.RESOURCE_FILE, file);
+        }
+
+        if (LOADER_TEXT.equals(loader) && file != null) {
+            return new ModuleScript(ModuleScript.TEXT_FILE, file);
+        }
+
+        //special handling for json file require
+        if (path.endsWith(".json") && file != null) {
+            return new ModuleScript(ModuleScript.JSON_FILE, file);
+        }
+
+        if (path.endsWith(".bin") && file != null) {
+            log.warn(".bin loder are currently not supported (file  requested: " + path);
+        }
+
+        try {
+            if (file == null || !file.adaptTo(Node.class).isNodeType(NodeType.NT_FILE)) {
+                file = currentResource.getResourceResolver().getResource(path + ".js");
+                if (file == null) {
+                    file = currentResource.getResourceResolver().getResource(path + ".json");
+                    if (file == null) {
+                        return null;
+                    }
+                    type = ModuleScript.JSON_FILE;
+                } else {
+                    type = ModuleScript.JS_FILE;
+                }
+            }
+        } catch (RepositoryException ex) {
+            log.error(module + "", ex);
+        }
+
+        return createModuleScript(file, type);
+    }
+
+    private String cleanModulePathFromLoaders(String path) {
+        if (path.startsWith("resource!")) {
+            return path.substring("resource!".length(), path.length());
+        }
+
+        if (path.startsWith("text!")) {
+            return path.substring("text!".length(), path.length());
+        }
+
+        return path;
+    }
+
+    /**
+     *
+     * @param module
+     * @param path
+     * @param currentResource
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadAsDirectory(String module, String path, Resource currentResource, String loader) throws ScriptException {
+
+        ResourceResolver resolver = currentResource.getResourceResolver();
+        Resource packageJson = resolver.getResource(path + "/package.json");
+
+        if (packageJson != null) {
+            Node jsonFile = packageJson.adaptTo(Node.class);
+
+            try {
+                boolean isFile = (jsonFile.isNodeType(NodeType.NT_FILE) || jsonFile.isNodeType(NodeType.NT_RESOURCE));
+
+                if (isFile) {
+
+                    InputStream is = packageJson.getChild("jcr:content").adaptTo(InputStream.class);
+                    try {
+                        String jsonData = IOUtils.toString(is);
+
+                        JSONObject json;
+                        try {
+                            json = new JSONObject(jsonData);
+                        } catch (JSONException ex) {
+                            throw new ScriptException(ex);
+                        }
+
+                        if (json.has("main")) {
+                            String packageModule;
+                            try {
+                                packageModule = json.getString("main");
+                            } catch (JSONException ex) {
+                                throw new ScriptException(ex);
+                            }
+
+                            String mainpath = normalizePath(packageModule,
+                                    path);
+
+                            return loadAsFile(packageModule, mainpath, currentResource, loader);
+                        }
+
+                    } catch (IOException ex) {
+                        throw new ScriptException(ex);
+                    }
+                }
+
+            } catch (RepositoryException ex) {
+                throw new ScriptException(ex);
+            }
+
+        }
+
+        Resource indexjs = resolver.getResource(path + "/index.js");
+
+        if (indexjs != null) {
+            return createModuleScript(indexjs, ModuleScript.JS_FILE);
+        }
+
+        Resource indexjson = resolver.getResource(path + "/index.json");
+
+        if (indexjson != null) {
+            return createModuleScript(indexjson, ModuleScript.JSON_FILE);
+        }
+
+        Resource indexnode = resolver.getResource(path + "/index.node");
+        if (indexnode != null) {
+            throw new ScriptException("Node module .node (binary) loading is currently not supported");
+        }
+
+        return null;
+    }
+
+    /**
+     *
+     * @param module
+     * @param currentResource
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadAsModule(String module, Resource currentResource, String loader) throws ScriptException {
+        return loadAsModule(module, currentResource, true, loader);
+    }
+
+    /**
+     *
+     * @param paths
+     * @return
+     */
+    private String[] loadModulePaths(String paths) {
+        String[] parts = paths.split("/");
+        List<String> dirs = new ArrayList<String>();
+
+        for (int i = (parts.length - 1); i > 0;) {
+            log.debug(parts[i]);
+            if (parts[i] == "node_modules" || parts[i] == "esx_modules") {
+                continue;
+            }
+            String part = StringUtils.join(parts, "/", 0, i);
+            String dir = part + "/node_modules";
+            log.debug("load dir: " + dir);
+            dirs.add(part + "/esx_modules");
+            dirs.add(dir);
+            i = i - 1;
+        }
+
+        // if the regular module resoultion is not finding anything, try and check the
+        // global paths. needs to be optimized.
+        dirs.add("/apps/esx/esx_modules");
+        dirs.add("/apps/esx/node_modules");
+        dirs.add("/libs/esx/esx_modules");
+        dirs.add("/libs/esx/node_modules");
+
+        return dirs.stream().toArray(String[]::new);
+    }
+
+    /**
+     *
+     * @param module
+     * @param currentResource
+     * @param isFileResource
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadAsModule(String module, Resource currentResource, boolean isFileResource, String loader) throws ScriptException {
+        ModuleScript script = null;
+
+        String[] dirs = loadModulePaths(currentResource.getPath());
+        log.debug("loading modules from dir path");
+        for (String dir : dirs) {
+            log.debug("trying to resolve. " + dir);
+            Resource searchPath = currentResource.getResourceResolver().resolve(dir);
+            log.debug("searchpath  = " + searchPath.getPath());
+            if (searchPath != null && !ResourceUtil.isNonExistingResource(searchPath)) {
+                log.debug("searchpath loadasmodule: " + searchPath.getPath());
+                script = loadLocalModule(module, searchPath, false, loader);
+                if (script != null) {
+                    return script;
+                }
+            } else {
+                log.debug("dir is null = " + dir);
+            }
+        }
+        log.debug("finsihed loading dirs, script is loaded?!");
+        return script;
+    }
+
+    /**
+     *
+     * @param module
+     * @param currentResource
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadLocalModule(String module, Resource currentResource, String loader) throws ScriptException {
+        return loadLocalModule(module, currentResource, false, loader);
+    }
+
+    /**
+     *
+     * @param resource
+     * @return
+     */
+    private boolean resourceIsfile(Resource resource) {
+        try {
+            return resource.adaptTo(Node.class).isNodeType(NodeType.NT_FILE);
+        } catch (RepositoryException ex) {
+            log.error("resourceIsfile", ex);
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param module
+     * @param currentResource
+     * @param isFile
+     * @return
+     * @throws ScriptException
+     */
+    public ModuleScript loadLocalModule(String module, Resource currentResource, boolean isFile, String loader) throws ScriptException {
+        String basePath = (resourceIsfile(currentResource))
+                ? currentResource.getParent().getPath() : currentResource.getPath();
+        String path = normalizePath(module, basePath);
+
+        if (module.startsWith("/")) {
+            path = module;
+        }
+        ModuleScript script = loadAsFile(module, path, currentResource, loader);
+
+        if (script != null) {
+            return script;
+        }
+
+        return loadAsDirectory(module, path, currentResource, loader); // load as directory                              
+    }
+
+    /**
+     * p´
+     *
+     * @param module
+     * @param currentResource
+     * @return
+     * @throws javax.script.ScriptException
+     */
+    public ModuleScript resolve(String module, Resource currentResource, String loader) throws ScriptException {
+        // if x is core module / library return directly the one
+        log.debug("resolving module: " + module);
+        ModuleScript script;
+
+        if (isGlobalModule(module)) {
+            // ignore for now
+        }
+
+        if (isLocalModule(module)) {
+            script = loadLocalModule(module, currentResource, loader);
+            if (script != null) {
+                return script;
+            }
+        }
+
+        // load as module (first split path, then load)
+        script = loadAsModule(module, currentResource, loader);
+        if (script != null) {
+            return script;
+        }
+
+        throw new ScriptException("module not found " + module);
+    }
+
+    @Override
+    public Object require(String id) throws ScriptException, IOException {
+        log.debug("Trying to require Module with Id: " + id);
+        // different behavior if we are the main module, require directly
+        // run runScript directly on this module
+        if (get("id").equals(id)
+                && get("main") == this) {
+            return runScript();
+        }
+
+        String loader = LOADER_JS;
+        if (id.startsWith(LOADER_TEXT)) {
+            loader = LOADER_TEXT;
+        }
+
+        if (id.startsWith(LOADER_RESOURCE)) {
+            loader = LOADER_RESOURCE;
+        }
+        ModuleScript subModuleScript = resolve(cleanModulePathFromLoaders(id), (Resource) get(CONTEXT_FIELD_MODULE_RESOURCE), loader);
+
+        Module subModule = new Module(factory, (Resource) get(CONTEXT_FIELD_RESOURCE),
+                subModuleScript, id, this, (SlingScriptHelper) get(CONTEXT_FIELD_SLING), loader);
+        Object result = subModule.runScript();
+        children.add(subModule);
+        subModule.put(CONTEXT_FIELD_IS_LOADED, true);
+        return result;
+    }
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ModuleScript.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ModuleScript.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ModuleScript.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ModuleScript.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,96 @@
+/*
+ * 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.esx;
+
+import org.apache.sling.api.resource.Resource;
+
+public class ModuleScript {
+    
+    /**
+     * 
+     */
+    public static int JS_FILE = 1;
+    
+    /**
+     * 
+     */
+    public static int JSON_FILE = 2;
+    
+    /**
+     * 
+     */
+    public static int RESOURCE_FILE = 3;
+    
+    /**
+     * 
+     */
+    public static int TEXT_FILE = 4;
+    
+    
+    private int type;
+    private Resource resource;
+    
+    /**
+     * 
+     * @param type
+     * @param resource 
+     */
+    public ModuleScript(int type, Resource resource) {
+        this.type = type;
+        this.resource = resource;
+    }
+    
+    /**
+     * 
+     * @return 
+     */
+    public boolean isJsFile() {
+        return (type == JS_FILE);
+    }
+
+    /**
+     * 
+     * @return 
+     */
+    public boolean isJsonFile() {
+        return (type == JSON_FILE);
+    }
+    
+    /**
+     * 
+     * @return 
+     */
+    public boolean isResourceFile() {
+        return (type == RESOURCE_FILE);
+    }
+    
+    /**
+     * 
+     * @return 
+     */
+    public boolean isTextFile() {
+        return (type == TEXT_FILE);
+    }
+    
+    /**
+     * 
+     * @return 
+     */
+    public Resource getResource() {
+        return resource;
+    }
+}
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Require.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Require.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Require.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/Require.java Fri Mar 24 15:09:46 2017
@@ -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.esx;
+
+import java.io.IOException;
+import javax.script.ScriptException;
+
+/**
+ *
+ * @author stas
+ */
+@FunctionalInterface
+public interface Require {
+    public Object require(String id) throws ScriptException, IOException;
+}
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ScriptModuleCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ScriptModuleCache.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ScriptModuleCache.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/ScriptModuleCache.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.scripting.esx;
+
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import org.apache.sling.api.resource.Resource;
+import org.osgi.service.event.EventHandler;
+
+public interface ScriptModuleCache extends EventHandler{
+
+    /**
+     * put compiled script into script module cache
+     * @param path
+     * @param script
+     */
+    public void put(String module, ScriptObjectMirror script);
+
+    /**
+     * get compiled script or null if the script is not in the cache
+     * @param path
+     * @return
+     */
+    public ScriptObjectMirror get(String module);
+
+    /**
+     * 
+     * @param resource
+     * @return 
+     */
+    public ScriptObjectMirror get(Resource resource);
+    
+
+    /**
+     * removing module script from cache if existing otherwise
+     * doesn't do anything (return always true)
+     *
+     * return false if for some reason cannot be flushed from cache
+     *
+     * @param path
+     */
+    public boolean flush(String module);    
+    
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/ConsoleLog.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/ConsoleLog.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/ConsoleLog.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/ConsoleLog.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,49 @@
+/*
+ * 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.esx.plugins;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConsoleLog {
+
+    Logger log;
+
+    public ConsoleLog(String scriptId) {
+        this.log = LoggerFactory.getLogger(scriptId);
+    }
+
+    public void log(String msg) {
+        log.info(msg);
+    }
+
+    public void info(String msg) {
+        log.info(msg);
+    }
+
+    public void warn(String msg) {
+        log.warn(msg);
+    }
+
+    public void error(String msg) {
+        log.error(msg);
+    }
+
+    public Logger getLogger() {
+        return log;
+    }
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResource.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResource.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResource.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,95 @@
+/*
+ * 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.esx.plugins;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+
+public class SimpleResource {
+
+    private final Resource resource;
+    private final ValueMap valueMap;
+
+    public SimpleResource(Resource resource) {
+        this.resource = resource;
+        this.valueMap = resource.getValueMap();
+    }
+
+    public String getPath() {
+        return resource.getPath();
+    }
+
+    public String getResourceType() {
+        return resource.getResourceType();
+    }
+
+    public String getResourceSuperType() {
+        return resource.getResourceSuperType();
+    }
+
+    public SimpleResource getParent() {
+        return resource.getParent().adaptTo(SimpleResource.class);
+    }
+
+    public boolean hasChildren() {
+        return resource.hasChildren();
+    }
+
+    public boolean isResourceType(String resourceType) {
+        return resource.isResourceType(resourceType);
+    }
+
+    public ValueMap getValueMap() {
+        return valueMap;
+    }
+    
+    public ValueMap getProperties() {
+        return getValueMap();
+    }
+    
+    public String getStringProperty(String key) {
+        return valueMap.get(key, String.class);
+    }
+    
+    public long getDateTimeProperty(String key) {
+        return ((Calendar) valueMap.get(key, Calendar.class)).getTime().getTime();
+    }
+    
+    public Object[] getArray(String key) {
+        return (Object[]) valueMap.get(key, Object[].class);
+    }
+
+    public SimpleResource getChild(String childName) {
+        return resource.getChild(childName).adaptTo(SimpleResource.class);
+    }
+    
+    public ResourceResolver getResourceResolver() {
+        return resource.getResourceResolver();
+    }
+    public List<SimpleResource> getChildren() {
+        Iterator<Resource> resChildren = resource.listChildren();
+        ArrayList<SimpleResource> children = new ArrayList<SimpleResource>();
+        resChildren.forEachRemaining(resource -> children.add(resource.adaptTo(SimpleResource.class)));
+        return children;
+    }
+
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResourceAdapterFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResourceAdapterFactory.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResourceAdapterFactory.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/plugins/SimpleResourceAdapterFactory.java Fri Mar 24 15:09:46 2017
@@ -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.esx.plugins;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.resource.Resource;
+
+@Component
+@Service
+public class SimpleResourceAdapterFactory implements AdapterFactory {
+
+    @Property(name = "adapters")
+    public static final String[] ADAPTER_CLASSES = {
+        SimpleResource.class.getName()
+    };
+    @Property(name = "adaptables")
+    public static final String[] ADAPTABLE_CLASSES = {
+        Resource.class.getName()
+    };
+
+    @Override
+    public <AdapterType> AdapterType getAdapter(Object adaptableObject, Class<AdapterType> type) {
+        if (type.equals(SimpleResource.class)
+                && adaptableObject instanceof Resource) {
+
+            SimpleResource simpeResource = new SimpleResource((Resource) adaptableObject);
+
+            return (AdapterType) simpeResource;
+        } else {
+            return null;
+        }
+    }
+
+}

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/ScriptModuleCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/ScriptModuleCache.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/ScriptModuleCache.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/ScriptModuleCache.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.scripting.esx.services;
+
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import org.apache.sling.api.resource.Resource;
+import org.osgi.service.event.EventHandler;
+
+public interface ScriptModuleCache extends EventHandler{
+
+    /**
+     * put compiled script into script module cache
+     * @param path
+     * @param script
+     */
+    public void put(String module, ScriptObjectMirror script);
+
+    /**
+     * get compiled script or null if the script is not in the cache
+     * @param path
+     * @return
+     */
+    public ScriptObjectMirror get(String module);   
+
+    /**
+     * 
+     * @param resource
+     * @return 
+     */
+    public ScriptObjectMirror get(Resource resource);
+   
+
+    /**
+     * removing module script from cache if existing otherwise
+     * doesn't do anything (return always true)
+     *
+     * return false if for some reason cannot be flushed from cache
+     *
+     * @param path
+     */
+    public boolean flush(String module);        
+    
+}
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/RepositoryModuleCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/RepositoryModuleCache.java?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/RepositoryModuleCache.java (added)
+++ sling/trunk/contrib/scripting/esx/src/main/java/org/apache/sling/scripting/esx/services/impl/RepositoryModuleCache.java Fri Mar 24 15:09:46 2017
@@ -0,0 +1,75 @@
+/*
+ * 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.esx.services.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.scripting.esx.ScriptModuleCache;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service(value = {EventHandler.class, ScriptModuleCache.class})
+@Property(name = org.osgi.service.event.EventConstants.EVENT_TOPIC,
+        value = {SlingConstants.TOPIC_RESOURCE_CHANGED, SlingConstants.TOPIC_RESOURCE_REMOVED})
+public class RepositoryModuleCache implements ScriptModuleCache {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private Map<String, ScriptObjectMirror> cache = new HashMap<String, ScriptObjectMirror>();
+
+    @Override
+    public void put(String module, ScriptObjectMirror script) {
+        log.debug("putting module with absolute path {} in the cache", module);
+        cache.put(module, script);
+    }
+
+    @Override
+    public ScriptObjectMirror get(String module) {
+        return cache.get(module);
+    }
+
+    @Override
+    public ScriptObjectMirror get(Resource resource) {
+        return cache.get(resource.getPath());
+    }
+
+    @Override
+    public boolean flush(String module) {
+        Object res = cache.remove(module);
+        if (res != null) {
+            log.debug("{} flushed from cache", module);
+        }
+        return (true);
+    }
+
+    @Override
+    public void handleEvent(Event event) {
+        final String eventPath = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
+        if (cache.remove(eventPath) != null) {
+            log.info("{} was removed from cache", eventPath);
+        }
+
+    }
+}
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/README.md
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/README.md?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/README.md (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/README.md Fri Mar 24 15:09:46 2017
@@ -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.
+ */
+-->
+# Apache Sling ESX Quick Demo
+
+This is a simple application demonstrating some of the ESX script engine possibilities and ideas how to use it.
+
+In future we want to switch to full ES6 syntax.
+
+
+The demo purpose of this demonstration is to show the usage of npm libraries.
+
+following NPM modules are demonstrated:
+- "handlebars": "^4.0.6",
+- "highlight.js": "^9.10.0",
+- "marked": "^0.3.6",
+- "moment": "^2.18.0",
+- "underscore": "^1.8.3"
+
+## Installation
+
+- switch to directory src/main/resources/libs/esx/demo
+- run: npm install
+- go back to package root directory
+- run mvn clean install sling:install´
+
+open the page /libs/esx/demo/content/demo.html

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/index.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/index.js?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/index.js (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/BlogComponent/index.js Fri Mar 24 15:09:46 2017
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+var Handlebars = require("handlebars");
+var marked = require("marked");
+var URL = require("url");
+
+var renderer = new marked.Renderer();
+renderer.blockquote = function (quote) {
+  return "<blockquote class='blockquote'>" + quote + "</blockquote>";
+}
+
+function resolveTitle(res) {
+   return  res.properties.navTitle || res.properties.title || res.properties["jcr:title"] || res.name;
+
+}
+
+function BlogComponent () {
+  this.templateURL = "../../hbstemplates/layout.html"
+  this.basePath = URL.getAbsoluteParent(currentNode.resource.path, 4);
+  this.baseResource = require("resource!" + this.basePath);
+  this.stylesheet = "";
+  this.partialContentTemplateURL = "../../hbstemplates/content.html";
+  this.model = currentNode;
+  this.model.title = currentNode.properties.pageTitle || currentNode.properties.title || currentNode.properties["jcr:title"] || currentNode.resource.name;
+}
+
+BlogComponent.prototype.transformMarkdown = function (content) {
+  return marked(content, { renderer: renderer});
+}
+BlogComponent.prototype.pages = function () {
+  var pages = [];
+  var homePage =
+    pages.push({
+        path: this.basePath,
+        title: resolveTitle(this.baseResource),
+        active: (currentNode.resource.path === this.basePath ? 'active' : '')
+    });
+
+  var rootPage = require("resource!" + this.basePath + "/pages");
+   var children = rootPage.simpleResource.children;
+
+    for(var key in children) {
+        var child =  children[key];
+        var nav = {};
+        nav.path =child.path;
+        nav.title =  resolveTitle(child) ;
+        nav.active = (currentNode.resource.path === child.path ? 'active' : '');
+        pages.push(nav);
+    }
+
+  return pages;
+}
+
+BlogComponent.prototype.render = function () {
+  this.init();
+  Handlebars.registerPartial('content',require("text!" + this.partialContentTemplateURL));
+
+
+  var templateSource= require("text!" + this.templateURL);
+  var template = Handlebars.compile(templateSource);
+  this.model.style = this.stylesheet;
+  this.model.pagesNav = this.pages();
+
+  return template(this.model);
+}
+
+module.exports = BlogComponent;

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/index.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/index.js?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/index.js (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/esx_modules/calculator/index.js Fri Mar 24 15:09:46 2017
@@ -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.
+ */
+
+function calulate(a, b) {
+  return a + b;
+}
+exports.math = calulate;
+exports.VERSION = "version 1.1 " + __dirname;

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/content.html
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/content.html?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/content.html (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/content.html Fri Mar 24 15:09:46 2017
@@ -0,0 +1,17 @@
+{{!--/*
+ * 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.
+ */--}}
+content partial template, please overwrite
\ No newline at end of file

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/layout.html
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/layout.html?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/layout.html (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/hbstemplates/layout.html Fri Mar 24 15:09:46 2017
@@ -0,0 +1,68 @@
+{{!--/*
+ * 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.
+ */--}}<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <!-- Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <style>
+    {{{style}}}
+    </style>
+    <title>{{title}}</title>
+  </head>
+  <body>
+    <nav  class="navbar navbar-light bg-faded navbar-toggleable-md" style="background-color:#f9bb00">
+      <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+   <span class="navbar-toggler-icon"></span>
+ </button>
+      <a class="navbar-brand" href="#">
+        <img src="https://sling.apache.org/res/logo.png" height="50">
+      </a>
+
+
+      <div class="collapse navbar-collapse" id="navbarNav">
+        <ul class="navbar-nav container">
+          {{#each pagesNav}}
+           <li class="nav-item {{active}}">
+              <a class="nav-link" href="{{path}}.html">{{title}}</a>
+          </li>
+          {{/each}}
+        </ul>
+      </div>
+
+    </nav>
+
+<div class="jumbotron jumbotron-fluid">
+  <div class="container">   <p class="lead">{{date}}</p>
+    <h1 class="display-2">{{title}}</h1>
+    <p class="lead">{{description}}</p>
+  </div>
+</div>
+  <div class="container">
+    {{> content }}
+  </div>
+
+
+
+    <!-- jQuery first, then Tether, then Bootstrap JS. -->
+    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
+  </body>
+</html>

Added: sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/index.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/index.js?rev=1788464&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/index.js (added)
+++ sling/trunk/contrib/scripting/esx/src/main/resources/libs/esx/demo/components/page/helper/calculator/index.js Fri Mar 24 15:09:46 2017
@@ -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.
+ */
+
+function calulate(a, b) {
+  return a + b;
+}
+exports.math = calulate;
+exports.VERSION = "version 1.1";
\ No newline at end of file