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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5f0175f  SLING-8012 - Extract an HTL runtime bundle from the existing 
HTL modules
5f0175f is described below

commit 5f0175fc727033030a4cfc728acb43b3ed3165ce
Author: Radu Cotescu <[email protected]>
AuthorDate: Thu Oct 18 16:20:55 2018 +0200

    SLING-8012 - Extract an HTL runtime bundle from the existing HTL modules
    
    * refactored code so that compilation becomes completely optional, depending
    on which modules are available at runtime
---
 pom.xml                                            |  24 +-
 .../sightly/impl/engine/SightlyCompiledScript.java |  15 +-
 .../impl/engine/SightlyJavaCompilerService.java    | 280 -------------------
 .../sightly/impl/engine/SightlyScriptEngine.java   | 144 ++--------
 .../impl/engine/SightlyScriptEngineFactory.java    |  94 +------
 .../impl/engine/compiled/SourceIdentifier.java     | 155 +----------
 .../engine/extension/FormatFilterExtension.java    |   5 +-
 .../engine/extension/I18nRuntimeExtension.java     |   5 +-
 .../engine/extension/IncludeRuntimeExtension.java  |   5 +-
 .../impl/engine/extension/JoinFilterExtension.java |   5 +-
 .../engine/extension/ResourceRuntimeExtension.java |   5 +-
 .../extension/URIManipulationFilterExtension.java  |   5 +-
 .../impl/engine/extension/XSSRuntimeExtension.java |  60 ++++-
 .../impl/engine/extension/use/JavaUseProvider.java |  89 ++++---
 .../engine/extension/use/RenderUnitProvider.java   |   2 +-
 .../engine/extension/use/UseRuntimeExtension.java  |   5 +-
 .../impl/engine/runtime/RenderContextImpl.java     |  14 +-
 .../compiler/SightlyJavaCompilerServiceTest.java   | 189 -------------
 .../impl/engine/SightlyCompiledScriptTest.java     |   6 +-
 .../engine/SightlyScriptEngineFactoryTest.java     | 121 ---------
 .../compiled/SlingHTLMasterCompilerTest.java       | 296 +++++++++++++++++++++
 .../impl/engine/compiled/SourceIdentifierTest.java |  29 +-
 22 files changed, 490 insertions(+), 1063 deletions(-)

diff --git a/pom.xml b/pom.xml
index cdf3d74..09a7d3b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,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.57-1.4.0-SNAPSHOT</version>
+    <version>1.1.0-1.4.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Scripting HTL Engine</name>
@@ -89,9 +89,15 @@
                             io.sightly; version:Version=1.4
                         </Provide-Capability>
                         <Require-Capability>
-                            io.sightly.compiler; 
filter:="(&amp;(version&gt;=1.0)(version&lt;=1.4))",
-                            io.sightly.compiler.java; 
filter:="(&amp;(version&gt;=1.0)(version&lt;=1.4))"
+                            io.sightly.runtime; 
filter:="(&amp;(version&gt;=1.0)(!(version&gt;=2.0)))"
                         </Require-Capability>
+                        <Import-Package>
+                            
org.apache.sling.scripting.sightly.compiler.*;resolution:=optional,
+                            
org.apache.sling.scripting.sightly.java.compiler.*;resolution:=optional,
+                            
org.apache.sling.commons.compiler.*;resolution:=optional,
+                            
org.apache.sling.commons.classloader.*;resolution:=optional,
+                            *
+                        </Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
@@ -168,17 +174,25 @@
     <!-- D E P E N D E N C I E S                                               
  -->
     <!-- 
======================================================================= -->
     <dependencies>
+        <!-- HTL Runtime -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.sightly.runtime</artifactId>
+            <version>1.0.0-1.4.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+
         <!-- HTL Compilers -->
         <dependency>
             <groupId>org.apache.sling</groupId>
             
<artifactId>org.apache.sling.scripting.sightly.compiler</artifactId>
-            <version>1.0.22-1.4.0</version>
+            <version>1.0.23-1.4.0-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             
<artifactId>org.apache.sling.scripting.sightly.compiler.java</artifactId>
-            <version>1.0.26-1.4.0</version>
+            <version>1.0.27-1.4.0-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
 
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScript.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScript.java
index cf2c9ea..c43e297 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScript.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScript.java
@@ -19,33 +19,32 @@
 package org.apache.sling.scripting.sightly.impl.engine;
 
 import java.io.PrintWriter;
+
 import javax.script.Bindings;
 import javax.script.CompiledScript;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
-import javax.script.ScriptException;
 import javax.script.SimpleBindings;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.api.scripting.SlingScriptConstants;
 import org.apache.sling.scripting.sightly.SightlyException;
 import 
