SLING-7674 Remove embedded Thymeleaf dependency from bundle

* rely fully on Scripting Resource Resolver
* remove Sling's custom contexts and SlingEngineContextFactory
* provide ServletContext
* wrap Thymeleaf in ITs
diff --git a/README.md b/README.md
index 6a575d8..41c6c18 100644
--- a/README.md
+++ b/README.md
@@ -31,9 +31,3 @@
     karaf@root()> feature:install sling-scripting-thymeleaf
 
 **Note:** Sling Scripting Thymeleaf requires an implementation of OSGi Declarative Services 1.3 (e.g. [Apache Felix Service Component Runtime](http://felix.apache.org/documentation/subprojects/apache-felix-service-component-runtime.html) 2.0.0 or greater)
-
-## Relevant Thymeleaf issues
-
-* [Create OSGi bundle](https://github.com/thymeleaf/thymeleaf/issues/32)
-* [keep (custom) IContext accessible](https://github.com/thymeleaf/thymeleaf/issues/388)
-* [Make IContext available in ITemplateResolver](https://github.com/thymeleaf/thymeleaf/issues/514)
diff --git a/bnd.bnd b/bnd.bnd
index 2c07c1f..172b7ff 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -8,51 +8,6 @@
 
 Bundle-Vendor: The Apache Software Foundation
 
-Export-Package:\
-  org.apache.sling.scripting.thymeleaf,\
-  org.thymeleaf;version=5.0.0,\
-  org.thymeleaf.cache;version=3.1.0,\
-  org.thymeleaf.context;version=3.1.0,\
-  org.thymeleaf.dialect;version=3.0.0,\
-  org.thymeleaf.engine;version=4.0.0;-split-package:=merge-first,\
-  org.thymeleaf.exceptions;version=3.0.0,\
-  org.thymeleaf.expression;version=3.1.0,\
-  org.thymeleaf.inline;version=3.0.0,\
-  org.thymeleaf.linkbuilder;version=3.0.0,\
-  org.thymeleaf.messageresolver;version=3.0.0,\
-  org.thymeleaf.model;version=3.0.0,\
-  org.thymeleaf.postprocessor;version=3.0.0,\
-  org.thymeleaf.preprocessor;version=3.0.0,\
-  org.thymeleaf.processor;version=3.0.0,\
-  org.thymeleaf.processor.cdatasection;version=3.0.0,\
-  org.thymeleaf.processor.comment;version=3.0.0,\
-  org.thymeleaf.processor.doctype;version=3.0.0,\
-  org.thymeleaf.processor.element;version=3.0.0,\
-  org.thymeleaf.processor.processinginstruction;version=3.0.0,\
-  org.thymeleaf.processor.templateboundaries;version=3.0.0,\
-  org.thymeleaf.processor.text;version=3.0.0 ,\
-  org.thymeleaf.processor.xmldeclaration;version=3.0.0,\
-  org.thymeleaf.standard;version=3.0.0,\
-  org.thymeleaf.standard.expression;version=3.1.0,\
-  org.thymeleaf.standard.inline;version=3.0.0,\
-  org.thymeleaf.standard.processor;version=3.1.0,\
-  org.thymeleaf.standard.serializer;version=3.0.0,\
-  org.thymeleaf.standard.util;version=3.0.0,\
-  org.thymeleaf.templatemode;version=3.0.0,\
-  org.thymeleaf.templateparser;version=3.0.0,\
-  org.thymeleaf.templateparser.markup;version=3.0.0,\
-  org.thymeleaf.templateparser.markup.decoupled;version=3.0.0,\
-  org.thymeleaf.templateparser.raw;version=3.0.0,\
-  org.thymeleaf.templateparser.reader;version=3.0.0,\
-  org.thymeleaf.templateparser.text;version=4.0.0,\
-  org.thymeleaf.templateresolver;version=3.1.0;-split-package:=merge-first,\
-  org.thymeleaf.templateresource;version=3.1.0,\
-  org.thymeleaf.util;version=3.3.0
-
-Import-Package:\
-  com.fasterxml.jackson.*;version=${com.fasterxml.jackson.version};resolution:=optional,\
-  *
-
 Provide-Capability:\
   osgi.service;objectClass=org.thymeleaf.ITemplateEngine
 
diff --git a/pom.xml b/pom.xml
index f6fcd65..28943b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -166,7 +166,7 @@
       <groupId>org.thymeleaf</groupId>
       <artifactId>thymeleaf</artifactId>
       <version>3.0.9.RELEASE</version>
-      <scope>compile</scope>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.attoparser</groupId>
@@ -252,6 +252,12 @@
       <version>${org.ops4j.pax.exam.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.url</groupId>
+      <artifactId>pax-url-wrap</artifactId>
+      <version>2.5.4</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java
deleted file mode 100644
index f6d4d1d..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java
+++ /dev/null
@@ -1,41 +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.thymeleaf;
-
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.thymeleaf.context.AbstractContext;
-
-public class DefaultSlingContext extends AbstractContext implements SlingContext {
-
-    private final ResourceResolver resourceResolver;
-
-    public DefaultSlingContext(final ResourceResolver resourceResolver, final Locale locale, final Map<String, Object> variables) {
-        super(locale, variables);
-        this.resourceResolver = resourceResolver;
-    }
-
-    @Override
-    public ResourceResolver getResourceResolver() {
-        return resourceResolver;
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
deleted file mode 100644
index 4b2c282..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
+++ /dev/null
@@ -1,30 +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.thymeleaf;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.osgi.annotation.versioning.ProviderType;
-import org.thymeleaf.context.IContext;
-
-@ProviderType
-public interface SlingContext extends IContext {
-
-    ResourceResolver getResourceResolver();
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java
deleted file mode 100644
index c5dc3b6..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java
+++ /dev/null
@@ -1,44 +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.thymeleaf.internal;
-
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.scripting.thymeleaf.SlingContext;
-import org.thymeleaf.IEngineConfiguration;
-import org.thymeleaf.context.EngineContext;
-import org.thymeleaf.engine.TemplateData;
-
-public class SlingEngineContext extends EngineContext implements SlingContext {
-
-    private final ResourceResolver resourceResolver;
-
-    public SlingEngineContext(final ResourceResolver resourceResolver, final IEngineConfiguration configuration, final TemplateData templateData, final Map<String, Object> templateResolutionAttributes, final Locale locale, final Map<String, Object> variables) {
-        super(configuration, templateData, templateResolutionAttributes, locale, variables);
-        this.resourceResolver = resourceResolver;
-    }
-
-    @Override
-    public ResourceResolver getResourceResolver() {
-        return resourceResolver;
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java
deleted file mode 100644
index e25715e..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java
+++ /dev/null
@@ -1,63 +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.thymeleaf.internal;
-
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.scripting.thymeleaf.SlingContext;
-import org.osgi.framework.Constants;
-import org.osgi.service.component.annotations.Component;
-import org.thymeleaf.IEngineConfiguration;
-import org.thymeleaf.context.IContext;
-import org.thymeleaf.context.IEngineContext;
-import org.thymeleaf.context.IEngineContextFactory;
-import org.thymeleaf.engine.TemplateData;
-
-@Component(
-    immediate = true,
-    property = {
-        Constants.SERVICE_DESCRIPTION + "=Sling EngineContextFactory for Sling Scripting Thymeleaf",
-        Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
-    }
-)
-public class SlingEngineContextFactory implements IEngineContextFactory {
-
-    @Override
-    public IEngineContext createEngineContext(final IEngineConfiguration configuration, final TemplateData templateData, final Map<String, Object> templateResolutionAttributes, final IContext context) {
-        if (context instanceof SlingContext) {
-            // TODO web context
-            final SlingContext slingContext = (SlingContext) context;
-            final ResourceResolver resourceResolver = slingContext.getResourceResolver();
-            final Locale locale = context.getLocale();
-            final Set<String> variableNames = context.getVariableNames();
-            final Map<String, Object> variables = new LinkedHashMap<>(variableNames.size() + 1, 1.0f);
-            for (final String variableName : variableNames) {
-                variables.put(variableName, context.getVariable(variableName));
-            }
-            return new SlingEngineContext(resourceResolver, configuration, templateData, templateResolutionAttributes, locale, variables);
-        } else {
-            throw new IllegalStateException("context is not an instance of SlingContext");
-        }
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
index bc40258..dfcbb40 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
@@ -22,7 +22,7 @@
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.scripting.thymeleaf.SlingContext;
+import org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
 import org.apache.sling.scripting.thymeleaf.TemplateModeProvider;
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Activate;
@@ -39,7 +39,6 @@
 import org.thymeleaf.IEngineConfiguration;
 import org.thymeleaf.cache.ICacheEntryValidity;
 import org.thymeleaf.cache.NonCacheableCacheEntryValidity;
-import org.thymeleaf.context.IContext;
 import org.thymeleaf.templatemode.TemplateMode;
 import org.thymeleaf.templateresolver.ITemplateResolver;
 import org.thymeleaf.templateresolver.TemplateResolution;
@@ -66,6 +65,13 @@
     )
     private volatile TemplateModeProvider templateModeProvider;
 
+    @Reference(
+            cardinality = ReferenceCardinality.MANDATORY,
+            policy = ReferencePolicy.DYNAMIC,
+            policyOption = ReferencePolicyOption.GREEDY
+    )
+    private volatile ScriptingResourceResolverProvider scriptingResourceResolverProvider;
+
     private SlingResourceTemplateResolverConfiguration configuration;
 
     private final Logger logger = LoggerFactory.getLogger(SlingResourceTemplateResolver.class);
@@ -109,32 +115,27 @@
     }
 
     @Override
-    public TemplateResolution resolveTemplate(final IEngineConfiguration engineConfiguration, final IContext context, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes) {
+    public TemplateResolution resolveTemplate(final IEngineConfiguration engineConfiguration, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes) {
         logger.debug("resolving template '{}'", template);
-        if (context instanceof SlingContext) {
-            final SlingContext slingContext = (SlingContext) context;
-            final ResourceResolver resourceResolver = slingContext.getResourceResolver();
-            final Resource resource = resourceResolver.getResource(template);
-            if (resource == null) {
-                logger.warn("resource for template '{}' is null, not resolving template", template);
-                return null;
-            }
-            final ITemplateResource templateResource = new SlingTemplateResource(resource);
-            final boolean templateResourceExistenceVerified = false;
-            final TemplateMode templateMode = templateModeProvider.provideTemplateMode(resource);
-            if (templateMode == null) {
-                logger.warn("template mode for template '{}' is null, not resolving template", template);
-                return null;
-            } else {
-                logger.debug("using template mode {} for template '{}'", templateMode, template);
-                final boolean useDecoupledLogic = templateMode.isMarkup() && configuration.useDecoupledLogic();
-                final ICacheEntryValidity validity = NonCacheableCacheEntryValidity.INSTANCE;
-                return new TemplateResolution(templateResource, templateResourceExistenceVerified, templateMode, useDecoupledLogic, validity);
-            }
-        } else {
-            logger.error("context is not an instance of SlingContext");
+        // per thread service resource resolver
+        final ResourceResolver resourceResolver = scriptingResourceResolverProvider.getRequestScopedResourceResolver();
+        final Resource resource = resourceResolver.getResource(template);
+        if (resource == null) {
+            logger.warn("resource for template '{}' is null, not resolving template", template);
             return null;
         }
+        final ITemplateResource templateResource = new SlingTemplateResource(resource);
+        final boolean templateResourceExistenceVerified = false;
+        final TemplateMode templateMode = templateModeProvider.provideTemplateMode(resource);
+        if (templateMode == null) {
+            logger.warn("template mode for template '{}' is null, not resolving template", template);
+            return null;
+        } else {
+            logger.debug("using template mode {} for template '{}'", templateMode, template);
+            final boolean useDecoupledLogic = templateMode.isMarkup() && configuration.useDecoupledLogic();
+            final ICacheEntryValidity validity = NonCacheableCacheEntryValidity.INSTANCE;
+            return new TemplateResolution(templateResource, templateResourceExistenceVerified, templateMode, useDecoupledLogic, validity);
+        }
     }
 
 }
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java
deleted file mode 100644
index e977d46..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java
+++ /dev/null
@@ -1,70 +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.thymeleaf.internal;
-
-import java.util.Locale;
-import java.util.Map;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.scripting.thymeleaf.DefaultSlingContext;
-import org.thymeleaf.context.IWebContext;
-
-public class SlingWebContext extends DefaultSlingContext implements IWebContext {
-
-    private final SlingHttpServletRequest servletRequest;
-
-    private final SlingHttpServletResponse servletResponse;
-
-    private final ServletContext servletContext;
-
-    public SlingWebContext(final SlingHttpServletRequest servletRequest, final SlingHttpServletResponse servletResponse, final ServletContext servletContext, final ResourceResolver resourceResolver, final Locale locale, final Map<String, Object> variables) {
-        super(resourceResolver, locale, variables);
-        this.servletRequest = servletRequest;
-        this.servletResponse = servletResponse;
-        this.servletContext = servletContext;
-    }
-
-    @Override
-    public HttpServletRequest getRequest() {
-        return servletRequest;
-    }
-
-    @Override
-    public HttpServletResponse getResponse() {
-        return servletResponse;
-    }
-
-    @Override
-    public HttpSession getSession() {
-        return servletRequest.getSession(false);
-    }
-
-    @Override
-    public ServletContext getServletContext() {
-        return servletContext;
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
index d653556..ac16c19 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
@@ -29,13 +29,13 @@
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.thymeleaf.context.IContext;
+import org.thymeleaf.context.WebContext;
 
 public final class ThymeleafScriptEngine extends AbstractSlingScriptEngine {
 
@@ -59,15 +59,13 @@
 
         final SlingHttpServletRequest request = helper.getRequest();
         final SlingHttpServletResponse response = helper.getResponse();
-        final ServletContext servletContext = null; // only used by Thymeleaf's ServletContextResourceResolver (TODO check if still true for 3.0)
-
+        final ServletContext servletContext = thymeleafScriptEngineFactory.getSlingServletContext();
         final Locale locale = helper.getResponse().getLocale();
         final String scriptName = helper.getScript().getScriptResource().getPath();
         final Writer writer = scriptContext.getWriter();
 
         try {
-            final ResourceResolver resourceResolver = thymeleafScriptEngineFactory.getRequestScopedResourceResolver();
-            final IContext context = new SlingWebContext(request, response, servletContext, resourceResolver, locale, bindings);
+            final IContext context = new WebContext(request, response, servletContext, locale, bindings);
             thymeleafScriptEngineFactory.getTemplateEngine().process(scriptName, context, writer);
         } catch (Exception e) {
             logger.error("Failure rendering Thymeleaf template '{}': {}", scriptName, e.getMessage());
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
index 22a18f1..5512c09 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
@@ -27,6 +27,7 @@
 
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
+import javax.servlet.ServletContext;
 
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
@@ -122,6 +123,7 @@
     private volatile ICacheManager cacheManager;
 
     @Reference(
+        cardinality = ReferenceCardinality.OPTIONAL,
         policy = ReferencePolicy.DYNAMIC,
         policyOption = ReferencePolicyOption.GREEDY,
         bind = "setEngineContextFactory",
@@ -135,6 +137,13 @@
     )
     private volatile ScriptingResourceResolverProvider scriptingResourceResolverProvider;
 
+    @Reference(
+        policy = ReferencePolicy.DYNAMIC,
+        policyOption = ReferencePolicyOption.GREEDY,
+        target = "(name=org.apache.sling)"
+    )
+    private volatile ServletContext servletContext;
+
     private ThymeleafScriptEngineFactoryConfiguration configuration;
 
     private BundleContext bundleContext;
@@ -432,4 +441,8 @@
         return scriptingResourceResolverProvider.getRequestScopedResourceResolver();
     }
 
+    ServletContext getSlingServletContext() {
+        return servletContext;
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
index e73c710..3830241 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
@@ -92,6 +92,6 @@
         name = "use standard engine context factory",
         description = "Enables Thymeleaf's standard engine context factory and uses it exclusively."
     )
-    boolean useStandardEngineContextFactory() default false;
+    boolean useStandardEngineContextFactory() default true;
 
 }
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/package-info.java b/src/main/java/org/apache/sling/scripting/thymeleaf/package-info.java
index 0c5d436..0d4ab66 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/package-info.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/package-info.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-@Version("1.1.0")
+@Version("2.0.0")
 package org.apache.sling.scripting.thymeleaf;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/thymeleaf/engine/TemplateManager.java b/src/main/java/org/thymeleaf/engine/TemplateManager.java
deleted file mode 100644
index b80f7ca..0000000
--- a/src/main/java/org/thymeleaf/engine/TemplateManager.java
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * =============================================================================
- * 
- *   Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org)
- * 
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- * 
- *       http://www.apache.org/licenses/LICENSE-2.0
- * 
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- * 
- * =============================================================================
- */
-package org.thymeleaf.engine;
-
-import java.io.Writer;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.thymeleaf.IEngineConfiguration;
-import org.thymeleaf.TemplateEngine;
-import org.thymeleaf.TemplateSpec;
-import org.thymeleaf.cache.AlwaysValidCacheEntryValidity;
-import org.thymeleaf.cache.ICache;
-import org.thymeleaf.cache.ICacheEntryValidity;
-import org.thymeleaf.cache.ICacheManager;
-import org.thymeleaf.cache.NonCacheableCacheEntryValidity;
-import org.thymeleaf.cache.TemplateCacheKey;
-import org.thymeleaf.context.IContext;
-import org.thymeleaf.context.IEngineContext;
-import org.thymeleaf.context.ITemplateContext;
-import org.thymeleaf.exceptions.TemplateInputException;
-import org.thymeleaf.exceptions.TemplateProcessingException;
-import org.thymeleaf.postprocessor.IPostProcessor;
-import org.thymeleaf.preprocessor.IPreProcessor;
-import org.thymeleaf.templatemode.TemplateMode;
-import org.thymeleaf.templateparser.ITemplateParser;
-import org.thymeleaf.templateparser.markup.HTMLTemplateParser;
-import org.thymeleaf.templateparser.markup.XMLTemplateParser;
-import org.thymeleaf.templateparser.raw.RawTemplateParser;
-import org.thymeleaf.templateparser.text.CSSTemplateParser;
-import org.thymeleaf.templateparser.text.JavaScriptTemplateParser;
-import org.thymeleaf.templateparser.text.TextTemplateParser;
-import org.thymeleaf.templateresolver.ITemplateResolver;
-import org.thymeleaf.templateresolver.TemplateResolution;
-import org.thymeleaf.templateresource.ITemplateResource;
-import org.thymeleaf.util.LoggingUtils;
-import org.thymeleaf.util.Validate;
-
-
-/**
- *
- * @author Daniel Fern&aacute;ndez
- * 
- * @since 3.0.0
- *
- */
-public final class TemplateManager {
-
-    private static final Logger logger = LoggerFactory.getLogger(TemplateManager.class);
-
-    private static final int DEFAULT_PARSER_POOL_SIZE = 40;
-    private static final int DEFAULT_PARSER_BLOCK_SIZE = 2048;
-
-    private final IEngineConfiguration configuration;
-
-    private final ITemplateParser htmlParser;
-    private final ITemplateParser xmlParser;
-    private final ITemplateParser textParser;
-    private final ITemplateParser javascriptParser;
-    private final ITemplateParser cssParser;
-    private final ITemplateParser rawParser;
-
-
-    private final ICache<TemplateCacheKey,TemplateModel> templateCache; // might be null! (= no cache)
-
-
-
-
-    /**
-     * <p>
-     *   This constructor should only be called directly for <strong>testing purposes</strong>.
-     * </p>
-     *
-     * @param configuration the engine configuration
-     */
-    public TemplateManager(final IEngineConfiguration configuration) {
-        
-        super();
-
-        Validate.notNull(configuration, "Configuration cannot be null");
-
-        this.configuration = configuration;
-
-        final ICacheManager cacheManager = this.configuration.getCacheManager();
-
-        if (cacheManager == null) {
-            this.templateCache = null;
-        } else {
-            this.templateCache = cacheManager.getTemplateCache();
-        }
-
-        final boolean standardDialectPresent = this.configuration.isStandardDialectPresent();
-
-        // TODO Make these parser implementations configurable: one parser per template mode, then make default implementations extensible/configurable (e.g. AttoParser config)
-        this.htmlParser = new HTMLTemplateParser(DEFAULT_PARSER_POOL_SIZE,DEFAULT_PARSER_BLOCK_SIZE);
-        this.xmlParser = new XMLTemplateParser(DEFAULT_PARSER_POOL_SIZE, DEFAULT_PARSER_BLOCK_SIZE);
-        this.textParser = new TextTemplateParser(DEFAULT_PARSER_POOL_SIZE, DEFAULT_PARSER_BLOCK_SIZE, standardDialectPresent);
-        this.javascriptParser = new JavaScriptTemplateParser(DEFAULT_PARSER_POOL_SIZE, DEFAULT_PARSER_BLOCK_SIZE, standardDialectPresent);
-        this.cssParser = new CSSTemplateParser(DEFAULT_PARSER_POOL_SIZE, DEFAULT_PARSER_BLOCK_SIZE, standardDialectPresent);
-        this.rawParser = new RawTemplateParser(DEFAULT_PARSER_POOL_SIZE, DEFAULT_PARSER_BLOCK_SIZE);
-
-    }
-    
-
-    
-    
-    
-    /**
-     * <p>
-     *   Clears the template cache.
-     * </p>
-     */
-    public void clearCaches() {
-        if (this.templateCache != null) {
-            this.templateCache.clear();
-        }
-    }
-
-    
-    /**
-     * <p>
-     *   Clears any existing entries for template of the specified
-     *   name at the template cache.
-     * </p>
-     * 
-     * @param template the name of the template whose entries have to be cleared.
-     */
-    public void clearCachesFor(final String template) {
-        Validate.notNull(template, "Cannot specify null template");
-        if (this.templateCache != null) {
-            final Set<TemplateCacheKey> keysToBeRemoved = new HashSet<TemplateCacheKey>(4);
-            final Set<TemplateCacheKey> templateCacheKeys = this.templateCache.keySet();
-            // We are iterating twice and creating a temporary set just in case the 'keySet' Set is still connected
-            // to the original cache store and we provoke ConcurrentModificationExceptions when removing entries
-            for (final TemplateCacheKey templateCacheKey : templateCacheKeys) {
-                final String ownerTemplate = templateCacheKey.getOwnerTemplate();
-                if (ownerTemplate != null) {
-                    // It's not a standalone template, so we are interested on the owner template
-                    if (ownerTemplate.equals(template)) {
-                        keysToBeRemoved.add(templateCacheKey);
-                    }
-                } else {
-                    if (templateCacheKey.getTemplate().equals(template)) {
-                        keysToBeRemoved.add(templateCacheKey);
-                    }
-                }
-            }
-            for (final TemplateCacheKey keyToBeRemoved : keysToBeRemoved) {
-                this.templateCache.clearKey(keyToBeRemoved);
-            }
-        }
-    }
-
-
-
-
-
-
-    /*
-     * -------------
-     * PARSE methods
-     * -------------
-     *
-     * Parse methods will create 'template models' that are basically collections of events in the form of an
-     * immutable IModel implementation.
-     */
-
-
-    public TemplateModel parseStandalone(
-            final ITemplateContext context, final String template, final Set<String> templateSelectors,
-            final TemplateMode templateMode, final boolean useCache, final boolean failIfNotExists) {
-
-        Validate.notNull(context, "Context cannot be null");
-        Validate.notNull(template, "Template cannot be null");
-        // templateSelectors CAN be null if we are going to render the entire template
-        // templateMode CAN be null if we are going to use the mode specified by the template resolver
-        // templateResolutionAttributes CAN be null
-
-
-        final String ownerTemplate = context.getTemplateData().getTemplate();
-        final Map<String,Object> templateResolutionAttributes = context.getTemplateResolutionAttributes();
-
-        final Set<String> cleanTemplateSelectors;
-        if (templateSelectors != null && !templateSelectors.isEmpty()) {
-            Validate.containsNoEmpties(
-                    templateSelectors, "If specified, the Template Selector set cannot contain any nulls or empties");
-            if (templateSelectors.size() == 1) {
-                cleanTemplateSelectors = Collections.singleton(templateSelectors.iterator().next());
-            } else {
-                // We will be using a TreeSet because we want the selectors to be ORDERED, so that comparison at the
-                // equals(...) method works alright
-                cleanTemplateSelectors = Collections.unmodifiableSet(new TreeSet<String>(templateSelectors));
-            }
-        } else {
-            cleanTemplateSelectors = null;
-        }
-
-
-        final TemplateCacheKey cacheKey =
-                useCache?
-                        new TemplateCacheKey(
-                                ownerTemplate,
-                                template, cleanTemplateSelectors,
-                                0, 0,
-                                templateMode,
-                                templateResolutionAttributes)
-                        : null;
-
-        /*
-         * First look at the cache - it might be already cached
-         */
-        if (useCache && this.templateCache != null) {
-            final TemplateModel cached =  this.templateCache.get(cacheKey);
-            if (cached != null) {
-                /*
-                 * Just at the end, and importantly AFTER CACHING, check if we need to apply any pre-processors
-                 * to this model before returning and letting the engine insert the model in any way it needs.
-                 */
-                return applyPreProcessorsIfNeeded(context, cached);
-            }
-        }
-
-
-        /*
-         * Resolve the template
-         */
-        final TemplateResolution templateResolution =
-                resolveTemplate(this.configuration, context, ownerTemplate, template, templateResolutionAttributes, failIfNotExists);
-
-
-        /*
-         * Once the template has been resolved (or tried to), and depending on the value of our 'failIfNotExists'
-         * flag, we will check two conditions in which we will be returning null:
-         *
-         *    1. No template resolver has been able to resolve the template (this can happen if resolvers are
-         *       configured with the 'checkExistence' flag to true).
-         *    2. If the template was resolved, its existence should be checked in order to avoid exceptions during
-         *       the reading phase.
-         *
-         * NOTE we will not cache this "null" result because the fact that a template is cacheable or not is
-         * determined by template resolvers. And in this case there is no template resolver being applied
-         * (actually, we are here because no resolver had success).
-         */
-        if (!failIfNotExists) {
-
-            if (templateResolution == null) {
-                // No resolver could resolve this
-                return null;
-            }
-
-            if (!templateResolution.isTemplateResourceExistenceVerified()) {
-                final ITemplateResource resource = templateResolution.getTemplateResource();
-                if (resource == null || !resource.exists()) {
-                    // Calling resource.exists() each time is not great, but think this only happens if the resource
-                    // has not been cached (e.g. when it does not exist)
-                    return null;
-                }
-            }
-
-        }
-
-
-        /*
-         * Build the TemplateData object
-         */
-        final TemplateData templateData =
-                buildTemplateData(templateResolution, template, cleanTemplateSelectors, templateMode, useCache);
-
-
-        /*
-         *  Create the Template Handler that will be in charge of building the TemplateModel
-         */
-        final ModelBuilderTemplateHandler builderHandler = new ModelBuilderTemplateHandler(this.configuration, templateData);
-
-
-        /*
-         * PROCESS THE TEMPLATE
-         */
-        final ITemplateParser parser = getParserForTemplateMode(templateData.getTemplateMode());
-        parser.parseStandalone(
-                this.configuration,
-                ownerTemplate, template, cleanTemplateSelectors, templateData.getTemplateResource(),
-                templateData.getTemplateMode(), templateResolution.getUseDecoupledLogic(), builderHandler);
-
-        final TemplateModel templateModel = builderHandler.getModel();
-
-
-        /*
-         * Cache the template if it is cacheable
-         */
-        if (useCache && this.templateCache != null) {
-            if (templateResolution.getValidity().isCacheable()) {
-                this.templateCache.put(cacheKey, templateModel);
-            }
-        }
-
-
-        /*
-         * Last step: just at the end, and importantly AFTER CACHING, check if we need to apply any pre-processors
-         * to this model before returning and letting the engine insert the model in any way it needs.
-         */
-        return applyPreProcessorsIfNeeded(context, templateModel);
-
-    }
-
-
-
-
-    /*
-     * This method manually applies preprocessors to template models that have just been parsed or obtained from
-     * cache. This is needed for fragments, just before these fragments (coming from templates, not simply parsed
-     * text) are returned to whoever needs them (usually the fragment insertion mechanism).
-     *
-     * NOTE that PRE-PROCESSOR INSTANCES ARE NOT SHARED among the different fragments being inserted
-     *      in a template (or between fragments and the main template). The reason for this is that pre-processors are
-     *      implementations of ITemplateHandler and therefore instances are inserted into processing chains that cannot
-     *      be broken (if a pre-processor is used for the main template its "next" step in the chain cannot be
-     *      'momentarily' changed in order to be a fragment-building handler instead of the ProcessorTemplateHandler)
-     *
-     *      The only way therefore among pre-processor instances to actually share information is by setting it into
-     *      the context.
-     */
-    private TemplateModel applyPreProcessorsIfNeeded(final ITemplateContext context, final TemplateModel templateModel) {
-
-        final TemplateData templateData = templateModel.getTemplateData();
-
-        if (this.configuration.getPreProcessors(templateData.getTemplateMode()).isEmpty()) {
-            return templateModel;
-        }
-
-        final IEngineContext engineContext =
-                EngineContextManager.prepareEngineContext(this.configuration, templateData, context.getTemplateResolutionAttributes(), context);
-
-        final ModelBuilderTemplateHandler builderHandler = new ModelBuilderTemplateHandler(this.configuration, templateData);
-        final ITemplateHandler processingHandlerChain =
-                createTemplateProcessingHandlerChain(engineContext, true, false, builderHandler, null);
-
-        templateModel.process(processingHandlerChain);
-
-        EngineContextManager.disposeEngineContext(engineContext);
-
-        return builderHandler.getModel();
-
-    }
-
-
-
-
-    public TemplateModel parseString(
-            final TemplateData ownerTemplateData, final String template,
-            final int lineOffset, final int colOffset,
-            final TemplateMode templateMode,
-            final boolean useCache) {
-
-        Validate.notNull(ownerTemplateData, "Owner template cannot be null");
-        Validate.notNull(template, "Template cannot be null");
-        // NOTE selectors cannot be specified when parsing a nested template
-        // templateMode CAN be null (if we are using the owner's)
-
-        final String ownerTemplate = ownerTemplateData.getTemplate();
-
-        final TemplateMode definitiveTemplateMode =
-                (templateMode != null? templateMode : ownerTemplateData.getTemplateMode());
-
-
-        final TemplateCacheKey cacheKey =
-                useCache?
-                        new TemplateCacheKey(
-                                ownerTemplate,
-                                template, null,
-                                lineOffset, colOffset,
-                                definitiveTemplateMode,
-                                null) // template resolution attributes do not affect string fragments: no resolution!
-                        : null;
-
-        /*
-         * First look at the cache - it might be already cached
-         */
-        if (useCache && this.templateCache != null) {
-            final TemplateModel cached =  this.templateCache.get(cacheKey);
-            if (cached != null) {
-                return cached;
-            }
-        }
-
-
-        /*
-         * Compute the cache validity. In order for a String fragment to be cacheable, we will have to have
-         * specified the 'useCache' parameter as true, and the owner template must be cacheable
-         */
-        final ICacheEntryValidity cacheValidity =
-                (useCache && ownerTemplateData.getValidity().isCacheable()?
-                        AlwaysValidCacheEntryValidity.INSTANCE : NonCacheableCacheEntryValidity.INSTANCE);
-
-
-        /*
-         * Build the TemplateData
-         *
-         * NOTE how, by default, we are using the owner's TemplateData. And even if the template mode changes
-         * and we need to create a new TemplateData object, we will keep the original name and resource.
-         * This is because we want the elements inside the fragment to me reported as belonging to the
-         * container template, not to the fragment String considered as a fragment in its own (which
-         * wouldn't make sense)
-         */
-        final TemplateData templateData =
-                (templateMode == null?
-                        // No change in Template Mode -> simply use the owner's template data
-                        ownerTemplateData :
-                        // Template Mode changed -> new TemplateData, very similar but different template mode
-                        new TemplateData(
-                                ownerTemplateData.getTemplate(), ownerTemplateData.getTemplateSelectors(),
-                                ownerTemplateData.getTemplateResource(), templateMode, cacheValidity));
-
-
-        /*
-         * Create the Template Handler that will be in charge of building the TemplateModel
-         *
-         * NOTE how we are using the owner's TemplateData and not a new one created for this fragment, because
-         * we want the elements inside the fragment to me reported as belonging to the container template,
-         * not to the fragment String considered as a fragment in its own (which wouldn't make sense)
-         */
-        final ModelBuilderTemplateHandler builderHandler = new ModelBuilderTemplateHandler(this.configuration, templateData);
-
-
-        /*
-         * PROCESS THE TEMPLATE
-         */
-        final ITemplateParser parser = getParserForTemplateMode(templateData.getTemplateMode());
-        // NO RESOURCE is sent to the parser, in this case. We simply pass the String template
-        parser.parseString(this.configuration, ownerTemplate, template, lineOffset, colOffset, definitiveTemplateMode, builderHandler);
-
-        final TemplateModel parsedTemplate = builderHandler.getModel();
-
-
-        /*
-         * Cache the template if it is cacheable
-         */
-        if (useCache && this.templateCache != null) {
-            if (cacheValidity.isCacheable()) {
-                this.templateCache.put(cacheKey, parsedTemplate);
-            }
-        }
-        
-        return parsedTemplate;
-        
-    }
-
-
-
-
-
-
-    /*
-     * ---------------
-     * PROCESS methods
-     * ---------------
-     *
-     * Processing means executing a template that has already been parsed into a TemplateModel object
-     */
-
-
-    public void process(
-            final TemplateModel template,
-            final ITemplateContext context,
-            final Writer writer) {
-
-        Validate.isTrue(
-                this.configuration == template.getConfiguration(),
-                "Specified template was built by a different Template Engine instance");
-
-        /*
-         * Create the context instance that corresponds to this execution of the template engine
-         */
-        final IEngineContext engineContext =
-                EngineContextManager.prepareEngineContext(this.configuration, template.getTemplateData(), context.getTemplateResolutionAttributes(), context);
-
-        /*
-         * Create the handler chain to process the data.
-         *
-         * In this case we are only processing an already existing model, which was created after some computation
-         * at template-processing time. So this does not come directly from a template, and therefore pre-processors
-         * should not be applied.
-         *
-         * As for post-processors, we know the result of this will not be directly written to output in most cases but
-         * instead used to create a String that is afterwards inserted into the model as a Text node. In the only cases
-         * in which this is not true is when this is used inside any kind of Lazy-processing CharSequence writer like
-         * LazyProcessingCharSequence, and in such case we know those CharSequences are only used when there are
-         * NO post-processors, so we are safe anyway.
-         */
-        final ProcessorTemplateHandler processorTemplateHandler = new ProcessorTemplateHandler();
-        final ITemplateHandler processingHandlerChain =
-                createTemplateProcessingHandlerChain(engineContext, false, false, processorTemplateHandler, writer);
-
-        /*
-         *  Process the template
-         */
-        template.process(processingHandlerChain);
-
-
-        /*
-         * Dispose the engine context now that processing has been done
-         */
-        EngineContextManager.disposeEngineContext(engineContext);
-
-    }
-
-
-
-
-
-
-    /*
-     * -------------------------
-     * PARSE-AND-PROCESS methods
-     * -------------------------
-     *
-     * These methods perform the whole cycle of a template's processing: resolving, parsing and processing.
-     * This is only meant to be called from the TemplateEngine
-     */
-
-
-    public void parseAndProcess(
-            final TemplateSpec templateSpec,
-            final IContext context,
-            final Writer writer) {
-
-        Validate.notNull(templateSpec, "Template Specification cannot be null");
-        Validate.notNull(context, "Context cannot be null");
-        Validate.notNull(writer, "Writer cannot be null");
-
-
-        // TemplateSpec will already have validated its contents, so need to do it here (template selectors,
-        // resolution attributes, etc.)
-
-        final String template = templateSpec.getTemplate();
-        final Set<String> templateSelectors = templateSpec.getTemplateSelectors();
-        final TemplateMode templateMode = templateSpec.getTemplateMode();
-        final Map<String, Object> templateResolutionAttributes = templateSpec.getTemplateResolutionAttributes();
-
-        final TemplateCacheKey cacheKey =
-                    new TemplateCacheKey(
-                            null, // ownerTemplate
-                            template, templateSelectors,
-                            0, 0, // lineOffset, colOffset
-                            templateMode,
-                            templateResolutionAttributes);
-
-
-        /*
-         * First look at the cache - it might be already cached
-         */
-        if (this.templateCache != null) {
-
-            final TemplateModel cached =  this.templateCache.get(cacheKey);
-
-            if (cached != null) {
-
-                final IEngineContext engineContext =
-                        EngineContextManager.prepareEngineContext(this.configuration, cached.getTemplateData(), templateResolutionAttributes, context);
-
-                /*
-                 * Create the handler chain to process the data.
-                 * This is PARSE + PROCESS, so its called from the TemplateEngine, and the only case in which we should apply
-                 * both pre-processors and post-processors (besides creating a last output-to-writer step)
-                 */
-                final ProcessorTemplateHandler processorTemplateHandler = new ProcessorTemplateHandler();
-                final ITemplateHandler processingHandlerChain =
-                        createTemplateProcessingHandlerChain(engineContext, true, true, processorTemplateHandler, writer);
-
-                cached.process(processingHandlerChain);
-
-                EngineContextManager.disposeEngineContext(engineContext);
-
-                return;
-
-            }
-
-        }
-
-
-        /*
-         * Resolve the template
-         */
-        final TemplateResolution templateResolution =
-                resolveTemplate(this.configuration, context, null, template, templateResolutionAttributes, true);
-
-
-        /*
-         * Build the TemplateData object
-         */
-        final TemplateData templateData =
-                buildTemplateData(templateResolution, template, templateSelectors, templateMode, true);
-
-
-        /*
-         * Prepare the context instance that corresponds to this execution of the template engine
-         */
-        final IEngineContext engineContext =
-                EngineContextManager.prepareEngineContext(this.configuration, templateData, templateResolutionAttributes, context);
-
-
-        /*
-         * Create the handler chain to process the data.
-         * This is PARSE + PROCESS, so its called from the TemplateEngine, and the only case in which we should apply
-         * both pre-processors and post-processors (besides creating a last output-to-writer step)
-         */
-        final ProcessorTemplateHandler processorTemplateHandler = new ProcessorTemplateHandler();
-        final ITemplateHandler processingHandlerChain =
-                createTemplateProcessingHandlerChain(engineContext, true, true, processorTemplateHandler, writer);
-
-
-        /*
-         * Obtain the parser
-         */
-        final ITemplateParser parser = getParserForTemplateMode(engineContext.getTemplateMode());
-
-
-        /*
-         * If the resolved template is cacheable, so we will first read it as an object, cache it, and then process it
-         */
-        if (templateResolution.getValidity().isCacheable() && this.templateCache != null) {
-
-            // Create the handler chain to create the Template object
-            final ModelBuilderTemplateHandler builderHandler = new ModelBuilderTemplateHandler(this.configuration, templateData);
-
-            // Process the template into a TemplateModel
-            parser.parseStandalone(
-                    this.configuration,
-                    null, template, templateSelectors, templateData.getTemplateResource(),
-                    engineContext.getTemplateMode(), templateResolution.getUseDecoupledLogic(), builderHandler);
-
-            // Obtain the TemplateModel
-            final TemplateModel templateModel = builderHandler.getModel();
-
-            // Put the new template into cache
-            this.templateCache.put(cacheKey, templateModel);
-
-            // Process the read (+cached) template itself
-            templateModel.process(processingHandlerChain);
-
-        } else {
-
-            //  Process the template, which is not cacheable (so no worry about caching)
-            parser.parseStandalone(
-                    this.configuration,
-                    null, template, templateSelectors, templateData.getTemplateResource(),
-                    engineContext.getTemplateMode(), templateResolution.getUseDecoupledLogic(),  processingHandlerChain);
-
-        }
-
-
-        /*
-         * Dispose the engine context now that processing has been done
-         */
-        EngineContextManager.disposeEngineContext(engineContext);
-
-
-    }
-
-
-    public ThrottledTemplateProcessor parseAndProcessThrottled(final TemplateSpec templateSpec, final IContext context) {
-
-        Validate.notNull(templateSpec, "Template Specification cannot be null");
-        Validate.notNull(context, "Context cannot be null");
-
-
-        // TemplateSpec will already have validated its contents, so need to do it here (template selectors,
-        // resolution attributes, etc.)
-
-        final String template = templateSpec.getTemplate();
-        final Set<String> templateSelectors = templateSpec.getTemplateSelectors();
-        final TemplateMode templateMode = templateSpec.getTemplateMode();
-        final Map<String, Object> templateResolutionAttributes = templateSpec.getTemplateResolutionAttributes();
-
-        final TemplateCacheKey cacheKey =
-                new TemplateCacheKey(
-                        null, // ownerTemplate
-                        template, templateSelectors,
-                        0, 0, // lineOffset, colOffset
-                        templateMode,
-                        templateResolutionAttributes);
-
-
-        /*
-         * Instantiate the throttling artifacts, including the throttled writer, which might be only for
-         */
-        final TemplateFlowController flowController = new TemplateFlowController();
-
-        final ThrottledTemplateWriter throttledTemplateWriter;
-        if (templateSpec.isOutputSSE()) {
-            throttledTemplateWriter = new SSEThrottledTemplateWriter(template, flowController);
-        } else {
-            throttledTemplateWriter = new ThrottledTemplateWriter(template, flowController);
-        }
-
-
-        /*
-         * First look at the cache - it might be already cached
-         */
-        if (this.templateCache != null) {
-
-            final TemplateModel cached =  this.templateCache.get(cacheKey);
-
-            if (cached != null) {
-
-                final IEngineContext engineContext =
-                        EngineContextManager.prepareEngineContext(this.configuration, cached.getTemplateData(), templateResolutionAttributes, context);
-
-                /*
-                 * Create the handler chain to process the data.
-                 * This is PARSE + PROCESS, so its called from the TemplateEngine, and the only case in which we should apply
-                 * both pre-processors and post-processors (besides creating a last output-to-writer step)
-                 */
-                final ProcessorTemplateHandler processorTemplateHandler = new ProcessorTemplateHandler();
-                processorTemplateHandler.setFlowController(flowController);
-                final ITemplateHandler processingHandlerChain =
-                        createTemplateProcessingHandlerChain(engineContext, true, true, processorTemplateHandler, throttledTemplateWriter);
-
-                /*
-                 * Return the throttled template processor
-                 */
-                return new ThrottledTemplateProcessor(
-                        templateSpec, engineContext, cached, processingHandlerChain,
-                        processorTemplateHandler, flowController, throttledTemplateWriter);
-
-            }
-
-        }
-
-
-        /*
-         * Resolve the template
-         */
-        final TemplateResolution templateResolution =
-                resolveTemplate(this.configuration, context, null, template, templateResolutionAttributes, true);
-
-
-        /*
-         * Build the TemplateData object
-         */
-        final TemplateData templateData =
-                buildTemplateData(templateResolution, template, templateSelectors, templateMode, true);
-
-
-        /*
-         * Prepare the context instance that corresponds to this execution of the template engine
-         */
-        final IEngineContext engineContext =
-                EngineContextManager.prepareEngineContext(this.configuration, templateData, templateResolutionAttributes, context);
-
-
-        /*
-         * Create the handler chain to process the data.
-         * This is PARSE + PROCESS, so its called from the TemplateEngine, and the only case in which we should apply
-         * both pre-processors and post-processors (besides creating a last output-to-writer step)
-         */
-        final ProcessorTemplateHandler processorTemplateHandler = new ProcessorTemplateHandler();
-        processorTemplateHandler.setFlowController(flowController);
-        final ITemplateHandler processingHandlerChain =
-                createTemplateProcessingHandlerChain(engineContext, true, true, processorTemplateHandler, throttledTemplateWriter);
-
-
-        /*
-         * Obtain the parser
-         */
-        final ITemplateParser parser = getParserForTemplateMode(engineContext.getTemplateMode());
-
-
-        /*
-         * Parse the template into a TemplateModel. Even if we are not using the cache, throttled template processings
-         * will always be processed first into a TemplateModel, so that throttling can then be applied on an
-         * already-in-memory sequence of events
-         */
-        final ModelBuilderTemplateHandler builderHandler = new ModelBuilderTemplateHandler(this.configuration, templateData);
-        parser.parseStandalone(
-                this.configuration,
-                null, template, templateSelectors, templateData.getTemplateResource(),
-                engineContext.getTemplateMode(), templateResolution.getUseDecoupledLogic(), builderHandler);
-        final TemplateModel templateModel = builderHandler.getModel();
-
-
-        /*
-         * If cache is active, put the cached TemplateModel into cache
-         */
-        if (templateResolution.getValidity().isCacheable() && this.templateCache != null) {
-
-            // Put the new template into cache
-            this.templateCache.put(cacheKey, templateModel);
-
-        }
-
-
-        /*
-         * Return the throttled template processor
-         */
-        return new ThrottledTemplateProcessor(
-                templateSpec, engineContext, templateModel, processingHandlerChain,
-                processorTemplateHandler, flowController, throttledTemplateWriter);
-
-    }
-
-
-
-
-
-
-    private static TemplateResolution resolveTemplate(
-            final IEngineConfiguration configuration,
-            final IContext context,
-            final String ownerTemplate,
-            final String template,
-            final Map<String, Object> templateResolutionAttributes,
-            final boolean failIfNotExists) {
-
-        // Note that the MARKUP SELECTORS that might be used for a executing or inserting a template
-        // are not specified to the template resolver. The reason is markup selectors are applied by the parser,
-        // not the template resolvers, and allowing the resolver to take any decisions based on markup selectors
-        // (like e.g. omitting some output from the resource) could harm the correctness of the selection operation
-        // performed by the parser.
-
-        for (final ITemplateResolver templateResolver : configuration.getTemplateResolvers()) {
-
-            final TemplateResolution templateResolution =
-                    templateResolver.resolveTemplate(configuration, context, ownerTemplate, template, templateResolutionAttributes);
-            if (templateResolution != null) {
-                if (logger.isTraceEnabled()) {
-                    logger.trace(
-                            "[THYMELEAF][{}] Template resolver match! Resolver \"{}\" will resolve template \"{}\"",
-                            new Object[] {TemplateEngine.threadIndex(), templateResolver.getName(), LoggingUtils.loggifyTemplateName(template)});
-                }
-                return templateResolution;
-            }
-
-            if (logger.isTraceEnabled()) {
-                    logger.trace(
-                            "[THYMELEAF][{}] Skipping template resolver \"{}\" for template \"{}\"",
-                            new Object[] {TemplateEngine.threadIndex(), templateResolver.getName(), LoggingUtils.loggifyTemplateName(template)});
-            }
-
-        }
-
-        if (!failIfNotExists) {
-            // In this case we will not consider that a "not exists" means a failure. Maybe we are in a scenario
-            // (e.g. some types of operations with FragmentExpressions) in which we desire this.
-            return null;
-        }
-
-        throw new TemplateInputException(
-                "Error resolving template \"" + LoggingUtils.loggifyTemplateName(template) + "\", " +
-                "template might not exist or might not be accessible by " +
-                "any of the configured Template Resolvers");
-
-    }
-
-
-
-
-    private static TemplateData buildTemplateData(
-            final TemplateResolution templateResolution,
-            final String template,
-            final Set<String> templateSelectors,
-            final TemplateMode templateMode,
-            final boolean useCache) {
-
-        final TemplateMode definitiveTemplateMode =
-                (templateMode == null ? templateResolution.getTemplateMode() : templateMode);
-
-        final ICacheEntryValidity definitiveCacheEntryValidity =
-                (useCache? templateResolution.getValidity() : NonCacheableCacheEntryValidity.INSTANCE);
-
-        return new TemplateData(
-                template, templateSelectors, templateResolution.getTemplateResource(), definitiveTemplateMode, definitiveCacheEntryValidity);
-
-
-    }
-
-
-
-
-    private ITemplateParser getParserForTemplateMode(final TemplateMode templateMode) {
-        switch (templateMode) {
-            case HTML:       return this.htmlParser;
-            case XML:        return this.xmlParser;
-            case TEXT:       return this.textParser;
-            case JAVASCRIPT: return this.javascriptParser;
-            case CSS:        return this.cssParser;
-            case RAW:        return this.rawParser;
-            default:
-                throw new IllegalArgumentException("No parser exists for template mode: " + templateMode);
-        }
-    }
-
-
-
-
-
-    private static ITemplateHandler createTemplateProcessingHandlerChain(
-            final IEngineContext context,
-            final boolean setPreProcessors, final boolean setPostProcessors,
-            final ITemplateHandler handler, final Writer writer) {
-
-        final IEngineConfiguration configuration = context.getConfiguration();
-
-        /*
-         * Declare the pair of pointers that will allow us to build the chain of template handlers
-         */
-        ITemplateHandler firstHandler = null;
-        ITemplateHandler lastHandler = null;
-
-        /*
-         * First type of handlers to be added: pre-processors (if any)
-         */
-        if (setPreProcessors) {
-            final Set<IPreProcessor> preProcessors = configuration.getPreProcessors(context.getTemplateMode());
-            if (preProcessors != null && preProcessors.size() > 0) {
-                for (final IPreProcessor preProcessor : preProcessors) {
-                    final Class<? extends ITemplateHandler> preProcessorClass = preProcessor.getHandlerClass();
-                    final ITemplateHandler preProcessorHandler;
-                    try {
-                        preProcessorHandler = preProcessorClass.newInstance();
-                    } catch (final Exception e) {
-                        // This should never happen - class was already checked during configuration to contain a zero-arg constructor
-                        throw new TemplateProcessingException(
-                                "An exception happened during the creation of a new instance of pre-processor " + preProcessorClass.getClass().getName(), e);
-                    }
-                    // Initialize the pre-processor
-                    preProcessorHandler.setContext(context);
-                    if (firstHandler == null) {
-                        firstHandler = preProcessorHandler;
-                        lastHandler = preProcessorHandler;
-                    } else {
-                        lastHandler.setNext(preProcessorHandler);
-                        lastHandler = preProcessorHandler;
-                    }
-                }
-            }
-        }
-
-
-        /*
-         * Initialize and add to the chain te Processor Handler itself, the central piece of the chain
-         */
-        handler.setContext(context);
-        if (firstHandler == null) {
-            firstHandler = handler;
-            lastHandler = handler;
-        } else {
-            lastHandler.setNext(handler);
-            lastHandler = handler;
-        }
-
-
-        /*
-         * After the Processor Handler, we now must add the post-processors (if any)
-         */
-        if (setPostProcessors) {
-            final Set<IPostProcessor> postProcessors = configuration.getPostProcessors(context.getTemplateMode());
-            if (postProcessors != null && postProcessors.size() > 0) {
-                for (final IPostProcessor postProcessor : postProcessors) {
-                    final Class<? extends ITemplateHandler> postProcessorClass = postProcessor.getHandlerClass();
-                    final ITemplateHandler postProcessorHandler;
-                    try {
-                        postProcessorHandler = postProcessorClass.newInstance();
-                    } catch (final Exception e) {
-                        // This should never happen - class was already checked during configuration to contain a zero-arg constructor
-                        throw new TemplateProcessingException(
-                                "An exception happened during the creation of a new instance of post-processor " + postProcessorClass.getClass().getName(), e);
-                    }
-                    // Initialize the pre-processor
-                    postProcessorHandler.setContext(context);
-                    if (firstHandler == null) {
-                        firstHandler = postProcessorHandler;
-                        lastHandler = postProcessorHandler;
-                    } else {
-                        lastHandler.setNext(postProcessorHandler);
-                        lastHandler = postProcessorHandler;
-                    }
-                }
-            }
-        }
-
-
-        /*
-         * Last step: the OUTPUT HANDLER
-         */
-        if (writer != null) {
-            final OutputTemplateHandler outputHandler = new OutputTemplateHandler(writer);
-            outputHandler.setContext(context);
-            if (firstHandler == null) {
-                firstHandler = outputHandler;
-            } else {
-                lastHandler.setNext(outputHandler);
-            }
-        }
-
-        return firstHandler;
-
-    }
-
-
-
-
-}
diff --git a/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java
deleted file mode 100755
index e3eb4cf..0000000
--- a/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * =============================================================================
- * 
- *   Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org)
- * 
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- * 
- *       http://www.apache.org/licenses/LICENSE-2.0
- * 
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- * 
- * =============================================================================
- */
-package org.thymeleaf.templateresolver;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.thymeleaf.IEngineConfiguration;
-import org.thymeleaf.cache.ICacheEntryValidity;
-import org.thymeleaf.context.IContext;
-import org.thymeleaf.templatemode.TemplateMode;
-import org.thymeleaf.templateresource.ITemplateResource;
-import org.thymeleaf.util.PatternSpec;
-import org.thymeleaf.util.Validate;
-
-
-/**
- * <p>
- *   Convenience base class for all Template Resolvers.
- * </p>
- * <p>
- *   Note a class with this name existed since 1.0, but it was completely reimplemented
- *   in Thymeleaf 3.0
- * </p>
- *
- * @author Daniel Fern&aacute;ndez
- * 
- * @since 3.0.0
- *
- */
-public abstract class AbstractTemplateResolver implements ITemplateResolver {
-
-    /**
-     * <p>
-     *   By default, resources will not be checked their existence before being returned. This tries to
-     *   avoid a possible performance impact from performing a double access to the resource (one for checking
-     *   existence, another one for reading it).
-     * </p>
-     */
-    public static final boolean DEFAULT_EXISTENCE_CHECK = false;
-
-    /**
-     * <p>
-     *   By default, resources will not be marked to look for decoupled logic.
-     * </p>
-     */
-    public static final boolean DEFAULT_USE_DECOUPLED_LOGIC = false;
-
-    
-    private String name = this.getClass().getName();
-    private Integer order = null;
-    private boolean checkExistence = DEFAULT_EXISTENCE_CHECK;
-    private boolean useDecoupledLogic = DEFAULT_USE_DECOUPLED_LOGIC;
-
-    private final PatternSpec resolvablePatternSpec = new PatternSpec();
-    
-
-
-
-    protected AbstractTemplateResolver() {
-        super();
-    }
-
-
-
-    /**
-     * <p>
-     *   Returns the name of the template resolver
-     * </p>
-     * 
-     * @return the name of the template resolver
-     */
-    public final String getName() {
-        return this.name;
-    }
-
-
-    /**
-     * <p>
-     *   Sets a new name for the Template Resolver.
-     * </p>
-     * 
-     * @param name the new name
-     */
-    public void setName(final String name) {
-        this.name = name;
-    }
-    
-    
-    /**
-     * <p>
-     *   Returns the order in which this template resolver will be asked to resolve
-     *   templates as a part of the chain of resolvers configured into the template engine.
-     * </p>
-     * <p>
-     *   Order should start with 1.
-     * </p>
-     * 
-     * @return the order in which this template resolver will be called in the chain.
-     */
-    public final Integer getOrder() {
-        return this.order;
-    }
-
-
-    /**
-     * <p>
-     *   Sets a new order for the template engine in the chain. Order should start with 1.
-     * </p>
-     * 
-     * @param order the new order.
-     */
-    public void setOrder(final Integer order) {
-        this.order = order;
-    }
-    
-    
-
-    
-    /**
-     * <p>
-     *   Returns the <i>pattern spec</i> specified for establishing which
-     *   templates can be resolved by this template resolver. For those templates
-     *   which names do not match this patterns, the Template Resolver will return null.
-     * </p>
-     * <p>
-     *   This allows for a fast discard of those templates that the developer might
-     *   know for sure that will not be resolvable by the Resource Resolver used by
-     *   this Template Resolver, so that an execution of the resource resolver is not needed.
-     * </p>
-     * 
-     * @return the pattern spec
-     */
-    public final PatternSpec getResolvablePatternSpec() {
-        return this.resolvablePatternSpec;
-    }
-    
-    /**
-     * <p>
-     *   Returns the <i>patterns</i> (as String) specified for establishing which
-     *   templates can be resolved by this template resolver. For those templates
-     *   which names do not match this patterns, the Template Resolver will return null.
-     * </p>
-     * <p>
-     *   This allows for a fast discard of those templates that the developer might
-     *   know for sure that will not be resolvable by the Resource Resolver used by
-     *   this Template Resolver, so that an execution of the resource resolver is not needed.
-     * </p>
-     * <p>
-     *   This is a convenience method equivalent to {@link #getResolvablePatternSpec()}.getPatterns()
-     * </p>
-     * 
-     * @return the pattern spec
-     */
-    public final Set<String> getResolvablePatterns() {
-        return this.resolvablePatternSpec.getPatterns();
-    }
-
-    /**
-     * <p>
-     *   Sets the new <i>patterns</i> to be applied for establishing which
-     *   templates can be resolved by this template resolver. For those templates
-     *   which names do not match this patterns, the Template Resolver will return null.
-     * </p>
-     * <p>
-     *   This allows for a fast discard of those templates that the developer might
-     *   know for sure that will not be resolvable by the Resource Resolver used by
-     *   this Template Resolver, so that an execution of the resource resolver is not needed.
-     * </p>
-     * <p>
-     *   This is a convenience method equivalent to {@link #getResolvablePatternSpec()}.setPatterns(Set&lt;String&gt;)
-     * </p>
-     * 
-     * @param resolvablePatterns the new patterns
-     */
-    public void setResolvablePatterns(final Set<String> resolvablePatterns) {
-        this.resolvablePatternSpec.setPatterns(resolvablePatterns);
-    }
-
-
-
-    /**
-     * <p>
-     *   Returns whether template resources will be checked for existence before being returned or not.
-     * </p>
-     * <p>
-     *   Default value is <tt>FALSE</tt>.
-     * </p>
-     * <p>
-     *   Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()}
-     *   for each resolved resource before returning a {@link TemplateResolution}, returning <tt>null</tt> if the
-     *   resource does not exist.
-     * </p>
-     * <p>
-     *   This allows resolvers to pass control to the next {@link ITemplateResolver} in
-     *   the chain based on real resource existence and not only on the matching performed by the <em>resolvable
-     *   patterns</em> specified at {@link #getResolvablePatterns()}. But at the same time, might pose a performance
-     *   issue on certain scenarios (e.g. HTTP URL resolution) that require actually accessing the resource in order
-     *   to determine its existence, being the resource accessed twice in those cases (once for determining its
-     *   existence, another time for reading it).
-     * </p>
-     * <p>
-     *   If this <em>existence check</em> is enabled and a resource is determined to not exist,
-     *   {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, IContext, String, String, Map)} will return <tt>null</tt>.
-     * </p>
-     *
-     * @return <tt>true</tt> if resource existence will be checked, <tt>false</tt> if not
-     *
-     * @since 3.0.0
-     *
-     */
-    public final boolean getCheckExistence() {
-        return this.checkExistence;
-    }
-
-
-    /**
-     * <p>
-     *   Sets whether template resources will be checked for existence before being returned or not.
-     * </p>
-     * <p>
-     *   Default value is <tt>FALSE</tt>.
-     * </p>
-     * <p>
-     *   Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()}
-     *   for each resolved resource before returning a {@link TemplateResolution}, returning <tt>null</tt> if the
-     *   resource does not exist.
-     * </p>
-     * <p>
-     *   This allows resolvers to pass control to the next {@link ITemplateResolver} in
-     *   the chain based on real resource existence and not only on the matching performed by the <em>resolvable
-     *   patterns</em> specified at {@link #getResolvablePatterns()}. But at the same time, might pose a performance
-     *   issue on certain scenarios (e.g. HTTP URL resolution) that require actually accessing the resource in order
-     *   to determine its existence, being the resource accessed twice in those cases (once for determining its
-     *   existence, another time for reading it).
-     * </p>
-     * <p>
-     *   If this <em>existence check</em> is enabled and a resource is determined to not exist,
-     *   {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, IContext, String, String, Map)} will return <tt>null</tt>.
-     * </p>
-     *
-     * @param checkExistence <tt>true</tt> if resource existence should be checked, <tt>false</tt> if not
-     *
-     * @since 3.0.0
-     *
-     */
-    public void setCheckExistence(final boolean checkExistence) {
-        this.checkExistence = checkExistence;
-    }
-
-
-
-    /**
-     * <p>
-     *   Returns whether a separate (decoupled) resource containing template logic should be checked for existence
-     *   and its instructions included into the resolved template during parsing.
-     * </p>
-     * <p>
-     *   This mechanism allows the creation of <em>pure</em> HTML or XML markup templates, which acquire their logic
-     *   from an external resource. The way this decoupled resources are resolved is defined by a configured
-     *   implementation of the {@link org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver}
-     *   interface.
-     * </p>
-     * <p>
-     *   Note this flag can only be <tt>true</tt> for the {@link TemplateMode#HTML} and {@link TemplateMode#XML}
-     *   template modes. Also, note that setting this flag to <tt>true</tt> does not mean that a resource with
-     *   decoupled logic must exist for the resolved template, only that it can exist.
-     * </p>
-     * <p>
-     *   Decoupled logic extracted from these additional resources is injected into the resolved templates in real-time
-     *   as the resolved templates are parsed and processed. This greatly reduces overhead caused by decoupled parsing
-     *   for non-cacheable templates, and completely removes any overhead for cached templates.
-     * </p>
-     * <p>
-     *   Default value is <tt>FALSE</tt>.
-     * </p>
-     *
-     * @return <tt>true</tt> if decoupled logic resources should be checked, <tt>false</tt> if not.
-     *
-     * @since 3.0.0
-     *
-     */
-    public final boolean getUseDecoupledLogic() {
-        return this.useDecoupledLogic;
-    }
-
-
-    /**
-     * <p>
-     *   Sets whether a separate (decoupled) resource containing template logic should be checked for existence
-     *   and its instructions included into the resolved template during parsing.
-     * </p>
-     * <p>
-     *   This mechanism allows the creation of <em>pure</em> HTML or XML markup templates, which acquire their logic
-     *   from an external resource. The way this decoupled resources are resolved is defined by a configured
-     *   implementation of the {@link org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver}
-     *   interface.
-     * </p>
-     * <p>
-     *   Note this flag can only be <tt>true</tt> for the {@link TemplateMode#HTML} and {@link TemplateMode#XML}
-     *   template modes. Also, note that setting this flag to <tt>true</tt> does not mean that a resource with
-     *   decoupled logic must exist for the resolved template, only that it can exist and therefore it should be
-     *   checked.
-     * </p>
-     * <p>
-     *   Decoupled logic extracted from these additional resources is injected into the resolved templates in real-time
-     *   as the resolved templates are parsed and processed. This greatly reduces overhead caused by decoupled parsing
-     *   for non-cacheable templates, and completely removes any overhead for cached templates.
-     * </p>
-     * <p>
-     *   Default value is <tt>FALSE</tt>.
-     * </p>
-     *
-     * @param useDecoupledLogic <tt>true</tt> if resource existence should be checked, <tt>false</tt> if not
-     *
-     * @since 3.0.0
-     *
-     */
-    public void setUseDecoupledLogic(final boolean useDecoupledLogic) {
-        this.useDecoupledLogic = useDecoupledLogic;
-    }
-
-
-
-
-    public final TemplateResolution resolveTemplate(
-        final IEngineConfiguration configuration,
-        final IContext context,
-        final String ownerTemplate, final String template,
-        final Map<String, Object> templateResolutionAttributes) {
-
-        Validate.notNull(configuration, "Engine Configuration cannot be null");
-        // ownerTemplate CAN be null
-        Validate.notNull(template, "Template Name cannot be null");
-        // templateResolutionAttributes CAN be null
-
-        if (!computeResolvable(configuration, ownerTemplate, template, templateResolutionAttributes)) {
-            return null;
-        }
-
-        final ITemplateResource templateResource = computeTemplateResource(configuration, ownerTemplate, template, templateResolutionAttributes);
-        if (templateResource == null) {
-            return null;
-        }
-
-        if (this.checkExistence && !templateResource.exists()) { // will only check if flag set to true
-            return null;
-        }
-
-        return new TemplateResolution(
-                templateResource,
-                this.checkExistence,
-                computeTemplateMode(configuration, ownerTemplate, template, templateResolutionAttributes),
-                this.useDecoupledLogic,
-                computeValidity(configuration, ownerTemplate, template, templateResolutionAttributes));
-        
-    }
-    
-    
-    
-    
-    /**
-     * <p>
-     *   Computes whether a template can be resolved by this resolver or not, 
-     *   applying the corresponding patterns. Meant only for use or override by subclasses.
-     * </p>
-     *
-     * @param configuration the engine configuration.
-     * @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
-     * @param template the template to be resolved (usually its name).
-     * @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
-     *
-     * @return whether the template is resolvable or not.
-     */
-    protected boolean computeResolvable(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes) {
-        if (this.resolvablePatternSpec.isEmpty()) {
-            return true;
-        }
-        return this.resolvablePatternSpec.matches(template);
-    }
-
-
-
-
-    
-    
-    /**
-     * <p>
-     *   Computes the resolved template resource.
-     * </p>
-     *
-     * @param configuration the engine configuration.
-     * @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
-     * @param template the template to be resolved (usually its name).
-     * @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
-     *
-     * @return the template resource, or null if this template cannot be resolved (or the resource does not exist).
-     */
-    protected abstract ITemplateResource computeTemplateResource(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes);
-
-    
-    
-    /**
-     * <p>
-     *   Computes the template mode that should be applied to a template, according
-     *   to existing configuration.
-     * </p>
-     *
-     * @param configuration the engine configuration.
-     * @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
-     * @param template the template to be resolved (usually its name).
-     * @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
-     *
-     * @return the template mode proposed by the template resolver for the resolved template.
-     */
-    protected abstract TemplateMode computeTemplateMode(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes);
-    
-    
-    
-    /**
-     * <p>
-     *   Computes the validity to be applied to the template resolution. This
-     *   includes determining whether the template can be cached or not, and
-     *   also in what circumstances (for instance, for how much time) can
-     *   its cache entry be considered valid.
-     * </p>
-     *
-     * @param configuration the engine configuration.
-     * @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
-     * @param template the template to be resolved (usually its name).
-     * @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
-     * @return the validity
-     */
-    protected abstract ICacheEntryValidity computeValidity(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes);
-    
-    
-    
-}
diff --git a/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java
deleted file mode 100755
index eb4fc55..0000000
--- a/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * =============================================================================
- * 
- *   Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org)
- * 
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- * 
- *       http://www.apache.org/licenses/LICENSE-2.0
- * 
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- * 
- * =============================================================================
- */
-package org.thymeleaf.templateresolver;
-
-import java.util.Map;
-
-import org.thymeleaf.IEngineConfiguration;
-import org.thymeleaf.context.IContext;
-import org.thymeleaf.templatemode.TemplateMode;
-import org.thymeleaf.templateresource.ITemplateResource;
-
-/**
- * <p>
- *   Interface for all Template Resolvers.
- * </p>
- * <p>
- *   Template resolvers are in charge of resolving templates into
- *   {@link TemplateResolution} objects that contain additional information related to
- *   the template like:
- * </p>
- * <ul>
- *   <li>Its corresponding <i>template resource</i> (see
- *       {@link org.thymeleaf.templateresource.ITemplateResource}).</li>
- *   <li>The Template Mode to be applied to this template: {@link TemplateMode}</li>
- *   <li>Whether the template can be cached or not.</li>
- *   <li>If the template can be cached, (optionally) the time it will live in cache.</li>
- * </ul>
- * <p>
- *   The Template Resolver will usually get all this information from a set of configurations
- *   like applicability patterns, template mode patterns, etc. Each {@link ITemplateResolver}
- *   implementation will provide its own set of methods for specifying such configurations. 
- * </p>
- * <p>
- *   The fact that a Template Resolver returns a {@link TemplateResolution} does not necessarily
- *   mean that the resolved template resource exists. It might only be so if the template resolver
- *   is configured to perform an <em>existence check</em> on the resource before returning a resolution
- *   result (by means of calling {@link ITemplateResource#exists()}), which might be configurable on
- *   a per-{@link ITemplateResolver}-implementation basis. Implementations might choose not to check
- *   resource existance by default in order to avoid the possible performance impact of a double access
- *   to the resource.
- * </p>
- * <p>
- *   A Template Engine can be configured several template resolvers, and these will
- *   be asked in order (according to the value returned by {@link #getOrder()}) to return
- *   a {@link TemplateResolution} object for each template name. If a template resolver
- *   returns null for a specific resolution, the next one in the chain is asked. Template Resolvers
- *   that are not configured an order will be executed last in the chain.
- * </p>
- * <p>
- *   Implementations of this interface should be <strong>thread-safe</strong>.
- * </p>
- * <p>
- *   Note a class with this name existed since 1.0, but it was completely reimplemented
- *   in Thymeleaf 3.0
- * </p>
- * 
- * @author Daniel Fern&aacute;ndez
- *
- * @see ITemplateResource
- * @see ClassLoaderTemplateResolver
- * @see FileTemplateResolver
- * @see ServletContextTemplateResolver
- * @see StringTemplateResolver
- * @see UrlTemplateResolver
- *
- * @since 3.0.0
- *
- */
-public interface ITemplateResolver {
-
-    
-    /**
-     * <p>
-     *   Returns the name of this template resolver. Used in logs and configuration
-     *   details.
-     * </p>
-     * 
-     * @return the template resolver name.
-     */
-    public String getName();
-
-    
-    /**
-     * <p>
-     *   Return the order in which this template resolver will be executed in the
-     *   chain when several template resolvers are set for the same Template Engine.
-     * </p>
-     * 
-     * @return the order of this resolver in the chain.
-     */
-    public Integer getOrder();
-
-
-    /**
-     * <p>
-     *   Tries to resolve a template.
-     * </p>
-     * <p>
-     *   The method arguments contain all the info needed for trying to
-     *   resolve the template. The Template Resolver will apply its configuration
-     *   (prefixes/suffixes, template mode patterns, cache configurations, etc) and
-     *   return a {@link TemplateResolution} object.
-     * </p>
-     * <p>
-     *   The <tt>ownerTemplate</tt>, which might be null, will be specified when the template
-     *   is resolved in order to be used as a fragent to be inserted into a higher level
-     *   template (the <em>owner</em>). Most template resolver implementations will simply ignore
-     *   this argument, but others might change their resolution results depending on the
-     *   owner template that is inserting the resolved fragment.
-     * </p>
-     * <p>
-     *   The fact that a Template Resolver returns a {@link TemplateResolution} does not necessarily
-     *   mean that the resolved template resource exists. It might only be so if the template resolver
-     *   is configured to perform an <em>existence check</em> on the resource before returning a resolution
-     *   result (by means of calling {@link ITemplateResource#exists()}), which might be configurable on
-     *   a per-{@link ITemplateResolver}-implementation basis. Implementations might choose not to check
-     *   resource existance by default in order to avoid the possible performance impact of a double access
-     *   to the resource.
-     * </p>
-     * <p>
-     *   Note that the <em>template selectors</em> that might be used for a executing or inserting a template
-     *   are not specified to the template resolver. The reason is template selectors are applied by the parser,
-     *   not the template resolvers, and allowing the resolver to take any decisions based on template selectors
-     *   (like e.g. omitting some output from the resource) could harm the correctness of the selection operation
-     *   performed by the parser.
-     * </p>
-     * 
-     * @param configuration the engine configuration.
-     * @param context the context
-     * @param ownerTemplate the containing template from which we want to resolve a new one as a fragment. Can be null.
-     * @param template the template to be resolved (usually its name).
-     * @param templateResolutionAttributes the template resolution attributes to be used (usually coming from a
-     *                                     {@link org.thymeleaf.TemplateSpec} instance. Can be null.
-     * @return a TemplateResolution object (which might represent an existing resource or not), or null if the
-     *         template could not be resolved.
-     */
-    public TemplateResolution resolveTemplate(
-        final IEngineConfiguration configuration,
-        final IContext context,
-        final String ownerTemplate, final String template,
-        final Map<String, Object> templateResolutionAttributes);
-
-}
diff --git a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
index f059f1c..c819b3f 100644
--- a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
+++ b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
@@ -45,6 +45,7 @@
 import static org.ops4j.pax.exam.CoreOptions.composite;
 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
 
 public abstract class ThymeleafTestSupport extends TestSupport {
 
@@ -77,6 +78,7 @@
             quickstart(),
             // Sling Scripting Thymeleaf
             testBundle("bundle.filename"),
+            wrappedBundle(mavenBundle().groupId("org.thymeleaf").artifactId("thymeleaf").versionAsInProject()),
             mavenBundle().groupId("org.attoparser").artifactId("attoparser").versionAsInProject(),
             mavenBundle().groupId("org.unbescape").artifactId("unbescape").versionAsInProject(),
             mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.ognl").versionAsInProject(),
diff --git a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/html/LinkBuilderIT.java b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/html/LinkBuilderIT.java
index f93a41c..a5649d4 100644
--- a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/html/LinkBuilderIT.java
+++ b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/html/LinkBuilderIT.java
@@ -55,7 +55,7 @@
     @Test
     public void testBarLink() throws IOException {
         final Element link = document.getElementById("bar");
-        assertThat(link.attributes().get("href"), is("bar"));
+        assertThat(link.attributes().get("href"), is("/thymeleaf/bar"));
     }
 
 }