You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:12:18 UTC
[sling-org-apache-sling-scripting-thymeleaf] 02/17: SLING-3649 make
Thymeleaf scripting configurable and extensible
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.scripting.thymeleaf-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-thymeleaf.git
commit accb73b10b0fb49b2a0175dea07c729d1961a943
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jun 10 15:07:36 2014 +0000
SLING-3649 make Thymeleaf scripting configurable and extensible
- out of the box support for legacy HTML5 through embedded NekoHTML
- runtime configurable TemplateModeHandlers for XML, VALIDXML, XHTML, VALIDXHTML, HTML5 and LEGACYHTML5
- MessageResolver backed by ResourceBundleProvider from org.apache.sling.i18n
- uses UTF-8 charset for reading templates (not configurable)
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/thymeleaf@1601661 13f79535-47bb-0310-9956-ffa450edef68
---
README.md | 10 +-
pom.xml | 23 +++-
.../sling/scripting/thymeleaf/SlingContext.java | 27 +---
...Resolver.java => SlingTemplateModeHandler.java} | 26 +---
.../scripting/thymeleaf/SlingTemplateResolver.java | 62 ---------
.../sling/scripting/thymeleaf/SlingWebContext.java | 123 +++++++++++++++++
.../scripting/thymeleaf/ThymeleafScriptEngine.java | 31 +++--
.../thymeleaf/ThymeleafScriptEngineFactory.java | 138 ++++++++++++++++---
.../thymeleaf/impl/NonCachingTemplateResolver.java | 148 +++++++++++++++++++++
.../impl/ResourceBundleMessageResolver.java | 123 +++++++++++++++++
.../ScriptReaderResourceResolver.java} | 28 +++-
.../AbstractTemplateModeHandler.java | 110 +++++++++++++++
.../Html5TemplateModeHandler.java | 64 +++++++++
.../LegacyHtml5TemplateModeHandler.java | 64 +++++++++
.../ValidatingXhtmlTemplateModeHandler.java | 64 +++++++++
.../ValidatingXmlTemplateModeHandler.java | 64 +++++++++
.../XhtmlTemplateModeHandler.java | 64 +++++++++
.../XmlTemplateModeHandler.java | 64 +++++++++
.../OSGI-INF/metatype/metatype.properties | 43 +++++-
19 files changed, 1125 insertions(+), 151 deletions(-)
diff --git a/README.md b/README.md
index 693fcae..85faa4d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,15 @@
Apache Sling Scripting Thymeleaf
================================
-scripting engine for Thymeleaf templates
+scripting engine for _Thymeleaf_ templates
* http://www.thymeleaf.org
* https://github.com/thymeleaf/thymeleaf
+
+Features
+--------
+
+* out of the box support for _legacy_ HTML5 through embedded _NekoHTML_
+* runtime configurable `TemplateModeHandler`s for _XML_, _VALIDXML_, _XHTML_, _VALIDXHTML_, _HTML5_ and _LEGACYHTML5_
+* `MessageResolver` backed by `ResourceBundleProvider` from `org.apache.sling.i18n`
+* uses `UTF-8` charset for reading templates
diff --git a/pom.xml b/pom.xml
index 9d0ef77..c14df0a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,7 +38,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <sling.java.version>7</sling.java.version>
+ <sling.java.version>6</sling.java.version>
</properties>
<scm>
@@ -60,6 +60,11 @@
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
<!-- Apache Commons -->
<dependency>
<groupId>commons-io</groupId>
@@ -80,6 +85,18 @@
<version>2.1.6</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.osgi</artifactId>
+ <version>2.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.i18n</artifactId>
+ <version>2.2.8</version>
+ <scope>provided</scope>
+ </dependency>
<!-- Apache Felix -->
<dependency>
<groupId>org.apache.felix</groupId>
@@ -127,8 +144,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
- <source>1.7</source>
- <target>1.7</target>
+ <source>1.6</source>
+ <target>1.6</target>
</configuration>
</plugin>
<plugin>
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
index 733614a..a4fc418 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
@@ -19,32 +19,11 @@
package org.apache.sling.scripting.thymeleaf;
import java.io.Reader;
-import java.util.Locale;
-import java.util.Map;
-import org.thymeleaf.context.Context;
+import org.thymeleaf.context.IContext;
-// TODO WebContext?
-public class SlingContext extends Context {
+public interface SlingContext extends IContext {
- private final Reader reader;
-
- public SlingContext(final Reader reader) {
- this.reader = reader;
- }
-
- public SlingContext(Locale locale, final Reader reader) {
- super(locale);
- this.reader = reader;
- }
-
- public SlingContext(Locale locale, Map<String, ?> variables, final Reader reader) {
- super(locale, variables);
- this.reader = reader;
- }
-
- public Reader getReader() {
- return reader;
- }
+ Reader getReader();
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateModeHandler.java
similarity index 56%
rename from src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java
rename to src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateModeHandler.java
index cf811e0..abb35c8 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateModeHandler.java
@@ -18,29 +18,11 @@
*/
package org.apache.sling.scripting.thymeleaf;
-import org.thymeleaf.Arguments;
-import org.thymeleaf.messageresolver.IMessageResolver;
-import org.thymeleaf.messageresolver.MessageResolution;
+import org.thymeleaf.PatternSpec;
+import org.thymeleaf.templatemode.ITemplateModeHandler;
-public class SlingMessageResolver implements IMessageResolver {
+public interface SlingTemplateModeHandler extends ITemplateModeHandler {
- @Override
- public String getName() {
- return getClass().getSimpleName();
- }
-
- @Override
- public Integer getOrder() {
- return 0; // TODO make configurable
- }
-
- @Override
- public MessageResolution resolveMessage(final Arguments arguments, final String key, final Object[] messageParameters) {
- return new MessageResolution("TODO"); // TODO
- }
-
- @Override
- public void initialize() {
- }
+ PatternSpec getPatternSpec();
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java
deleted file mode 100644
index 173a31a..0000000
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java
+++ /dev/null
@@ -1,62 +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.nio.charset.StandardCharsets;
-
-import org.thymeleaf.TemplateProcessingParameters;
-import org.thymeleaf.templatemode.StandardTemplateModeHandlers;
-import org.thymeleaf.templateresolver.ITemplateResolutionValidity;
-import org.thymeleaf.templateresolver.ITemplateResolver;
-import org.thymeleaf.templateresolver.NonCacheableTemplateResolutionValidity;
-import org.thymeleaf.templateresolver.TemplateResolution;
-
-public class SlingTemplateResolver implements ITemplateResolver {
-
- final SlingResourceResolver resourceResolver;
-
- public SlingTemplateResolver(final SlingResourceResolver resourceResolver) {
- this.resourceResolver = resourceResolver;
- }
-
- @Override
- public String getName() {
- return getClass().getSimpleName();
- }
-
- @Override
- public Integer getOrder() {
- return 0; // TODO make configurable
- }
-
- @Override
- public TemplateResolution resolveTemplate(TemplateProcessingParameters templateProcessingParameters) {
- final String templateName = templateProcessingParameters.getTemplateName();
- final String resourceName = templateName; // TODO
- final String characterEncoding = StandardCharsets.UTF_8.name();
- final String templateMode = StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName(); // TODO make configurable
- final ITemplateResolutionValidity validity = new NonCacheableTemplateResolutionValidity(); // TODO
- return new TemplateResolution(templateName, resourceName, resourceResolver, characterEncoding, templateMode, validity);
- }
-
- @Override
- public void initialize() {
- }
-
-}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingWebContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingWebContext.java
new file mode 100644
index 0000000..afbdfd8
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingWebContext.java
@@ -0,0 +1,123 @@
+/*
+ * 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.io.Reader;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.thymeleaf.context.AbstractContext;
+import org.thymeleaf.context.IWebContext;
+import org.thymeleaf.context.VariablesMap;
+import org.thymeleaf.context.WebContextExecutionInfo;
+import org.thymeleaf.util.Validate;
+
+public class SlingWebContext implements SlingContext, IWebContext {
+
+ private final Locale locale;
+
+ private final VariablesMap<String, Object> variables = new VariablesMap<String, Object>();
+
+ private final SlingHttpServletRequest servletRequest;
+
+ private final SlingHttpServletResponse servletResponse;
+
+ private final ServletContext servletContext;
+
+ private final Reader reader;
+
+ public SlingWebContext(final SlingHttpServletRequest servletRequest, final SlingHttpServletResponse servletResponse, final ServletContext servletContext, final Locale locale, final Map<String, ?> variables, final Reader reader) {
+ this.servletRequest = servletRequest;
+ this.servletResponse = servletResponse;
+ this.servletContext = servletContext;
+ this.locale = locale;
+ this.variables.putAll(variables);
+ this.reader = reader;
+ }
+
+ @Override
+ public SlingHttpServletRequest getHttpServletRequest() {
+ return servletRequest;
+ }
+
+ @Override
+ public SlingHttpServletResponse getHttpServletResponse() {
+ return servletResponse;
+ }
+
+ @Override
+ public HttpSession getHttpSession() {
+ return servletRequest.getSession(false);
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+ @Override
+ public VariablesMap<String, String[]> getRequestParameters() {
+ return null;
+ }
+
+ @Override
+ public VariablesMap<String, Object> getRequestAttributes() {
+ return null;
+ }
+
+ @Override
+ public VariablesMap<String, Object> getSessionAttributes() {
+ return null;
+ }
+
+ @Override
+ public VariablesMap<String, Object> getApplicationAttributes() {
+ return null;
+ }
+
+ @Override
+ public Reader getReader() {
+ return reader;
+ }
+
+ @Override
+ public VariablesMap<String, Object> getVariables() {
+ return variables;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ @Override
+ public void addContextExecutionInfo(String templateName) {
+ Validate.notEmpty(templateName, "Template name cannot be null or empty");
+ final Calendar now = Calendar.getInstance();
+ final WebContextExecutionInfo webContextExecutionInfo = new WebContextExecutionInfo(templateName, now);
+ variables.put(AbstractContext.EXEC_INFO_VARIABLE_NAME, webContextExecutionInfo);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java
index f21d6d7..91d4916 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java
@@ -23,22 +23,27 @@ import java.util.Locale;
import javax.script.Bindings;
import javax.script.ScriptContext;
-import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
+import javax.servlet.ServletContext;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
-import org.thymeleaf.TemplateEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.thymeleaf.context.IContext;
public class ThymeleafScriptEngine extends AbstractSlingScriptEngine {
- private final TemplateEngine templateEngine;
+ private final ThymeleafScriptEngineFactory thymeleafScriptEngineFactory;
- public ThymeleafScriptEngine(final ScriptEngineFactory scriptEngineFactory, final TemplateEngine templateEngine) {
- super(scriptEngineFactory);
- this.templateEngine = templateEngine;
+ private final Logger logger = LoggerFactory.getLogger(ThymeleafScriptEngine.class);
+
+ public ThymeleafScriptEngine(final ThymeleafScriptEngineFactory thymeleafScriptEngineFactory) {
+ super(thymeleafScriptEngineFactory);
+ this.thymeleafScriptEngineFactory = thymeleafScriptEngineFactory;
}
@Override
@@ -50,15 +55,19 @@ public class ThymeleafScriptEngine extends AbstractSlingScriptEngine {
throw new ScriptException("SlingScriptHelper missing from bindings");
}
- final Locale locale = helper.getRequest().getLocale();
+ final SlingHttpServletRequest request = helper.getRequest();
+ final SlingHttpServletResponse response = helper.getResponse();
+ final ServletContext servletContext = null; // only used by Thymeleaf's ServletContextResourceResolver
+
+ final Locale locale = helper.getResponse().getLocale();
final String scriptName = helper.getScript().getScriptResource().getPath();
try {
- final IContext context = new SlingContext(locale, bindings, reader);
- templateEngine.process(scriptName, context, scriptContext.getWriter());
+ final IContext context = new SlingWebContext(request, response, servletContext, locale, bindings, reader);
+ thymeleafScriptEngineFactory.getTemplateEngine().process(scriptName, context, scriptContext.getWriter());
} catch (Exception e) {
- final String message = String.format("Failure rendering Thymeleaf template '%s': %s", scriptName, e.getMessage());
- throw new ScriptException(message);
+ logger.error("Failure rendering Thymeleaf template '{}': {}", scriptName, e.getMessage());
+ throw new ScriptException(e);
}
return null;
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngineFactory.java
index 781770f..57eb200 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngineFactory.java
@@ -18,20 +18,36 @@
*/
package org.apache.sling.scripting.thymeleaf;
+import java.util.Dictionary;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
import javax.script.ScriptEngine;
+import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.thymeleaf.TemplateEngine;
+import org.thymeleaf.messageresolver.IMessageResolver;
+import org.thymeleaf.templateresolver.ITemplateResolver;
@Component(
- name = "org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory",
- label = "%org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.label",
- description = "%org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.description",
+ label = "Apache Sling Scripting Thymeleaf “Script Engine Factory”",
+ description = "scripting engine for Thymeleaf templates",
immediate = true,
metatype = true
)
@@ -43,30 +59,105 @@ import org.thymeleaf.TemplateEngine;
})
public class ThymeleafScriptEngineFactory extends AbstractScriptEngineFactory {
- private SlingResourceResolver resourceResolver;
-
- private SlingTemplateResolver templateResolver;
+ @Reference(referenceInterface = ITemplateResolver.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+ final private Set<ITemplateResolver> templateResolvers = new LinkedHashSet<ITemplateResolver>();
- private SlingMessageResolver messageResolver;
+ @Reference(referenceInterface = IMessageResolver.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+ final private Set<IMessageResolver> messageResolvers = new LinkedHashSet<IMessageResolver>();
private TemplateEngine templateEngine;
+ public static final String DEFAULT_EXTENSION = "html";
+
+ @Property(value = {DEFAULT_EXTENSION}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String EXTENSIONS_PARAMETER = "org.apache.sling.scripting.thymeleaf.extensions";
+
+ public static final String DEFAULT_MIMETYPE = "text/html";
+
+ @Property(value = {DEFAULT_MIMETYPE}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String MIMETYPES_PARAMETER = "org.apache.sling.scripting.thymeleaf.mimetypes";
+
+ public static final String DEFAULT_NAME = "thymeleaf";
+
+ @Property(value = {DEFAULT_NAME}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String NAMES_PARAMETER = "org.apache.sling.scripting.thymeleaf.names";
+
+ public static final String TEMPLATE_CHARSET = "UTF-8";
+
+ private final Logger logger = LoggerFactory.getLogger(ThymeleafScriptEngineFactory.class);
+
public ThymeleafScriptEngineFactory() {
- // TODO make configurable
- setExtensions("html");
- setMimeTypes("text/html");
- setNames("thymeleaf");
- setupThymeleaf();
}
- // TODO make configurable
- protected void setupThymeleaf() {
- resourceResolver = new SlingResourceResolver();
- templateResolver = new SlingTemplateResolver(resourceResolver);
- messageResolver = new SlingMessageResolver();
- templateEngine = new TemplateEngine();
- templateEngine.setTemplateResolver(templateResolver);
- templateEngine.setMessageResolver(messageResolver);
+ @Activate
+ private void activate(final ComponentContext componentContext) {
+ logger.debug("activate");
+ configure(componentContext);
+ configureTemplateEngine();
+ }
+
+ @Modified
+ private void modified(final ComponentContext componentContext) {
+ logger.debug("modified");
+ configure(componentContext);
+ configureTemplateEngine();
+ }
+
+ @Deactivate
+ private void deactivate(final ComponentContext componentContext) {
+ logger.debug("deactivate");
+ templateEngine = null;
+ }
+
+ protected void bindTemplateResolvers(final ITemplateResolver templateResolver) {
+ logger.debug("binding template resolver '{}'", templateResolver.getName());
+ templateResolvers.add(templateResolver);
+ configureTemplateEngine();
+ }
+
+ protected void unbindTemplateResolvers(final ITemplateResolver templateResolver) {
+ logger.debug("unbinding template resolver '{}'", templateResolver.getName());
+ templateResolvers.remove(templateResolver);
+ configureTemplateEngine();
+ }
+
+ protected void bindMessageResolvers(final IMessageResolver messageResolver) {
+ logger.debug("binding message resolver '{}'", messageResolver.getName());
+ messageResolvers.add(messageResolver);
+ configureTemplateEngine();
+ }
+
+ protected void unbindMessageResolvers(final IMessageResolver messageResolver) {
+ logger.debug("unbinding message resolver '{}'", messageResolver.getName());
+ messageResolvers.remove(messageResolver);
+ configureTemplateEngine();
+ }
+
+ private synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+
+ final String[] extensions = PropertiesUtil.toStringArray(properties.get(EXTENSIONS_PARAMETER), new String[]{DEFAULT_EXTENSION});
+ setExtensions(extensions);
+
+ final String[] mimeTypes = PropertiesUtil.toStringArray(properties.get(MIMETYPES_PARAMETER), new String[]{DEFAULT_MIMETYPE});
+ setMimeTypes(mimeTypes);
+
+ final String[] names = PropertiesUtil.toStringArray(properties.get(NAMES_PARAMETER), new String[]{DEFAULT_NAME});
+ setNames(names);
+ }
+
+ // the configuration of the Thymeleaf TemplateEngine is static and we need to recreate on modification
+ private synchronized void configureTemplateEngine() {
+ logger.info("configure template engine");
+ if (templateEngine == null || templateEngine.isInitialized()) {
+ templateEngine = new TemplateEngine();
+ }
+ if (templateResolvers.size() > 0) {
+ templateEngine.setTemplateResolvers(templateResolvers);
+ }
+ if (messageResolvers.size() > 0) {
+ templateEngine.setMessageResolvers(messageResolvers);
+ }
}
@Override
@@ -81,7 +172,12 @@ public class ThymeleafScriptEngineFactory extends AbstractScriptEngineFactory {
@Override
public ScriptEngine getScriptEngine() {
- return new ThymeleafScriptEngine(this, templateEngine);
+ logger.debug("get script engine for Thymeleaf");
+ return new ThymeleafScriptEngine(this);
+ }
+
+ TemplateEngine getTemplateEngine() {
+ return templateEngine;
}
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/NonCachingTemplateResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/NonCachingTemplateResolver.java
new file mode 100644
index 0000000..4d6af69
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/NonCachingTemplateResolver.java
@@ -0,0 +1,148 @@
+/*
+ * 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.impl;
+
+import java.util.Dictionary;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.scripting.thymeleaf.SlingTemplateModeHandler;
+import org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.thymeleaf.TemplateProcessingParameters;
+import org.thymeleaf.resourceresolver.IResourceResolver;
+import org.thymeleaf.templateresolver.ITemplateResolutionValidity;
+import org.thymeleaf.templateresolver.ITemplateResolver;
+import org.thymeleaf.templateresolver.NonCacheableTemplateResolutionValidity;
+import org.thymeleaf.templateresolver.TemplateResolution;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Non-Caching Template Resolver”",
+ description = "non-caching template resolver for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "non-caching template resolver for Sling Scripting Thymeleaf")
+})
+public class NonCachingTemplateResolver implements ITemplateResolver {
+
+ @Reference
+ private IResourceResolver resourceResolver;
+
+ @Reference(referenceInterface = SlingTemplateModeHandler.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+ final private Set<SlingTemplateModeHandler> templateModeHandlers = new LinkedHashSet<SlingTemplateModeHandler>();
+
+ private Integer order;
+
+ public static final int DEFAULT_ORDER = 0;
+
+ @Property(intValue = DEFAULT_ORDER)
+ public static final String ORDER_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.NonCachingTemplateResolver.order";
+
+ private final Logger logger = LoggerFactory.getLogger(NonCachingTemplateResolver.class);
+
+ public NonCachingTemplateResolver() {
+ }
+
+ @Activate
+ private void activate(final ComponentContext componentContext) {
+ logger.debug("activate");
+ configure(componentContext);
+ }
+
+ @Modified
+ private void modified(final ComponentContext componentContext) {
+ logger.debug("modified");
+ configure(componentContext);
+ }
+
+ @Deactivate
+ private void deactivate(final ComponentContext componentContext) {
+ logger.debug("deactivate");
+ }
+
+ protected void bindTemplateModeHandlers(final SlingTemplateModeHandler templateModeHandler) {
+ logger.debug("binding template mode handler '{}'", templateModeHandler.getTemplateModeName());
+ templateModeHandlers.add(templateModeHandler);
+ }
+
+ protected void unbindTemplateModeHandlers(final SlingTemplateModeHandler templateModeHandler) {
+ logger.debug("unbinding template mode handler '{}'", templateModeHandler.getTemplateModeName());
+ templateModeHandlers.remove(templateModeHandler);
+ }
+
+ private synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ order = PropertiesUtil.toInteger(properties.get(ORDER_PARAMETER), DEFAULT_ORDER);
+ }
+
+ @Override
+ public String getName() {
+ return getClass().getName();
+ }
+
+ @Override
+ public Integer getOrder() {
+ return order;
+ }
+
+ @Override
+ public TemplateResolution resolveTemplate(TemplateProcessingParameters templateProcessingParameters) {
+ final String templateName = templateProcessingParameters.getTemplateName();
+ final String resourceName = templateName; // TODO
+ final String characterEncoding = ThymeleafScriptEngineFactory.TEMPLATE_CHARSET;
+ final String templateMode = computeTemplateMode(templateName);
+ final ITemplateResolutionValidity validity = new NonCacheableTemplateResolutionValidity();
+ return new TemplateResolution(templateName, resourceName, resourceResolver, characterEncoding, templateMode, validity);
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+ protected String computeTemplateMode(final String templateName) {
+ for (final SlingTemplateModeHandler templateModeHandler : templateModeHandlers) {
+ final String templateMode = templateModeHandler.getTemplateModeName();
+ logger.debug("template mode handler '{}' with patterns {}", templateMode, templateModeHandler.getPatternSpec().getPatterns());
+ if (templateModeHandler.getPatternSpec().matches(templateName)) {
+ logger.debug("using template mode '{}' for template '{}'", templateMode, templateName);
+ return templateMode;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/ResourceBundleMessageResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/ResourceBundleMessageResolver.java
new file mode 100644
index 0000000..fdc4e2b
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/ResourceBundleMessageResolver.java
@@ -0,0 +1,123 @@
+/*
+ * 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.impl;
+
+import java.text.MessageFormat;
+import java.util.Dictionary;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.thymeleaf.Arguments;
+import org.thymeleaf.context.IContext;
+import org.thymeleaf.messageresolver.IMessageResolver;
+import org.thymeleaf.messageresolver.MessageResolution;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Resource Bundle Message Resolver”",
+ description = "resource bundle message resolver for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "resource bundle message resolver for Sling Scripting Thymeleaf")
+})
+public class ResourceBundleMessageResolver implements IMessageResolver {
+
+ @Reference
+ private ResourceBundleProvider resourceBundleProvider;
+
+ private Integer order;
+
+ public static final int DEFAULT_ORDER = 0;
+
+ @Property(intValue = DEFAULT_ORDER)
+ public static final String ORDER_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.ResourceBundleMessageResolver.order";
+
+ public static final Object[] EMPTY_MESSAGE_PARAMETERS = new Object[0];
+
+ private final Logger logger = LoggerFactory.getLogger(ResourceBundleMessageResolver.class);
+
+ public ResourceBundleMessageResolver() {
+ }
+
+ @Activate
+ private void activate(final ComponentContext componentContext) {
+ logger.debug("activate");
+ configure(componentContext);
+ }
+
+ @Modified
+ private void modified(final ComponentContext componentContext) {
+ logger.debug("modified");
+ configure(componentContext);
+ }
+
+ @Deactivate
+ private void deactivate(final ComponentContext componentContext) {
+ logger.debug("deactivate");
+ }
+
+ private synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ order = PropertiesUtil.toInteger(properties.get(ORDER_PARAMETER), DEFAULT_ORDER);
+ }
+
+ @Override
+ public String getName() {
+ return getClass().getName();
+ }
+
+ @Override
+ public Integer getOrder() {
+ return order;
+ }
+
+ @Override
+ public MessageResolution resolveMessage(final Arguments arguments, final String key, final Object[] messageParameters) {
+ logger.debug("arguments: {}, key: {}, message parameters: {}", arguments, key, messageParameters);
+ final IContext context = arguments.getContext();
+ final Locale locale = context.getLocale();
+ final ResourceBundle resourceBundle = resourceBundleProvider.getResourceBundle(locale);
+ final String string = resourceBundle.getString(key);
+ final MessageFormat messageFormat = new MessageFormat(string, locale);
+ final String message = messageFormat.format((messageParameters != null ? messageParameters : EMPTY_MESSAGE_PARAMETERS));
+ return new MessageResolution(message);
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/ScriptReaderResourceResolver.java
similarity index 61%
rename from src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java
rename to src/main/java/org/apache/sling/scripting/thymeleaf/impl/ScriptReaderResourceResolver.java
index 51eea3e..661ed9e 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/ScriptReaderResourceResolver.java
@@ -16,23 +16,41 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.scripting.thymeleaf;
+package org.apache.sling.scripting.thymeleaf.impl;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.scripting.thymeleaf.SlingContext;
+import org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory;
+import org.osgi.framework.Constants;
import org.thymeleaf.TemplateProcessingParameters;
import org.thymeleaf.context.IContext;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.resourceresolver.IResourceResolver;
import org.thymeleaf.util.Validate;
-public class SlingResourceResolver implements IResourceResolver {
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Script Reader Resource Resolver”",
+ description = "script reader resource resolver for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "script reader resource resolver for Sling Scripting Thymeleaf"),
+ @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false)
+})
+public class ScriptReaderResourceResolver implements IResourceResolver {
@Override
public String getName() {
- return getClass().getSimpleName();
+ return getClass().getName();
}
@Override
@@ -43,7 +61,7 @@ public class SlingResourceResolver implements IResourceResolver {
final IContext context = templateProcessingParameters.getContext();
if (context instanceof SlingContext) {
final SlingContext slingContext = (SlingContext) context;
- return new ReaderInputStream(slingContext.getReader(), StandardCharsets.UTF_8);
+ return new ReaderInputStream(slingContext.getReader(), ThymeleafScriptEngineFactory.TEMPLATE_CHARSET);
} else {
throw new TemplateProcessingException("Cannot handle context: " + context.getClass().getName());
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/AbstractTemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/AbstractTemplateModeHandler.java
new file mode 100644
index 0000000..589a2b5
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/AbstractTemplateModeHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.sling.scripting.thymeleaf.SlingTemplateModeHandler;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.thymeleaf.PatternSpec;
+import org.thymeleaf.templateparser.ITemplateParser;
+import org.thymeleaf.templatewriter.ITemplateWriter;
+
+public abstract class AbstractTemplateModeHandler implements SlingTemplateModeHandler {
+
+ private final String templateModeName;
+
+ private final ITemplateParser templateParser;
+
+ private final ITemplateWriter templateWriter;
+
+ private PatternSpec patternSpec;
+
+ // see StandardTemplateModeHandlers#MAX_PARSERS_POOL_SIZE
+ private static final int MAX_PARSERS_POOL_SIZE = 24;
+
+ private final Logger logger = LoggerFactory.getLogger(AbstractTemplateModeHandler.class);
+
+ protected AbstractTemplateModeHandler(final String templateModeName, final ITemplateParser templateParser, final ITemplateWriter templateWriter) {
+ this.templateModeName = templateModeName;
+ this.templateParser = templateParser;
+ this.templateWriter = templateWriter;
+ }
+
+ @Activate
+ protected void activate(final ComponentContext componentContext) {
+ logger.debug("activate");
+ configure(componentContext);
+ }
+
+ @Modified
+ protected void modified(final ComponentContext componentContext) {
+ logger.debug("modified");
+ configure(componentContext);
+ }
+
+ @Deactivate
+ protected void deactivate(final ComponentContext componentContext) {
+ logger.debug("deactivate");
+ }
+
+ protected abstract void configure(final ComponentContext componentContext);
+
+ protected synchronized void configurePatternSpec(final String[] strings) {
+ final Set<String> set = new HashSet<String>();
+ Collections.addAll(set, strings);
+ final PatternSpec patternSpec = new PatternSpec(); // isInitialized() is private, so create a new PatternSpec
+ patternSpec.setPatterns(set);
+ this.patternSpec = patternSpec;
+ }
+
+ @Override
+ public String getTemplateModeName() {
+ return templateModeName;
+ }
+
+ @Override
+ public ITemplateParser getTemplateParser() {
+ return templateParser;
+ }
+
+ @Override
+ public ITemplateWriter getTemplateWriter() {
+ return templateWriter;
+ }
+
+ @Override
+ public PatternSpec getPatternSpec() {
+ return patternSpec;
+ }
+
+ // see StandardTemplateModeHandlers
+ protected static int poolSize() {
+ final int availableProcessors = Runtime.getRuntime().availableProcessors();
+ return Math.min((availableProcessors <= 2 ? availableProcessors : availableProcessors - 1), MAX_PARSERS_POOL_SIZE);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/Html5TemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/Html5TemplateModeHandler.java
new file mode 100644
index 0000000..438ce38
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/Html5TemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.xmlsax.XhtmlAndHtml5NonValidatingSAXTemplateParser;
+import org.thymeleaf.templatewriter.XhtmlHtml5TemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “HTML5 Template Mode Handler”",
+ description = "HTML5 template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "HTML5 template mode handler for Sling Scripting Thymeleaf")
+})
+public class Html5TemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "HTML5";
+
+ public static final String DEFAULT_PATTERN = "";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.Html5TemplateModeHandler.patterns";
+
+ public Html5TemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new XhtmlAndHtml5NonValidatingSAXTemplateParser(poolSize()), new XhtmlHtml5TemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/LegacyHtml5TemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/LegacyHtml5TemplateModeHandler.java
new file mode 100644
index 0000000..8591d5c
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/LegacyHtml5TemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.html.LegacyHtml5TemplateParser;
+import org.thymeleaf.templatewriter.XmlTemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Legacy HTML5 Template Mode Handler”",
+ description = "legacy HTML5 template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "legacy HTML5 template mode handler for Sling Scripting Thymeleaf")
+})
+public class LegacyHtml5TemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "LEGACYHTML5";
+
+ public static final String DEFAULT_PATTERN = "*.html";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.LegacyHtml5TemplateModeHandler.patterns";
+
+ public LegacyHtml5TemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new LegacyHtml5TemplateParser(TEMPLATE_MODE_NAME, poolSize()), new XmlTemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXhtmlTemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXhtmlTemplateModeHandler.java
new file mode 100644
index 0000000..14e0942
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXhtmlTemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.xmlsax.XhtmlAndHtml5NonValidatingSAXTemplateParser;
+import org.thymeleaf.templatewriter.XhtmlHtml5TemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Validating XHTML Template Mode Handler”",
+ description = "validating XHTML template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "validating XHTML template mode handler for Sling Scripting Thymeleaf")
+})
+public class ValidatingXhtmlTemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "VALIDXHTML";
+
+ public static final String DEFAULT_PATTERN = "*.xhtml";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXhtmlTemplateModeHandler.patterns";
+
+ public ValidatingXhtmlTemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new XhtmlAndHtml5NonValidatingSAXTemplateParser(poolSize()), new XhtmlHtml5TemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXmlTemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXmlTemplateModeHandler.java
new file mode 100644
index 0000000..17ac0f0
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/ValidatingXmlTemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.xmlsax.XmlValidatingSAXTemplateParser;
+import org.thymeleaf.templatewriter.XmlTemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “Validating XML Template Mode Handler”",
+ description = "validating XML template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "validating XML template mode handler for Sling Scripting Thymeleaf")
+})
+public class ValidatingXmlTemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "VALIDXML";
+
+ public static final String DEFAULT_PATTERN = "*.xml";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXmlTemplateModeHandler.patterns";
+
+ public ValidatingXmlTemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new XmlValidatingSAXTemplateParser(poolSize()), new XmlTemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XhtmlTemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XhtmlTemplateModeHandler.java
new file mode 100644
index 0000000..3f01374
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XhtmlTemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.xmlsax.XhtmlAndHtml5NonValidatingSAXTemplateParser;
+import org.thymeleaf.templatewriter.XhtmlHtml5TemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “XHTML Template Mode Handler”",
+ description = "XHTML template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "XHTML template mode handler for Sling Scripting Thymeleaf")
+})
+public class XhtmlTemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "XHTML";
+
+ public static final String DEFAULT_PATTERN = "*.xhtml";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XhtmlTemplateModeHandler.patterns";
+
+ public XhtmlTemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new XhtmlAndHtml5NonValidatingSAXTemplateParser(poolSize()), new XhtmlHtml5TemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XmlTemplateModeHandler.java b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XmlTemplateModeHandler.java
new file mode 100644
index 0000000..09b9eaf
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/impl/templatemodehandler/XmlTemplateModeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.templatemodehandler;
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.thymeleaf.templateparser.xmlsax.XmlNonValidatingSAXTemplateParser;
+import org.thymeleaf.templatewriter.XmlTemplateWriter;
+
+@Component(
+ label = "Apache Sling Scripting Thymeleaf “XML Template Mode Handler”",
+ description = "XML template mode handler for Sling Scripting Thymeleaf",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "XML template mode handler for Sling Scripting Thymeleaf")
+})
+public class XmlTemplateModeHandler extends AbstractTemplateModeHandler {
+
+ public static final String TEMPLATE_MODE_NAME = "XML";
+
+ public static final String DEFAULT_PATTERN = "*.xml";
+
+ @Property(value = {DEFAULT_PATTERN}, unbounded = PropertyUnbounded.ARRAY)
+ public static final String PATTERNS_PARAMETER = "org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XmlTemplateModeHandler.patterns";
+
+ public XmlTemplateModeHandler() {
+ super(TEMPLATE_MODE_NAME, new XmlNonValidatingSAXTemplateParser(poolSize()), new XmlTemplateWriter());
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ final String[] strings = PropertiesUtil.toStringArray(properties.get(PATTERNS_PARAMETER), new String[]{DEFAULT_PATTERN});
+ configurePatternSpec(strings);
+ }
+
+}
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
index b86149e..bc3e542 100644
--- a/src/main/resources/OSGI-INF/metatype/metatype.properties
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -20,5 +20,44 @@
service.ranking.name = service ranking
service.ranking.description = service property for identifying the service's ranking number
-org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.label = Apache Sling Scripting Thymeleaf
-org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.description = scripting engine for Thymeleaf templates
+# ThymeleafScriptEngineFactory
+org.apache.sling.scripting.thymeleaf.extensions.name = extensions
+org.apache.sling.scripting.thymeleaf.extensions.description = extensions
+
+org.apache.sling.scripting.thymeleaf.mimetypes.name = mime types
+org.apache.sling.scripting.thymeleaf.mimetypes.description = mime types
+
+org.apache.sling.scripting.thymeleaf.names.name = names
+org.apache.sling.scripting.thymeleaf.names.description = names
+
+# NonCachingTemplateResolver
+org.apache.sling.scripting.thymeleaf.impl.NonCachingTemplateResolver.order.name = order
+org.apache.sling.scripting.thymeleaf.impl.NonCachingTemplateResolver.order.description = property for ordering template resolvers inside the Thymeleaf template engine
+
+# ResourceBundleMessageResolver
+org.apache.sling.scripting.thymeleaf.impl.ResourceBundleMessageResolver.order.name = order
+org.apache.sling.scripting.thymeleaf.impl.ResourceBundleMessageResolver.order.description = property for ordering message resolvers inside the Thymeleaf template engine
+
+# XmlTemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XmlTemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XmlTemplateModeHandler.patterns.description = TODO
+
+# ValidatingXmlTemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXmlTemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXmlTemplateModeHandler.patterns.description = TODO
+
+# XhtmlTemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XhtmlTemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.XhtmlTemplateModeHandler.patterns.description = TODO
+
+# ValidatingXhtmlTemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXhtmlTemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.ValidatingXhtmlTemplateModeHandler.patterns.description = TODO
+
+# Html5TemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.Html5TemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.Html5TemplateModeHandler.patterns.description = TODO
+
+# LegacyHtml5TemplateModeHandler
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.LegacyHtml5TemplateModeHandler.patterns.name = patterns
+org.apache.sling.scripting.thymeleaf.impl.templatemodehandler.LegacyHtml5TemplateModeHandler.patterns.description = TODO
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.