org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl;
-import org.apache.sling.scripting.sightly.java.compiler.RenderUnit;
 import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RenderUnit;
 
 public class SightlyCompiledScript extends CompiledScript {
 
-    private ScriptEngine scriptEngine;
-    private RenderUnit renderUnit;
+    private final SightlyScriptEngine scriptEngine;
+    private final RenderUnit renderUnit;
 
-    public SightlyCompiledScript(ScriptEngine scriptEngine, RenderUnit 
renderUnit) {
+    public SightlyCompiledScript(SightlyScriptEngine scriptEngine, RenderUnit 
renderUnit) {
         this.scriptEngine = scriptEngine;
         this.renderUnit = renderUnit;
     }
 
     @Override
-    public Object eval(ScriptContext context) throws ScriptException {
+    public Object eval(ScriptContext context) {
         Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
         SlingBindings slingBindings = new SlingBindings();
         slingBindings.putAll(bindings);
@@ -56,7 +55,7 @@ public class SightlyCompiledScript extends CompiledScript {
         Object oldBindings = 
request.getAttribute(SlingBindings.class.getName());
         try {
             request.setAttribute(SlingBindings.class.getName(), slingBindings);
-            RenderContext renderContext = new RenderContextImpl(context);
+            RenderContext renderContext = new 
RenderContextImpl(scriptEngine.getExtensionRegistryService(), context);
             PrintWriter out = new PrintWriter(context.getWriter());
             renderUnit.render(out, renderContext, new SimpleBindings());
         } finally {
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
deleted file mode 100644
index 0827f9c..0000000
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
+++ /dev/null
@@ -1,280 +0,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.
- 
******************************************************************************/
-package org.apache.sling.scripting.sightly.impl.engine;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.commons.compiler.CompilationResult;
-import org.apache.sling.commons.compiler.CompilationUnit;
-import org.apache.sling.commons.compiler.CompilerMessage;
-import org.apache.sling.commons.compiler.JavaCompiler;
-import org.apache.sling.commons.compiler.Options;
-import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
-import org.apache.sling.scripting.sightly.SightlyException;
-import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier;
-import org.apache.sling.scripting.sightly.impl.utils.Patterns;
-import org.apache.sling.scripting.sightly.impl.utils.ScriptUtils;
-import org.apache.sling.scripting.sightly.render.RenderContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * The {@code SightlyJavaCompiler} allows for simple instantiation of 
arbitrary classes that are either stored in the repository
- * or in regular OSGi bundles. It also compiles Java sources on-the-fly and 
can discover class' source files based on
- * {@link Resource}s (typically Sling components). It supports Sling Resource 
type inheritance.
- */
-@Component(
-        service = SightlyJavaCompilerService.class
-)
-public class SightlyJavaCompilerService {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(SightlyJavaCompilerService.class);
-
-    @Reference
-    private ClassLoaderWriter classLoaderWriter = null;
-
-    @Reference
-    private JavaCompiler javaCompiler = null;
-
-    @Reference
-    private ResourceBackedPojoChangeMonitor resourceBackedPojoChangeMonitor = 
null;
-
-    @Reference
-    private SightlyEngineConfiguration sightlyEngineConfiguration = null;
-
-    @Reference
-    private ScriptingResourceResolverProvider 
scriptingResourceResolverProvider = null;
-
-    private Map<String, Lock> compilationLocks = new HashMap<>();
-
-    private Options options;
-
-    /**
-     * This method returns an Object instance based on a {@link 
Resource}-backed class that is either found through regular classloading
-     * mechanisms or on-the-fly compilation. In case the requested class does 
not denote a fully qualified class name, this service will
-     * try to find the class through Sling's resource resolution mechanism and 
compile the class on-the-fly if required.
-     *
-     * @param renderContext the render context
-     * @param className     name of class to use for object instantiation
-     * @return object instance of the requested class or {@code null} if the 
specified class is not backed by a {@link Resource}
-     */
-    public Object getResourceBackedUseObject(RenderContext renderContext, 
String className) {
-        LOG.debug("Attempting to load class {}.", className);
-        try {
-            if (className.contains(".")) {
-                Resource pojoResource =
-                        
SourceIdentifier.getPOJOFromFQCN(scriptingResourceResolverProvider.getRequestScopedResourceResolver()
-                                , null, className);
-                if (pojoResource != null) {
-                    return getUseObjectAndRecompileIfNeeded(pojoResource);
-                }
-            } else {
-                Resource pojoResource = ScriptUtils.resolveScript(
-                        
scriptingResourceResolverProvider.getRequestScopedResourceResolver(),
-                        renderContext,
-                        className + ".java"
-                );
-                if (pojoResource != null) {
-                    return getUseObjectAndRecompileIfNeeded(pojoResource);
-                }
-            }
-        } catch (Exception e) {
-            throw new SightlyException("Cannot obtain an instance for class " 
+ className + ".", e);
-        }
-        return null;
-    }
-
-    /**
-     * Compiles a class using the passed fully qualified class name and its 
source code.
-     *
-     * @param sourceIdentifier the source identifier
-     * @param sourceCode       the source code from which to generate the class
-     * @return object instance of the class to compile
-     */
-    public Object compileSource(SourceIdentifier sourceIdentifier, String 
sourceCode) {
-        Lock lock;
-        final String fqcn = sourceIdentifier.getFullyQualifiedClassName();
-        synchronized (compilationLocks) {
-            lock = compilationLocks.get(fqcn);
-            if (lock == null) {
-                lock = new ReentrantLock();
-                compilationLocks.put(fqcn, lock);
-            }
-        }
-        lock.lock();
-        try {
-            if (sightlyEngineConfiguration.keepGenerated()) {
-                String path = "/" + fqcn.replaceAll("\\.", "/") + ".java";
-                OutputStream os = classLoaderWriter.getOutputStream(path);
-                IOUtils.write(sourceCode, os, "UTF-8");
-                IOUtils.closeQuietly(os);
-            }
-            String[] sourceCodeLines = 
sourceCode.split("\\r\\n|[\\n\\x0B\\x0C\\r\\u0085\\u2028\\u2029]");
-            boolean foundPackageDeclaration = false;
-            for (String line : sourceCodeLines) {
-                Matcher matcher = 
Patterns.JAVA_PACKAGE_DECLARATION.matcher(line);
-                if (matcher.matches()) {
-                /*
-                 * This matching might return false positives like:
-                 * // package a.b.c;
-                 *
-                 * where from a syntactic point of view the source code 
doesn't have a package declaration and the expectancy is that our
-                 * SightlyJavaCompilerService will add one.
-                 */
-                    foundPackageDeclaration = true;
-                    break;
-                }
-            }
-
-            if (!foundPackageDeclaration) {
-                sourceCode = "package " + sourceIdentifier.getPackageName() + 
";\n" + sourceCode;
-            }
-
-            CompilationUnit compilationUnit = new 
SightlyCompilationUnit(sourceCode, fqcn);
-            long start = System.currentTimeMillis();
-            CompilationResult compilationResult = javaCompiler.compile(new 
CompilationUnit[]{compilationUnit}, options);
-            long end = System.currentTimeMillis();
-            List<CompilerMessage> errors = compilationResult.getErrors();
-            if (errors != null && errors.size() > 0) {
-                throw new SightlyException(createErrorMsg(errors));
-            }
-            if (compilationResult.didCompile()) {
-                LOG.debug("Class {} was compiled in {}ms.", fqcn, end - start);
-            }
-            /*
-             * the class loader might have become dirty, so let the {@link 
ClassLoaderWriter} decide which class loader to return
-             */
-            return 
classLoaderWriter.getClassLoader().loadClass(fqcn).newInstance();
-        } catch (Exception e) {
-            throw new SightlyException(e);
-        } finally {
-            lock.unlock();
-        }
-    }
-
-
-    private Object getUseObjectAndRecompileIfNeeded(Resource pojoResource)
-            throws IOException, InstantiationException, 
IllegalAccessException, ClassNotFoundException {
-        SourceIdentifier sourceIdentifier = new 
SourceIdentifier(sightlyEngineConfiguration, pojoResource.getPath());
-        long sourceLastModifiedDateFromCache =
-                
resourceBackedPojoChangeMonitor.getLastModifiedDateForJavaUseObject(pojoResource.getPath());
-        long classLastModifiedDate = classLoaderWriter.getLastModified("/" + 
sourceIdentifier.getFullyQualifiedClassName()
-                .replaceAll("\\.", "/") + ".class");
-        if (sourceLastModifiedDateFromCache == 0) {
-            // first access; let's check the real last modified date of the 
source
-            long sourceLastModifiedDate = 
pojoResource.getResourceMetadata().getModificationTime();
-            
resourceBackedPojoChangeMonitor.recordLastModifiedTimestamp(pojoResource.getPath(),
 sourceLastModifiedDate);
-            if (classLastModifiedDate < 0 || sourceLastModifiedDate > 
classLastModifiedDate) {
-                return compileSource(sourceIdentifier, 
IOUtils.toString(pojoResource.adaptTo(InputStream.class), "UTF-8"));
-            } else {
-                return 
classLoaderWriter.getClassLoader().loadClass(sourceIdentifier.getFullyQualifiedClassName()).newInstance();
-            }
-        } else {
-            if (sourceLastModifiedDateFromCache > classLastModifiedDate) {
-                return compileSource(sourceIdentifier, 
IOUtils.toString(pojoResource.adaptTo(InputStream.class), "UTF-8"));
-            } else {
-                return 
classLoaderWriter.getClassLoader().loadClass(sourceIdentifier.getFullyQualifiedClassName()).newInstance();
-            }
-        }
-    }
-
-    @Activate
-    protected void activate() {
-        LOG.info("Activating {}", getClass().getName());
-
-        String version = System.getProperty("java.specification.version");
-        options = new Options();
-        options.put(Options.KEY_GENERATE_DEBUG_INFO, true);
-        options.put(Options.KEY_SOURCE_VERSION, version);
-        options.put(Options.KEY_TARGET_VERSION, version);
-        options.put(Options.KEY_CLASS_LOADER_WRITER, classLoaderWriter);
-        options.put(Options.KEY_FORCE_COMPILATION, true);
-    }
-
-    //---------------------------------- private 
-----------------------------------
-    private String createErrorMsg(List<CompilerMessage> errors) {
-        final StringBuilder buffer = new StringBuilder();
-        buffer.append("Compilation errors in ");
-        buffer.append(errors.get(0).getFile());
-        buffer.append(":");
-        StringBuilder errorsBuffer = new StringBuilder();
-        boolean duplicateVariable = false;
-        for (final CompilerMessage e : errors) {
-            if (!duplicateVariable) {
-                if (e.getMessage().contains("Duplicate local variable")) {
-                    duplicateVariable = true;
-                    buffer.append(" Maybe you defined more than one identical 
block elements without defining a different variable for "
-                            + "each one?");
-                }
-            }
-            errorsBuffer.append("\nLine ");
-            errorsBuffer.append(e.getLine());
-            errorsBuffer.append(", column ");
-            errorsBuffer.append(e.getColumn());
-            errorsBuffer.append(" : ");
-            errorsBuffer.append(e.getMessage());
-        }
-        buffer.append(errorsBuffer);
-        return buffer.toString();
-    }
-
-    private static class SightlyCompilationUnit implements CompilationUnit {
-
-        private String fqcn;
-        private String sourceCode;
-
-        SightlyCompilationUnit(String sourceCode, String fqcn) throws 
Exception {
-            this.sourceCode = sourceCode;
-            this.fqcn = fqcn;
-        }
-
-        @Override
-        public Reader getSource() throws IOException {
-            return new InputStreamReader(IOUtils.toInputStream(sourceCode, 
"UTF-8"), "UTF-8");
-        }
-
-        @Override
-        public String getMainClassName() {
-            return fqcn;
-        }
-
-        @Override
-        public long getLastModified() {
-            return System.currentTimeMillis();
-        }
-    }
-}
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngine.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngine.java
index 4d08e8c..fdb6456 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngine.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngine.java
@@ -20,32 +20,14 @@ package org.apache.sling.scripting.sightly.impl.engine;
 
 import java.io.Reader;
 import java.io.StringReader;
-import java.util.Set;
 
-import javax.script.Bindings;
 import javax.script.Compilable;
 import javax.script.CompiledScript;
 import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
 import javax.script.ScriptException;
 
-import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
-import org.apache.sling.scripting.api.ScriptNameAware;
-import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
-import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.CompilationResult;
-import org.apache.sling.scripting.sightly.compiler.CompilationUnit;
-import org.apache.sling.scripting.sightly.compiler.CompilerMessage;
-import org.apache.sling.scripting.sightly.compiler.SightlyCompiler;
-import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier;
-import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
-import 
org.apache.sling.scripting.sightly.java.compiler.GlobalShadowCheckBackendCompiler;
-import 
org.apache.sling.scripting.sightly.java.compiler.JavaClassBackendCompiler;
-import org.apache.sling.scripting.sightly.java.compiler.JavaEscapeUtils;
-import org.apache.sling.scripting.sightly.java.compiler.JavaImportsAnalyzer;
-import org.apache.sling.scripting.sightly.java.compiler.RenderUnit;
+import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SlingHTLMasterCompiler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,25 +38,13 @@ public class SightlyScriptEngine extends 
AbstractSlingScriptEngine implements Co
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(SightlyScriptEngine.class);
 
-    public static final String NO_SCRIPT = "NO_SCRIPT";
+    private SlingHTLMasterCompiler slingHTLMasterCompiler;
+    private ExtensionRegistryService extensionRegistryService;
 
-    private SightlyCompiler sightlyCompiler;
-    private SightlyJavaCompilerService javaCompilerService;
-    private final SightlyEngineConfiguration configuration;
-    private final ScriptingResourceResolverProvider 
scriptingResourceResolverProvider;
-    private final SlingJavaImportsAnalyser importsAnalyser;
-
-    public SightlyScriptEngine(ScriptEngineFactory scriptEngineFactory,
-                               SightlyCompiler sightlyCompiler,
-                               SightlyJavaCompilerService javaCompilerService,
-                               SightlyEngineConfiguration configuration,
-                               ScriptingResourceResolverProvider 
scriptingResourceResolverProvider) {
-        super(scriptEngineFactory);
-        this.sightlyCompiler = sightlyCompiler;
-        this.javaCompilerService = javaCompilerService;
-        this.configuration = configuration;
-        this.scriptingResourceResolverProvider = 
scriptingResourceResolverProvider;
-        importsAnalyser = new SlingJavaImportsAnalyser();
+    SightlyScriptEngine(SightlyScriptEngineFactory factory, 
ExtensionRegistryService extensionRegistryService, SlingHTLMasterCompiler 
slingHTLMasterCompiler) {
+        super(factory);
+        this.extensionRegistryService = extensionRegistryService;
+        this.slingHTLMasterCompiler = slingHTLMasterCompiler;
     }
 
     @Override
@@ -84,72 +54,32 @@ public class SightlyScriptEngine extends 
AbstractSlingScriptEngine implements Co
 
     @Override
     public CompiledScript compile(final Reader script) throws ScriptException {
-        return internalCompile(script, null);
+        if (slingHTLMasterCompiler != null) {
+            return slingHTLMasterCompiler.compileHTLScript(this, script, null);
+        }
+        throw new ScriptException("Missing compilation support.");
     }
 
     @Override
     public Object eval(Reader reader, ScriptContext scriptContext) throws 
ScriptException {
         checkArguments(reader, scriptContext);
         try {
-            SightlyCompiledScript compiledScript = internalCompile(reader, 
scriptContext);
-            return compiledScript.eval(scriptContext);
+            SightlyCompiledScript compiledScript = null;
+            if (slingHTLMasterCompiler != null) {
+                compiledScript = slingHTLMasterCompiler.compileHTLScript(this, 
reader, scriptContext);
+            }
+            if (compiledScript != null) {
+                return compiledScript.eval(scriptContext);
+            }
         } catch (Exception e) {
             throw new ScriptException(e);
         }
+        LOGGER.warn("Did not find a compilable or executable unit.");
+        return null;
     }
 
-    private SightlyCompiledScript internalCompile(final Reader script, 
ScriptContext scriptContext) throws ScriptException {
-        ClassLoader old = Thread.currentThread().getContextClassLoader();
-        
Thread.currentThread().setContextClassLoader(((SightlyScriptEngineFactory) 
getFactory()).getClassLoader());
-        try {
-            String sName = NO_SCRIPT;
-            if (script instanceof ScriptNameAware) {
-                sName = ((ScriptNameAware) script).getScriptName();
-            }
-            if (sName.equals(NO_SCRIPT)) {
-                sName = getScriptName(scriptContext);
-            }
-            final String scriptName = sName;
-            CompilationUnit compilationUnit = new CompilationUnit() {
-                @Override
-                public String getScriptName() {
-                    return scriptName;
-                }
-
-                @Override
-                public Reader getScriptReader() {
-                    return script;
-                }
-            };
-            JavaClassBackendCompiler javaClassBackendCompiler = new 
JavaClassBackendCompiler(importsAnalyser);
-            GlobalShadowCheckBackendCompiler shadowCheckBackendCompiler = null;
-            if (scriptContext != null) {
-                Bindings bindings = 
scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
-                Set<String> globals = bindings.keySet();
-                shadowCheckBackendCompiler = new 
GlobalShadowCheckBackendCompiler(javaClassBackendCompiler, globals);
-            }
-            CompilationResult result = shadowCheckBackendCompiler == null ? 
sightlyCompiler.compile(compilationUnit,
-                    javaClassBackendCompiler) : 
sightlyCompiler.compile(compilationUnit, shadowCheckBackendCompiler);
-            if (result.getWarnings().size() > 0) {
-                for (CompilerMessage warning : result.getWarnings()) {
-                    LOGGER.warn("Script {} {}:{}: {}", 
warning.getScriptName(), warning.getLine(), warning.getColumn(), 
warning.getMessage());
-                }
-            }
-            if (result.getErrors().size() > 0) {
-                CompilerMessage error = result.getErrors().get(0);
-                throw new ScriptException(error.getMessage(), 
error.getScriptName(), error.getLine(), error.getColumn());
-            }
-            SourceIdentifier sourceIdentifier = new 
SourceIdentifier(configuration, scriptName);
-            String javaSourceCode = 
javaClassBackendCompiler.build(sourceIdentifier);
-            Object renderUnit = 
javaCompilerService.compileSource(sourceIdentifier, javaSourceCode);
-            if (renderUnit instanceof RenderUnit) {
-                return new SightlyCompiledScript(this, (RenderUnit) 
renderUnit);
-            } else {
-                throw new SightlyException("Expected a RenderUnit.");
-            }
-        } finally {
-            Thread.currentThread().setContextClassLoader(old);
-        }
+    public ExtensionRegistryService getExtensionRegistryService() {
+        return extensionRegistryService;
     }
 
     private void checkArguments(Reader reader, ScriptContext scriptContext) {
@@ -161,35 +91,5 @@ public class SightlyScriptEngine extends 
AbstractSlingScriptEngine implements Co
         }
     }
 
-    private String getScriptName(ScriptContext scriptContext) {
-        if (scriptContext != null) {
-            Bindings bindings = 
scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
-            String scriptName = (String) bindings.get(ScriptEngine.FILENAME);
-            if (scriptName != null && !"".equals(scriptName)) {
-                return scriptName;
-            }
-            SlingScriptHelper sling = BindingsUtils.getHelper(bindings);
-            if (sling != null) {
-                return sling.getScript().getScriptResource().getPath();
-            }
-        }
-        return NO_SCRIPT;
-    }
 
-    /**
-     * This custom imports analyser makes sure that no import statements are 
generated for repository-based use objects, since these are
-     * not compiled ahead of the HTL scripts.
-     */
-    class SlingJavaImportsAnalyser implements JavaImportsAnalyzer {
-        @Override
-        public boolean allowImport(String importedClass) {
-            for (String searchPath : 
scriptingResourceResolverProvider.getRequestScopedResourceResolver().getSearchPath())
 {
-                String subPackage = 
JavaEscapeUtils.makeJavaPackage(searchPath);
-                if (importedClass.startsWith(subPackage)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
 }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java
index 76ba78d..d80f13b 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactory.java
@@ -18,30 +18,17 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.engine;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
-import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
-import org.apache.sling.scripting.sightly.compiler.SightlyCompiler;
-import org.apache.sling.scripting.sightly.java.compiler.JavaEscapeUtils;
+import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SlingHTLMasterCompiler;
 import org.osgi.framework.Constants;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
 
 /**
  * HTL template engine factory
@@ -58,35 +45,17 @@ import org.slf4j.LoggerFactory;
 )
 public class SightlyScriptEngineFactory extends AbstractScriptEngineFactory {
 
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(SightlyScriptEngineFactory.class);
-
-    @Reference
-    private DynamicClassLoaderManager dynamicClassLoaderManager;
-
-    @Reference
-    private SightlyEngineConfiguration sightlyEngineConfiguration;
-
-    @Reference
-    private ClassLoaderWriter classLoaderWriter;
-
-    @Reference
-    private SightlyCompiler sightlyCompiler;
-
-    @Reference
-    private SightlyJavaCompilerService sightlyJavaCompilerService;
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = 
ReferencePolicyOption.GREEDY)
+    private SlingHTLMasterCompiler slingHTLMasterCompiler;
 
     @Reference
-    private ScriptingResourceResolverProvider 
scriptingResourceResolverProvider;
+    private ExtensionRegistryService extensionRegistryService;
 
     public final static String SHORT_NAME = "sightly";
-
-    public final static String LANGUAGE_NAME = "The HTL Templating Language";
-
-    public final static String LANGUAGE_VERSION = "1.3";
-
     public final static String EXTENSION = "html";
 
-    public static final String SIGHTLY_CONFIG_FILE = "/sightly.config";
+    private final static String LANGUAGE_NAME = "The HTL Templating Language";
+    private final static String LANGUAGE_VERSION = "1.4";
 
     public SightlyScriptEngineFactory() {
         setNames("htl", "HTL", SHORT_NAME);
@@ -105,49 +74,6 @@ public class SightlyScriptEngineFactory extends 
AbstractScriptEngineFactory {
 
     @Override
     public ScriptEngine getScriptEngine() {
-        return new SightlyScriptEngine(this, sightlyCompiler, 
sightlyJavaCompilerService, sightlyEngineConfiguration, 
scriptingResourceResolverProvider);
-    }
-
-    protected ClassLoader getClassLoader() {
-        return dynamicClassLoaderManager.getDynamicClassLoader();
-    }
-
-    @Activate
-    protected void activate() {
-        InputStream is;
-        boolean newVersion = true;
-        String versionInfo = null;
-        String newVersionString = 
sightlyEngineConfiguration.getEngineVersion();
-        try {
-            is = classLoaderWriter.getInputStream(SIGHTLY_CONFIG_FILE);
-            if (is != null) {
-                versionInfo = IOUtils.toString(is, "UTF-8");
-                if (newVersionString.equals(versionInfo)) {
-                    newVersion = false;
-                } else {
-                    LOGGER.info("Detected stale classes generated by Apache 
Sling Scripting HTL engine version {}.", versionInfo);
-                }
-                IOUtils.closeQuietly(is);
-            }
-        } catch (IOException e) {
-            // do nothing; if we didn't find any previous version information 
we're considering our version to be new
-        }
-        if (newVersion) {
-            OutputStream os = 
classLoaderWriter.getOutputStream(SIGHTLY_CONFIG_FILE);
-            try {
-                IOUtils.write(sightlyEngineConfiguration.getEngineVersion(), 
os, "UTF-8");
-            } catch (IOException e) {
-                // ignore
-            } finally {
-                IOUtils.closeQuietly(os);
-            }
-            String scratchFolder = 
sightlyEngineConfiguration.getScratchFolder();
-            boolean scratchFolderDeleted = 
classLoaderWriter.delete(scratchFolder);
-            if (scratchFolderDeleted) {
-                if (StringUtils.isNotEmpty(versionInfo)) {
-                    LOGGER.info("Deleted stale classes generated by Apache 
Sling Scripting HTL engine version {}.", versionInfo);
-                }
-            }
-        }
+        return new SightlyScriptEngine(this, extensionRegistryService, 
slingHTLMasterCompiler);
     }
 }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
index d32b5cb..5d2fb03 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
@@ -18,17 +18,7 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.engine.compiled;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
 import 
org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
 import org.apache.sling.scripting.sightly.java.compiler.ClassInfo;
 import org.apache.sling.scripting.sightly.java.compiler.JavaEscapeUtils;
@@ -39,14 +29,13 @@ import 
org.apache.sling.scripting.sightly.java.compiler.JavaEscapeUtils;
  */
 public class SourceIdentifier implements ClassInfo {
 
-    private static final Pattern MANGLED_CHAR_PATTERN = 
Pattern.compile("(.*)(__[0-9a-f]{4}__)(.*)");
     private SightlyEngineConfiguration engineConfiguration;
     private String scriptName;
     private String simpleClassName;
     private String packageName;
     private String fullyQualifiedClassName;
 
-    public SourceIdentifier(SightlyEngineConfiguration engineConfiguration, 
String resourcePath) {
+    SourceIdentifier(SightlyEngineConfiguration engineConfiguration, String 
resourcePath) {
         this.engineConfiguration = engineConfiguration;
         this.scriptName = resourcePath;
     }
@@ -96,146 +85,4 @@ public class SourceIdentifier implements ClassInfo {
         }
         return fullyQualifiedClassName;
     }
-
-    /**
-     * Given a {@code fullyQualifiedClassName} and optionally a sub-package 
that should be stripped ({@code slashSubpackage}), this
-     * method will try to locate a {@code Resource} in the repository that 
provides the source code for the Java class.
-     *
-     * @param resolver                a resource resolver with access to the 
script paths
-     * @param slashSubpackage         an optional sub-package that will be 
stripped from the {@code fullyQualifiedClassName}
-     * @param fullyQualifiedClassName the FQCN
-     * @return the {@code Resource} backing the class, or {@code null} if one 
cannot be found
-     */
-    public static Resource getPOJOFromFQCN(ResourceResolver resolver, String 
slashSubpackage, String fullyQualifiedClassName) {
-        String className = fullyQualifiedClassName;
-        StringBuilder pathElements = new StringBuilder("/");
-        if (StringUtils.isNotEmpty(slashSubpackage) && 
className.contains(slashSubpackage)) {
-            className = className.replaceAll(slashSubpackage + "\\.", "");
-        }
-        String[] classElements = StringUtils.split(className, '.');
-        for (int i = 0; i < classElements.length; i++) {
-            String classElem = classElements[i];
-            Matcher matcher = MANGLED_CHAR_PATTERN.matcher(classElem);
-            if (matcher.matches()) {
-                String group = matcher.group(2);
-                char unmangled = JavaEscapeUtils.unmangle(group);
-                classElem = classElem.replaceAll(group, 
Character.toString(unmangled));
-                while (matcher.find()) {
-                    group = matcher.group(2);
-                    unmangled = JavaEscapeUtils.unmangle(group);
-                    classElem = classElem.replaceAll(group, 
Character.toString(unmangled));
-                }
-            } else {
-                int underscoreIndex = classElem.indexOf('_');
-                if (underscoreIndex > -1) {
-                    if (underscoreIndex == classElem.length() - 1) {
-                        classElem = classElem.substring(0, classElem.length() 
-1);
-                    } else if (underscoreIndex == 0 && 
!Character.isJavaIdentifierStart(classElem.charAt(1))){
-                        classElem = classElem.substring(1);
-                    }
-                }
-            }
-            pathElements.append(classElem);
-            if (i < classElements.length - 1) {
-                pathElements.append("/");
-            }
-        }
-        Set<String> possiblePOJOPaths = 
getPossiblePojoPaths(pathElements.toString() + ".java");
-        for (String possiblePath : possiblePOJOPaths) {
-            Resource r = resolver.getResource(possiblePath);
-            if (r != null) {
-                return r;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * For a JCR path obtained from expanding a generated class name this 
method generates all the alternative path names that can be
-     * obtained by expanding the mentioned class' name.
-     *
-     * @param originalPath one of the possible paths
-     * @return a {@link Set} containing all the alternative paths if symbol 
replacement was needed; otherwise the set will contain just
-     * the {@code originalPath}
-     */
-    private static Set<String> getPossiblePojoPaths(String originalPath) {
-        Set<String> possiblePaths = new LinkedHashSet<>();
-        possiblePaths.add(originalPath);
-        Map<Integer, String> chars = new HashMap<>();
-        AmbiguousPathSymbol[] symbols = AmbiguousPathSymbol.values();
-        for (AmbiguousPathSymbol symbol : symbols) {
-            String pathCopy = originalPath.substring(0, 
originalPath.lastIndexOf("/"));
-            int actualIndex = 0;
-            boolean firstPass = true;
-            while (pathCopy.indexOf(symbol.getSymbol()) != -1) {
-                int pos = pathCopy.indexOf(symbol.getSymbol());
-                actualIndex += pos;
-                if (!firstPass) {
-                    actualIndex += 1;
-                }
-                chars.put(actualIndex, symbol.getSymbol().toString());
-                pathCopy = pathCopy.substring(pos + 1);
-                firstPass = false;
-            }
-        }
-        if (chars.size() > 0) {
-            ArrayList<AmbiguousPathSymbol[]> possibleArrangements = new 
ArrayList<>();
-            populateArray(possibleArrangements, new 
AmbiguousPathSymbol[chars.size()], 0);
-            Integer[] indexes = chars.keySet().toArray(new 
Integer[chars.size()]);
-            for (AmbiguousPathSymbol[] arrangement : possibleArrangements) {
-                char[] possiblePath = originalPath.toCharArray();
-                for (int i = 0; i < arrangement.length; i++) {
-                    char currentSymbol = arrangement[i].getSymbol();
-                    int currentIndex = indexes[i];
-                    possiblePath[currentIndex] = currentSymbol;
-                }
-                possiblePaths.add(new String(possiblePath));
-            }
-        }
-        return possiblePaths;
-    }
-
-    /**
-     * Given an initial array with its size equal to the number of elements of 
a needed arrangement, this method will generate all
-     * the possible arrangements of values for this array in the provided 
{@code arrayCollection}. The values with which the array is
-     * populated are the {@link AmbiguousPathSymbol} constants.
-     *
-     * @param arrayCollection the collection that will store the arrays
-     * @param symbolsArrangementArray an initial array that will be used for 
collecting the results
-     * @param index the initial index of the array that will be populated 
(needed for recursion purposes; start with 0 for the initial call)
-     */
-    private static void populateArray(ArrayList<AmbiguousPathSymbol[]> 
arrayCollection, AmbiguousPathSymbol[] symbolsArrangementArray, int
-            index) {
-        if (symbolsArrangementArray.length > 0) {
-            if (index == symbolsArrangementArray.length) {
-                arrayCollection.add(symbolsArrangementArray.clone());
-            } else {
-                for (AmbiguousPathSymbol symbol : 
AmbiguousPathSymbol.values()) {
-                    symbolsArrangementArray[index] = symbol;
-                    populateArray(arrayCollection, symbolsArrangementArray, 
index + 1);
-                }
-            }
-        }
-    }
-
-    /**
-     * The {@code AmbiguousPathSymbol} holds symbols that are valid for a JCR 
path but that will get transformed to a "_" to obey the
-     * Java naming conventions.
-     */
-    enum AmbiguousPathSymbol {
-        DASH('-'),
-        UNDERSCORE('_'),
-        POINT('.');
-
-        private Character symbol;
-
-        AmbiguousPathSymbol(Character symbol) {
-            this.symbol = symbol;
-        }
-
-        public Character getSymbol() {
-            return symbol;
-        }
-    }
-
 }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java
index 4ab9185..bd7d2b8 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/FormatFilterExtension.java
@@ -33,7 +33,6 @@ import java.util.regex.Pattern;
 import org.apache.commons.lang3.LocaleUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
@@ -42,7 +41,7 @@ import org.osgi.service.component.annotations.Component;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.FORMAT
+                RuntimeExtension.NAME + "=" + RuntimeExtension.FORMAT
         }
 )
 public class FormatFilterExtension implements RuntimeExtension {
@@ -60,7 +59,7 @@ public class FormatFilterExtension implements 
RuntimeExtension {
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.FORMAT, arguments, 
2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.FORMAT, arguments, 
2);
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         String source = runtimeObjectModel.toString(arguments[0]);
         Map<String, Object> options = (Map<String, Object>) arguments[1];
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
index b22b1e7..39a8236 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
@@ -30,7 +30,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.i18n.ResourceBundleProvider;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
@@ -42,7 +41,7 @@ import org.slf4j.LoggerFactory;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.I18N
+                RuntimeExtension.NAME + "=" + RuntimeExtension.I18N
         }
 )
 public class I18nRuntimeExtension implements RuntimeExtension {
@@ -51,7 +50,7 @@ public class I18nRuntimeExtension implements RuntimeExtension 
{
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.I18N, arguments, 2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.I18N, arguments, 2);
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         String text = runtimeObjectModel.toString(arguments[0]);
         Map<String, Object> options = (Map<String, Object>) arguments[1];
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java
index 27c2da8..b79dadd 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/IncludeRuntimeExtension.java
@@ -31,7 +31,6 @@ import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.api.servlets.ServletResolver;
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
@@ -46,7 +45,7 @@ import org.slf4j.LoggerFactory;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.INCLUDE
+                RuntimeExtension.NAME + "=" + RuntimeExtension.INCLUDE
         }
 )
 public class IncludeRuntimeExtension implements RuntimeExtension {
@@ -60,7 +59,7 @@ public class IncludeRuntimeExtension implements 
RuntimeExtension {
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.INCLUDE, arguments, 
2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.INCLUDE, arguments, 
2);
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         String originalPath = runtimeObjectModel.toString(arguments[0]);
         Map options = (Map) arguments[1];
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java
index b3f5bee..37b021b 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/JoinFilterExtension.java
@@ -21,7 +21,6 @@ package 
org.apache.sling.scripting.sightly.impl.engine.extension;
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
@@ -30,14 +29,14 @@ import org.osgi.service.component.annotations.Component;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.JOIN
+                RuntimeExtension.NAME + "=" + RuntimeExtension.JOIN
         }
 )
 public class JoinFilterExtension implements RuntimeExtension {
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.JOIN, arguments, 2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.JOIN, arguments, 2);
         Object joinArgument = arguments[0];
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         Collection<?> collection = 
runtimeObjectModel.toCollection(joinArgument);
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java
index 45b1f4a..3a71e13 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java
@@ -37,7 +37,6 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.SyntheticResource;
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
@@ -52,7 +51,7 @@ import org.slf4j.LoggerFactory;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.RESOURCE
+                RuntimeExtension.NAME + "=" + RuntimeExtension.RESOURCE
         }
 )
 public class ResourceRuntimeExtension implements RuntimeExtension {
@@ -70,7 +69,7 @@ public class ResourceRuntimeExtension implements 
RuntimeExtension {
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.RESOURCE, arguments, 
2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.RESOURCE, 
arguments, 2);
         return provideResource(renderContext, arguments[0], (Map<String, 
Object>) arguments[1]);
     }
 
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java
index e5a6b03..7ce8354 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/URIManipulationFilterExtension.java
@@ -36,7 +36,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.request.RequestPathInfo;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
@@ -48,7 +47,7 @@ import org.slf4j.LoggerFactory;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.URI_MANIPULATION
+                RuntimeExtension.NAME + "=" + RuntimeExtension.URI_MANIPULATION
         }
 )
 public class URIManipulationFilterExtension implements RuntimeExtension {
@@ -75,7 +74,7 @@ public class URIManipulationFilterExtension implements 
RuntimeExtension {
     @Override
     @SuppressWarnings("unchecked")
     public Object call(RenderContext renderContext, Object... arguments) {
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.URI_MANIPULATION, 
arguments, 2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.URI_MANIPULATION, 
arguments, 2);
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         String uriString = runtimeObjectModel.toString(arguments[0]);
         Map<String, Object> options = runtimeObjectModel.toMap(arguments[1]);
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java
index a56c825..40d78bb 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/XSSRuntimeExtension.java
@@ -18,19 +18,18 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.engine.extension;
 
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
-import org.apache.sling.scripting.sightly.compiler.expression.MarkupContext;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.xss.XSSAPI;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,12 +39,12 @@ import org.slf4j.LoggerFactory;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.XSS
+                RuntimeExtension.NAME + "=" + RuntimeExtension.XSS
         }
 )
 public class XSSRuntimeExtension implements RuntimeExtension {
 
-    @Reference(policyOption = ReferencePolicyOption.GREEDY)
+    @Reference
     private XSSAPI xssApi;
 
     private static final Set<String> elementNameWhiteList = new HashSet<>();
@@ -57,7 +56,7 @@ public class XSSRuntimeExtension implements RuntimeExtension {
     public Object call(final RenderContext renderContext, Object... arguments) 
{
         if (arguments.length < 2) {
             throw new SightlyException(
-                    String.format("Extension %s requires at least %d 
arguments", RuntimeFunction.XSS, 2));
+                    String.format("Extension %s requires at least %d 
arguments", RuntimeExtension.XSS, 2));
         }
         Object original = arguments[0];
         Object option = arguments[1];
@@ -237,4 +236,53 @@ public class XSSRuntimeExtension implements 
RuntimeExtension {
     private boolean isSensitiveAttribute(String name) {
         return ATTRIBUTE_BLACKLIST.matcher(name).matches();
     }
+
+    private enum MarkupContext {
+
+        HTML("html"),
+        TEXT("text"),
+        ELEMENT_NAME("elementName"),
+        ATTRIBUTE_NAME("attributeName"),
+        ATTRIBUTE("attribute"),
+        URI("uri"),
+        SCRIPT_TOKEN("scriptToken"),
+        SCRIPT_STRING("scriptString"),
+        SCRIPT_COMMENT("scriptComment"),
+        SCRIPT_REGEXP("scriptRegExp"),
+        STYLE_TOKEN("styleToken"),
+        STYLE_STRING("styleString"),
+        STYLE_COMMENT("styleComment"),
+        COMMENT("comment"),
+        NUMBER("number"),
+        UNSAFE("unsafe");
+
+        private final String name;
+
+        MarkupContext(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Returns the render context with the given name.
+         *
+         * @param name the name of the render context
+         * @return the rendering context value or {@code null} if the name 
matches no value
+         */
+        static MarkupContext lookup(String name) {
+            return reverseMap.get(name);
+        }
+
+        private static final Map<String, MarkupContext> reverseMap = new 
HashMap<>();
+
+        static {
+            for (MarkupContext markupContext : MarkupContext.values()) {
+                reverseMap.put(markupContext.getName(), markupContext);
+            }
+        }
+    }
+
 }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
index e85a2fd..1cb5919 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
@@ -21,7 +21,7 @@ package 
org.apache.sling.scripting.sightly.impl.engine.extension.use;
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.regex.Pattern;
+
 import javax.script.Bindings;
 import javax.servlet.ServletRequest;
 
@@ -29,8 +29,7 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.adapter.Adaptable;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.scripting.SlingScriptHelper;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import 
org.apache.sling.scripting.sightly.impl.engine.SightlyJavaCompilerService;
+import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SlingHTLMasterCompiler;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.impl.utils.Patterns;
 import org.apache.sling.scripting.sightly.pojo.Use;
@@ -40,6 +39,8 @@ import org.apache.sling.scripting.sightly.use.UseProvider;
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,14 +65,11 @@ public class JavaUseProvider implements UseProvider {
 
     }
 
-    public static final String ADAPTABLE = "adaptable";
+    private static final String ADAPTABLE = "adaptable";
     private static final Logger LOG = 
LoggerFactory.getLogger(JavaUseProvider.class);
 
-    @Reference
-    private SightlyJavaCompilerService sightlyJavaCompilerService = null;
-
-    @Reference
-    private ClassLoaderWriter classLoaderWriter = null;
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = 
ReferencePolicyOption.GREEDY)
+    private SlingHTLMasterCompiler slingHTLMasterCompiler;
 
     @Override
     public ProviderOutcome provide(String identifier, RenderContext 
renderContext, Bindings arguments) {
@@ -84,9 +82,11 @@ public class JavaUseProvider implements UseProvider {
         SlingHttpServletRequest request = 
BindingsUtils.getRequest(globalBindings);
         Map<String, Object> overrides = setRequestAttributes(request, 
arguments);
 
-        Object result;
+        Object result = null;
         try {
-            result = 
sightlyJavaCompilerService.getResourceBackedUseObject(renderContext, 
identifier);
+            if (slingHTLMasterCompiler != null) {
+                result = 
slingHTLMasterCompiler.getResourceBackedUseObject(renderContext, identifier);
+            }
             if (result != null) {
                 if (result instanceof Use) {
                     ((Use) result).init(BindingsUtils.merge(globalBindings, 
arguments));
@@ -94,41 +94,50 @@ public class JavaUseProvider implements UseProvider {
                 return ProviderOutcome.success(result);
             } else {
                 LOG.debug("Attempting to load class {} from the classloader 
cache.", identifier);
-                Class<?> cls = 
classLoaderWriter.getClassLoader().loadClass(identifier);
-                // attempt OSGi service load
-                result = sling.getService(cls);
-                if (result != null) {
-                    return ProviderOutcome.success(result);
+                ClassLoader classLoader = null;
+                if (slingHTLMasterCompiler != null) {
+                    classLoader = slingHTLMasterCompiler.getClassLoader();
                 }
-                Object adaptableCandidate = arguments.get(ADAPTABLE);
-                if (adaptableCandidate != null && adaptableCandidate 
instanceof Adaptable) {
-                    Adaptable adaptable = (Adaptable) adaptableCandidate;
-                    result = adaptable.adaptTo(cls);
+
+                // attempt OSGi service load
+                if (classLoader != null) {
+                    Class<?> cls = classLoader.loadClass(identifier);
+
+                    result = sling.getService(cls);
                     if (result != null) {
                         return ProviderOutcome.success(result);
                     }
-                }
-                result = request.adaptTo(cls);
-                if (result == null) {
-                    Resource resource = 
BindingsUtils.getResource(globalBindings);
-                    result = resource.adaptTo(cls);
-                }
-                if (result != null) {
-                    return ProviderOutcome.success(result);
-                } else if(cls.isInterface() || 
Modifier.isAbstract(cls.getModifiers())){
-                    LOG.debug("Wont attempt to instantiate an interface or 
abstract class {}",cls.getName());
-                    return ProviderOutcome.failure();
-                } else {
-                    /*
-                     * the object was cached by the class loader but it's not 
adaptable from {@link Resource} or {@link
-                     * SlingHttpServletRequest}; attempt to load it like a 
regular POJO that optionally could implement {@link Use}
-                     */
-                    result = cls.newInstance();
-                    if (result instanceof Use) {
-                        ((Use) 
result).init(BindingsUtils.merge(globalBindings, arguments));
+                    Object adaptableCandidate = arguments.get(ADAPTABLE);
+                    if (adaptableCandidate instanceof Adaptable) {
+                        Adaptable adaptable = (Adaptable) adaptableCandidate;
+                        result = adaptable.adaptTo(cls);
+                        if (result != null) {
+                            return ProviderOutcome.success(result);
+                        }
+                    }
+                    result = request.adaptTo(cls);
+                    if (result == null) {
+                        Resource resource = 
BindingsUtils.getResource(globalBindings);
+                        result = resource.adaptTo(cls);
+                    }
+                    if (result != null) {
+                        return ProviderOutcome.success(result);
+                    } else if (cls.isInterface() || 
Modifier.isAbstract(cls.getModifiers())) {
+                        LOG.debug("Wont attempt to instantiate an interface or 
abstract class {}", cls.getName());
+                        return ProviderOutcome.failure();
+                    } else {
+                        /*
+                         * the object was cached by the class loader but it's 
not adaptable from {@link Resource} or {@link
+                         * SlingHttpServletRequest}; attempt to load it like a 
regular POJO that optionally could implement {@link Use}
+                         */
+                        result = cls.newInstance();
+                        if (result instanceof Use) {
+                            ((Use) 
result).init(BindingsUtils.merge(globalBindings, arguments));
+                        }
+                        return ProviderOutcome.notNullOrFailure(result);
                     }
-                    return ProviderOutcome.notNullOrFailure(result);
                 }
+                return ProviderOutcome.failure();
             }
         } catch (Exception e) {
             // any other exception is an error
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
index 0008251..df29230 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/RenderUnitProvider.java
@@ -41,8 +41,8 @@ import 
org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngine;
 import 
org.apache.sling.scripting.sightly.impl.engine.SightlyScriptEngineFactory;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.impl.utils.ScriptUtils;
-import org.apache.sling.scripting.sightly.java.compiler.RenderUnit;
 import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RenderUnit;
 import org.apache.sling.scripting.sightly.use.ProviderOutcome;
 import org.apache.sling.scripting.sightly.use.UseProvider;
 import org.osgi.framework.Constants;
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
index 4d7789a..242228b 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/UseRuntimeExtension.java
@@ -29,7 +29,6 @@ import javax.script.SimpleBindings;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.scripting.sightly.SightlyException;
-import org.apache.sling.scripting.sightly.compiler.RuntimeFunction;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.impl.engine.extension.ExtensionUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
@@ -49,7 +48,7 @@ import org.osgi.service.component.annotations.ReferencePolicy;
 @Component(
         service = RuntimeExtension.class,
         property = {
-                RuntimeExtension.NAME + "=" + RuntimeFunction.USE
+                RuntimeExtension.NAME + "=" + RuntimeExtension.USE
         }
 )
 public class UseRuntimeExtension implements RuntimeExtension {
@@ -58,7 +57,7 @@ public class UseRuntimeExtension implements RuntimeExtension {
 
     @Override
     public Object call(final RenderContext renderContext, Object... arguments) 
{
-        ExtensionUtils.checkArgumentCount(RuntimeFunction.USE, arguments, 2);
+        ExtensionUtils.checkArgumentCount(RuntimeExtension.USE, arguments, 2);
         RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
         String identifier = runtimeObjectModel.toString(arguments[0]);
         if (StringUtils.isEmpty(identifier)) {
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
index e70d6e4..605b8e7 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/runtime/RenderContextImpl.java
@@ -19,16 +19,19 @@
 package org.apache.sling.scripting.sightly.impl.engine.runtime;
 
 import java.util.Map;
+
 import javax.script.Bindings;
 import javax.script.ScriptContext;
 
+import org.apache.sling.api.scripting.SlingScriptConstants;
 import org.apache.sling.scripting.sightly.SightlyException;
 import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
 import org.apache.sling.scripting.sightly.impl.engine.ExtensionRegistryService;
-import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
 import org.apache.sling.scripting.sightly.render.AbstractRuntimeObjectModel;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.wiring.BundleWiring;
 
 /**
  * Rendering context for HTL rendering units.
@@ -40,9 +43,14 @@ public class RenderContextImpl implements RenderContext {
     private final Bindings bindings;
     private final ExtensionRegistryService extensionRegistryService;
 
-    public RenderContextImpl(ScriptContext scriptContext) {
+    public RenderContextImpl(ExtensionRegistryService 
extensionRegistryService, ScriptContext scriptContext) {
+        this.extensionRegistryService = extensionRegistryService;
         bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
-        extensionRegistryService = 
BindingsUtils.getHelper(bindings).getService(ExtensionRegistryService.class);
+        Bundle scriptProvidingBundle = (Bundle) 
scriptContext.getAttribute("org.apache.sling.scripting.resolver.provider.bundle",
+                SlingScriptConstants.SLING_SCOPE);
+        if (scriptProvidingBundle != null) {
+            
bindings.put("org.apache.sling.scripting.sightly.render_unit.loader", 
scriptProvidingBundle.adapt(BundleWiring.class).getClassLoader());
+        }
     }
 
     @Override
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
deleted file mode 100644
index 98671d6..0000000
--- 
a/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
+++ /dev/null
@@ -1,189 +0,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.
- 
******************************************************************************/
-package org.apache.sling.scripting.sightly.impl.compiler;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceMetadata;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import org.apache.sling.commons.compiler.CompilationResult;
-import org.apache.sling.commons.compiler.CompilationUnit;
-import org.apache.sling.commons.compiler.CompilerMessage;
-import org.apache.sling.commons.compiler.JavaCompiler;
-import org.apache.sling.commons.compiler.Options;
-import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
-import 
org.apache.sling.scripting.sightly.impl.engine.ResourceBackedPojoChangeMonitor;
-import 
org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
-import 
org.apache.sling.scripting.sightly.impl.engine.SightlyJavaCompilerService;
-import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier;
-import 
org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.powermock.reflect.Whitebox;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.*;
-
-public class SightlyJavaCompilerServiceTest {
-
-    private SightlyJavaCompilerService compiler;
-    private ResourceBackedPojoChangeMonitor resourceBackedPojoChangeMonitor;
-    private ClassLoaderWriter classLoaderWriter;
-    private ScriptingResourceResolverProvider 
scriptingResourceResolverProvider;
-
-    @Before
-    public void setUp() throws Exception {
-        compiler = spy(new SightlyJavaCompilerService());
-        resourceBackedPojoChangeMonitor = spy(new 
ResourceBackedPojoChangeMonitor());
-        SightlyEngineConfiguration sightlyEngineConfiguration = 
mock(SightlyEngineConfiguration.class);
-        
when(sightlyEngineConfiguration.getBundleSymbolicName()).thenReturn("org.apache.sling.scripting.sightly");
-        
when(sightlyEngineConfiguration.getScratchFolder()).thenReturn("/org/apache/sling/scripting/sightly");
-        Whitebox.setInternalState(compiler, "sightlyEngineConfiguration", 
sightlyEngineConfiguration);
-        Whitebox.setInternalState(compiler, "resourceBackedPojoChangeMonitor", 
resourceBackedPojoChangeMonitor);
-        classLoaderWriter = Mockito.mock(ClassLoaderWriter.class);
-        ClassLoader classLoader = Mockito.mock(ClassLoader.class);
-        when(classLoaderWriter.getClassLoader()).thenReturn(classLoader);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        compiler = null;
-        resourceBackedPojoChangeMonitor = null;
-        classLoaderWriter = null;
-    }
-
-    @Test
-    public void testDiskCachedUseObject() throws Exception {
-        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
-        String className = "apps.myproject.testcomponents.a.Pojo";
-        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
-        Resource pojoResource = Mockito.mock(Resource.class);
-        when(pojoResource.getPath()).thenReturn(pojoPath);
-        ResourceMetadata mockMetadata = Mockito.mock(ResourceMetadata.class);
-        when(mockMetadata.getModificationTime()).thenReturn(1l);
-        when(pojoResource.getResourceMetadata()).thenReturn(mockMetadata);
-        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
-        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
-        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(2l);
-        getInstancePojoTest(className);
-        /*
-         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
-         * object
-         */
-        verify(compiler, never()).compileSource(any(SourceIdentifier.class), 
anyString());
-    }
-
-    @Test
-    public void testObsoleteDiskCachedUseObject() throws Exception {
-        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
-        String className = "apps.myproject.testcomponents.a.Pojo";
-        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
-        Resource pojoResource = Mockito.mock(Resource.class);
-        when(pojoResource.getPath()).thenReturn(pojoPath);
-        ResourceMetadata mockMetadata = Mockito.mock(ResourceMetadata.class);
-        when(mockMetadata.getModificationTime()).thenReturn(2l);
-        when(pojoResource.getResourceMetadata()).thenReturn(mockMetadata);
-        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
-        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
-        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(1l);
-        getInstancePojoTest(className);
-        /*
-         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
-         * object
-         */
-        verify(compiler).compileSource(any(SourceIdentifier.class), 
anyString());
-    }
-
-    @Test
-    public void testMemoryCachedUseObject() throws Exception {
-        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
-        String className = "apps.myproject.testcomponents.a.Pojo";
-        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
-        Resource pojoResource = Mockito.mock(Resource.class);
-        when(pojoResource.getPath()).thenReturn(pojoPath);
-        
when(resourceBackedPojoChangeMonitor.getLastModifiedDateForJavaUseObject(pojoPath)).thenReturn(1l);
-        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
-        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
-        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(2l);
-        getInstancePojoTest(className);
-        /*
-         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
-         * object
-         */
-        verify(compiler, never()).compileSource(any(SourceIdentifier.class), 
anyString());
-    }
-
-    @Test
-    public void testObsoleteMemoryCachedUseObject() throws Exception {
-        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
-        String className = "apps.myproject.testcomponents.a.Pojo";
-        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
-        Resource pojoResource = Mockito.mock(Resource.class);
-        when(pojoResource.getPath()).thenReturn(pojoPath);
-        
when(resourceBackedPojoChangeMonitor.getLastModifiedDateForJavaUseObject(pojoPath)).thenReturn(2l);
-        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
-        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
-        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(1l);
-        getInstancePojoTest(className);
-        /*
-         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
-         * object
-         */
-        verify(compiler).compileSource(any(SourceIdentifier.class), 
anyString());
-    }
-
-    private void getInstancePojoTest(String className) throws Exception {
-        RenderContextImpl renderContext = 
Mockito.mock(RenderContextImpl.class);
-
-
-        JavaCompiler javaCompiler = Mockito.mock(JavaCompiler.class);
-        CompilationResult compilationResult = 
Mockito.mock(CompilationResult.class);
-        when(compilationResult.getErrors()).thenReturn(new 
ArrayList<CompilerMessage>());
-        when(javaCompiler.compile(Mockito.any(CompilationUnit[].class), 
Mockito.any(Options.class))).thenReturn(compilationResult);
-        
when(classLoaderWriter.getClassLoader().loadClass(className)).thenAnswer(new 
Answer<Object>() {
-            @Override
-            public Object answer(InvocationOnMock invocation) throws Throwable 
{
-                return MockPojo.class;
-            }
-        });
-        Whitebox.setInternalState(compiler, "classLoaderWriter", 
classLoaderWriter);
-        Whitebox.setInternalState(compiler, "javaCompiler", javaCompiler);
-        Whitebox.setInternalState(compiler, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
-        Object obj = compiler.getResourceBackedUseObject(renderContext, 
className);
-        assertTrue("Expected to obtain a " + MockPojo.class.getName() + " 
object.", obj instanceof MockPojo);
-    }
-}
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScriptTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScriptTest.java
index 00cbf51..9fc3b03 100644
--- 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScriptTest.java
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyCompiledScriptTest.java
@@ -29,7 +29,7 @@ import javax.script.SimpleBindings;
 
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.scripting.sightly.java.compiler.RenderUnit;
+import org.apache.sling.scripting.sightly.render.RenderUnit;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -55,8 +55,8 @@ public class SightlyCompiledScriptTest {
      * @throws ScriptException
      */
     @Test
-    public void testEvalSlingBindings() throws ScriptException {
-        ScriptEngine scriptEngine = mock(ScriptEngine.class);
+    public void testEvalSlingBindings() {
+        SightlyScriptEngine scriptEngine = mock(SightlyScriptEngine.class);
         final RenderUnit renderUnit = mock(RenderUnit.class);
         Whitebox.setInternalState(renderUnit, "subTemplates", new 
HashMap<String, Object>());
         final BundleContext bundleContext = MockOsgi.newBundleContext();
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactoryTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactoryTest.java
deleted file mode 100644
index 79755ca..0000000
--- 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/SightlyScriptEngineFactoryTest.java
+++ /dev/null
@@ -1,121 +0,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.
- 
******************************************************************************/
-package org.apache.sling.scripting.sightly.impl.engine;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.commons.classloader.ClassLoaderWriter;
-import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.powermock.reflect.Whitebox;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SightlyScriptEngineFactoryTest {
-
-    private SightlyEngineConfiguration sightlyEngineConfiguration;
-    private ScriptingResourceResolverProvider 
scriptingResourceResolverProvider;
-
-    @Before
-    public void setUp() {
-        sightlyEngineConfiguration = mock(SightlyEngineConfiguration.class);
-        
when(sightlyEngineConfiguration.getEngineVersion()).thenReturn("1.0.17-SNAPSHOT");
-        
when(sightlyEngineConfiguration.getScratchFolder()).thenReturn("/org/apache/sling/scripting/sightly");
-
-        ResourceResolver scriptingResourceResolver = 
mock(ResourceResolver.class);
-        scriptingResourceResolverProvider = 
mock(ScriptingResourceResolverProvider.class);
-        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(scriptingResourceResolver);
-        when(scriptingResourceResolver.getSearchPath()).thenReturn(new 
String[] {"/apps", "/libs"});
-    }
-
-    @After
-    public void tearDown() {
-        sightlyEngineConfiguration = null;
-    }
-
-    @Test
-    public void testActivateNoPreviousInfo() {
-        SightlyScriptEngineFactory scriptEngineFactory = new 
SightlyScriptEngineFactory();
-        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        
when(classLoaderWriter.getOutputStream(SightlyScriptEngineFactory.SIGHTLY_CONFIG_FILE)).thenReturn(outputStream);
-        Whitebox.setInternalState(scriptEngineFactory, "classLoaderWriter", 
classLoaderWriter);
-        Whitebox.setInternalState(scriptEngineFactory, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
-        Whitebox.setInternalState(scriptEngineFactory, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
-        scriptEngineFactory.activate();
-        
verify(classLoaderWriter).delete(sightlyEngineConfiguration.getScratchFolder());
-        assertEquals("1.0.17-SNAPSHOT", outputStream.toString());
-    }
-
-    @Test
-    public void testActivateOverPreviousVersion()  {
-        SightlyScriptEngineFactory scriptEngineFactory = new 
SightlyScriptEngineFactory();
-        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
-        try {
-            
when(classLoaderWriter.getInputStream(SightlyScriptEngineFactory.SIGHTLY_CONFIG_FILE))
-                    .thenReturn(IOUtils.toInputStream("1.0.16", "UTF-8"));
-        } catch (IOException e) {
-            fail("IOException while setting tests.");
-        }
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        
when(classLoaderWriter.getOutputStream(SightlyScriptEngineFactory.SIGHTLY_CONFIG_FILE)).thenReturn(outputStream);
-        
when(classLoaderWriter.delete(sightlyEngineConfiguration.getScratchFolder())).thenReturn(true);
-        Whitebox.setInternalState(scriptEngineFactory, "classLoaderWriter", 
classLoaderWriter);
-        Whitebox.setInternalState(scriptEngineFactory, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
-        Whitebox.setInternalState(scriptEngineFactory, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
-        scriptEngineFactory.activate();
-        
verify(classLoaderWriter).delete(sightlyEngineConfiguration.getScratchFolder());
-        assertEquals("1.0.17-SNAPSHOT", outputStream.toString());
-    }
-
-    @Test
-    public void testActivateOverSameVersion() {
-        SightlyScriptEngineFactory scriptEngineFactory = new 
SightlyScriptEngineFactory();
-        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
-        try {
-            
when(classLoaderWriter.getInputStream(SightlyScriptEngineFactory.SIGHTLY_CONFIG_FILE))
-                    .thenReturn(IOUtils.toInputStream("1.0.17-SNAPSHOT", 
"UTF-8"));
-        } catch (IOException e) {
-            fail("IOException while setting tests.");
-        }
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream spyOutputStream = spy(outputStream);
-        
when(classLoaderWriter.getOutputStream(SightlyScriptEngineFactory.SIGHTLY_CONFIG_FILE)).thenReturn(spyOutputStream);
-        Whitebox.setInternalState(scriptEngineFactory, "classLoaderWriter", 
classLoaderWriter);
-        Whitebox.setInternalState(scriptEngineFactory, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
-        Whitebox.setInternalState(scriptEngineFactory, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
-        scriptEngineFactory.activate();
-        verify(classLoaderWriter, 
never()).delete(sightlyEngineConfiguration.getScratchFolder());
-        try {
-            verify(spyOutputStream, never()).write(any(byte[].class));
-            verify(spyOutputStream, never()).close();
-        } catch (IOException e) {
-            fail("IOException in test verification.");
-        }
-    }
-}
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SlingHTLMasterCompilerTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SlingHTLMasterCompilerTest.java
new file mode 100644
index 0000000..ed85dca
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SlingHTLMasterCompilerTest.java
@@ -0,0 +1,296 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.scripting.sightly.impl.engine.compiled;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.classloader.ClassLoaderWriter;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilationUnit;
+import org.apache.sling.commons.compiler.CompilerMessage;
+import org.apache.sling.commons.compiler.JavaCompiler;
+import org.apache.sling.commons.compiler.Options;
+import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
+import org.apache.sling.scripting.sightly.impl.compiler.MockPojo;
+import 
org.apache.sling.scripting.sightly.impl.engine.ResourceBackedPojoChangeMonitor;
+import 
org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
+import 
org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.reflect.Whitebox;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SlingHTLMasterCompilerTest {
+
+    private SightlyEngineConfiguration sightlyEngineConfiguration;
+    private ScriptingResourceResolverProvider 
scriptingResourceResolverProvider;
+    private SlingHTLMasterCompiler compiler;
+    private JavaCompiler javaCompiler;
+    private ResourceBackedPojoChangeMonitor resourceBackedPojoChangeMonitor;
+    private ClassLoaderWriter classLoaderWriter;
+
+    @Before
+    public void setUp() {
+        sightlyEngineConfiguration = mock(SightlyEngineConfiguration.class);
+        
when(sightlyEngineConfiguration.getBundleSymbolicName()).thenReturn("org.apache.sling.scripting.sightly");
+        
when(sightlyEngineConfiguration.getEngineVersion()).thenReturn("1.0.17-SNAPSHOT");
+        
when(sightlyEngineConfiguration.getScratchFolder()).thenReturn("/org/apache/sling/scripting/sightly");
+
+        ResourceResolver scriptingResourceResolver = 
mock(ResourceResolver.class);
+        scriptingResourceResolverProvider = 
mock(ScriptingResourceResolverProvider.class);
+        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(scriptingResourceResolver);
+        when(scriptingResourceResolver.getSearchPath()).thenReturn(new 
String[] {"/apps", "/libs"});
+
+        compiler = spy(new SlingHTLMasterCompiler());
+        javaCompiler = mock(JavaCompiler.class);
+
+        resourceBackedPojoChangeMonitor = spy(new 
ResourceBackedPojoChangeMonitor());
+
+        Whitebox.setInternalState(compiler, "sightlyEngineConfiguration", 
sightlyEngineConfiguration);
+        Whitebox.setInternalState(compiler, "resourceBackedPojoChangeMonitor", 
resourceBackedPojoChangeMonitor);
+        Whitebox.setInternalState(compiler, "javaCompiler", javaCompiler);
+        classLoaderWriter = Mockito.mock(ClassLoaderWriter.class);
+        ClassLoader classLoader = Mockito.mock(ClassLoader.class);
+        when(classLoaderWriter.getClassLoader()).thenReturn(classLoader);
+    }
+
+    @After
+    public void tearDown() {
+        sightlyEngineConfiguration = null;
+        compiler = null;
+        resourceBackedPojoChangeMonitor = null;
+        classLoaderWriter = null;
+    }
+
+    @Test
+    public void testActivateNoPreviousInfo() {
+        SlingHTLMasterCompiler slingHTLMasterCompiler = new 
SlingHTLMasterCompiler();
+        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        
when(classLoaderWriter.getOutputStream(SlingHTLMasterCompiler.SIGHTLY_CONFIG_FILE)).thenReturn(outputStream);
+        Whitebox.setInternalState(slingHTLMasterCompiler, "classLoaderWriter", 
classLoaderWriter);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
+        slingHTLMasterCompiler.activate();
+        
verify(classLoaderWriter).delete(sightlyEngineConfiguration.getScratchFolder());
+        assertEquals("1.0.17-SNAPSHOT", outputStream.toString());
+    }
+
+    @Test
+    public void testActivateOverPreviousVersion()  {
+        SlingHTLMasterCompiler slingHTLMasterCompiler = new 
SlingHTLMasterCompiler();
+        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
+        try {
+            
when(classLoaderWriter.getInputStream(SlingHTLMasterCompiler.SIGHTLY_CONFIG_FILE))
+                    .thenReturn(IOUtils.toInputStream("1.0.16", "UTF-8"));
+        } catch (IOException e) {
+            fail("IOException while setting tests.");
+        }
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        
when(classLoaderWriter.getOutputStream(SlingHTLMasterCompiler.SIGHTLY_CONFIG_FILE)).thenReturn(outputStream);
+        
when(classLoaderWriter.delete(sightlyEngineConfiguration.getScratchFolder())).thenReturn(true);
+        Whitebox.setInternalState(slingHTLMasterCompiler, "classLoaderWriter", 
classLoaderWriter);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
+        slingHTLMasterCompiler.activate();
+        
verify(classLoaderWriter).delete(sightlyEngineConfiguration.getScratchFolder());
+        assertEquals("1.0.17-SNAPSHOT", outputStream.toString());
+    }
+
+    @Test
+    public void testActivateOverSameVersion() {
+        SlingHTLMasterCompiler slingHTLMasterCompiler = new 
SlingHTLMasterCompiler();
+        ClassLoaderWriter classLoaderWriter = mock(ClassLoaderWriter.class);
+        try {
+            
when(classLoaderWriter.getInputStream(SlingHTLMasterCompiler.SIGHTLY_CONFIG_FILE))
+                    .thenReturn(IOUtils.toInputStream("1.0.17-SNAPSHOT", 
"UTF-8"));
+        } catch (IOException e) {
+            fail("IOException while setting tests.");
+        }
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ByteArrayOutputStream spyOutputStream = spy(outputStream);
+        
when(classLoaderWriter.getOutputStream(SlingHTLMasterCompiler.SIGHTLY_CONFIG_FILE)).thenReturn(spyOutputStream);
+        Whitebox.setInternalState(slingHTLMasterCompiler, "classLoaderWriter", 
classLoaderWriter);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"sightlyEngineConfiguration", sightlyEngineConfiguration);
+        Whitebox.setInternalState(slingHTLMasterCompiler, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
+        slingHTLMasterCompiler.activate();
+        verify(classLoaderWriter, 
never()).delete(sightlyEngineConfiguration.getScratchFolder());
+        try {
+            verify(spyOutputStream, never()).write(any(byte[].class));
+            verify(spyOutputStream, never()).close();
+        } catch (IOException e) {
+            fail("IOException in test verification.");
+        }
+    }
+
+    @Test
+    public void testDiskCachedUseObject() throws Exception {
+        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
+        String className = "apps.myproject.testcomponents.a.Pojo";
+        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
+        Resource pojoResource = Mockito.mock(Resource.class);
+        when(pojoResource.getPath()).thenReturn(pojoPath);
+        ResourceMetadata mockMetadata = Mockito.mock(ResourceMetadata.class);
+        when(mockMetadata.getModificationTime()).thenReturn(1L);
+        when(pojoResource.getResourceMetadata()).thenReturn(mockMetadata);
+        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
+        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
+        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(2L);
+        getInstancePojoTest(className);
+        /*
+         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
+         * object
+         */
+        verify(javaCompiler, never()).compile(any(CompilationUnit[].class), 
any(Options.class));
+    }
+
+    @Test
+    public void testObsoleteDiskCachedUseObject() throws Exception {
+        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
+        String className = "apps.myproject.testcomponents.a.Pojo";
+        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
+        Resource pojoResource = Mockito.mock(Resource.class);
+        when(pojoResource.getPath()).thenReturn(pojoPath);
+        ResourceMetadata mockMetadata = Mockito.mock(ResourceMetadata.class);
+        when(mockMetadata.getModificationTime()).thenReturn(2L);
+        when(pojoResource.getResourceMetadata()).thenReturn(mockMetadata);
+        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
+        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
+        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(1L);
+        getInstancePojoTest(className);
+        /*
+         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
+         * object
+         */
+        verify(compiler).getResourceBackedUseObject(any(RenderContext.class), 
anyString());
+    }
+
+    @Test
+    public void testMemoryCachedUseObject() throws Exception {
+        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
+        String className = "apps.myproject.testcomponents.a.Pojo";
+        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
+        Resource pojoResource = Mockito.mock(Resource.class);
+        when(pojoResource.getPath()).thenReturn(pojoPath);
+        
when(resourceBackedPojoChangeMonitor.getLastModifiedDateForJavaUseObject(pojoPath)).thenReturn(1L);
+        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
+        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
+        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(2L);
+        getInstancePojoTest(className);
+        /*
+         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
+         * object
+         */
+        verify(javaCompiler, never()).compile(any(CompilationUnit[].class), 
any(Options.class));
+    }
+
+    @Test
+    public void testObsoleteMemoryCachedUseObject() throws Exception {
+        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
+        String className = "apps.myproject.testcomponents.a.Pojo";
+        scriptingResourceResolverProvider = 
Mockito.mock(ScriptingResourceResolverProvider.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        
when(scriptingResourceResolverProvider.getRequestScopedResourceResolver()).thenReturn(resolver);
+        Resource pojoResource = Mockito.mock(Resource.class);
+        when(pojoResource.getPath()).thenReturn(pojoPath);
+        
when(resourceBackedPojoChangeMonitor.getLastModifiedDateForJavaUseObject(pojoPath)).thenReturn(2L);
+        
when(pojoResource.adaptTo(InputStream.class)).thenReturn(IOUtils.toInputStream("DUMMY",
 "UTF-8"));
+        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
+        
when(classLoaderWriter.getLastModified("/apps/myproject/testcomponents/a/Pojo.class")).thenReturn(1L);
+        getInstancePojoTest(className);
+        /*
+         * assuming the compiled class has a last modified date greater than 
the source, then the compiler should not recompile the Use
+         * object
+         */
+        verify(javaCompiler, times(1)).compile(any(CompilationUnit[].class), 
any(Options.class));
+    }
+
+    @Test
+    public void testGetPOJOFromFQCN() {
+        Map<String, String> expectedScriptNames = new HashMap<String, 
String>() {{
+            put("/apps/a_b_c/d_e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d.e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d-e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d.e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d-e-f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a/b/c/Pojo.java", "apps.a.b.c.Pojo");
+        }};
+        for (Map.Entry<String, String> scriptEntry : 
expectedScriptNames.entrySet()) {
+            ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+            Resource resource = Mockito.mock(Resource.class);
+            when(resource.getPath()).thenReturn(scriptEntry.getKey());
+            
when(resolver.getResource(scriptEntry.getKey())).thenReturn(resource);
+            Resource result = compiler.getPOJOFromFQCN(resolver, 
scriptEntry.getValue());
+            assertNotNull(
+                    String.format("ResourceResolver was expected to find 
resource %s for POJO %s. Got null instead.", scriptEntry.getKey(),
+                            scriptEntry.getValue()), result);
+            assertEquals(scriptEntry.getKey(), result.getPath());
+        }
+    }
+
+    private void getInstancePojoTest(String className) throws Exception {
+        RenderContextImpl renderContext = 
Mockito.mock(RenderContextImpl.class);
+        CompilationResult compilationResult = 
Mockito.mock(CompilationResult.class);
+        when(compilationResult.getErrors()).thenReturn(new 
ArrayList<CompilerMessage>());
+        when(javaCompiler.compile(Mockito.any(CompilationUnit[].class), 
Mockito.any(Options.class))).thenReturn(compilationResult);
+        
when(classLoaderWriter.getClassLoader().loadClass(className)).thenAnswer(new 
Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocation) {
+                return MockPojo.class;
+            }
+        });
+        Whitebox.setInternalState(compiler, "classLoaderWriter", 
classLoaderWriter);
+        Whitebox.setInternalState(compiler, "javaCompiler", javaCompiler);
+        Whitebox.setInternalState(compiler, 
"scriptingResourceResolverProvider", scriptingResourceResolverProvider);
+        Object obj = compiler.getResourceBackedUseObject(renderContext, 
className);
+        assertTrue("Expected to obtain a " + MockPojo.class.getName() + " 
object.", obj instanceof MockPojo);
+    }
+}
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
index 15e46d2..870652e 100644
--- 
a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
@@ -35,48 +35,25 @@ public class SourceIdentifierTest {
     private static final String BUNDLE_SYMBOLIC_NAME = 
"org.apache.sling.scripting.sightly";
 
     @Test
-    public void testGetClassName() throws Exception {
+    public void testGetClassName() {
         SourceIdentifier sourceIdentifier = 
getSourceIdentifier("/apps/blah/static/foo/foo.html");
         assertEquals("foo_html", sourceIdentifier.getSimpleClassName());
     }
 
     @Test
-    public void testGetPackageName() throws Exception {
+    public void testGetPackageName() {
         SourceIdentifier sourceIdentifier = 
getSourceIdentifier("/apps/blah/static/foo/foo.html");
         assertEquals(BUNDLE_SYMBOLIC_NAME + ".apps.blah.static_.foo", 
sourceIdentifier.getPackageName());
     }
 
     @Test
-    public void testGetFullyQualifiedName() throws Exception {
+    public void testGetFullyQualifiedName() {
         SourceIdentifier sourceIdentifier = 
getSourceIdentifier("/apps/blah/static/foo/foo.html");
         assertEquals(BUNDLE_SYMBOLIC_NAME + ".apps.blah.static_.foo.foo_html", 
sourceIdentifier.getPackageName() + "." +
                 sourceIdentifier.getSimpleClassName());
     }
 
     @Test
-    public void testGetPOJOFromFQCN() {
-        Map<String, String> expectedScriptNames = new HashMap<String, 
String>() {{
-            put("/apps/a_b_c/d_e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
-            put("/apps/a-b-c/d.e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
-            put("/apps/a-b-c/d-e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
-            put("/apps/a-b-c/d.e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
-            put("/apps/a-b-c/d-e-f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
-            put("/apps/a/b/c/Pojo.java", "apps.a.b.c.Pojo");
-        }};
-        for (Map.Entry<String, String> scriptEntry : 
expectedScriptNames.entrySet()) {
-            ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-            Resource resource = Mockito.mock(Resource.class);
-            when(resource.getPath()).thenReturn(scriptEntry.getKey());
-            
when(resolver.getResource(scriptEntry.getKey())).thenReturn(resource);
-            Resource result = SourceIdentifier.getPOJOFromFQCN(resolver, 
BUNDLE_SYMBOLIC_NAME, scriptEntry.getValue());
-            assertNotNull(
-                    String.format("ResourceResolver was expected to find 
resource %s for POJO %s. Got null instead.", scriptEntry.getKey(),
-                            scriptEntry.getValue()), result);
-            assertEquals(scriptEntry.getKey(), result.getPath());
-        }
-    }
-
-    @Test
     public void testPOJOMangling() {
         Map<String, String> expectedMangling = new HashMap<String, String>(){{
             put("/apps/test-static/Pojo.java", "apps.test_static.Pojo");

Reply via email to