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 <[email protected]> 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 "[email protected]" <[email protected]>.
