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á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á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<String>)
- * </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á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"));
}
}