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 bc1a745ce057468dfb5aa1377aa79efe3a62d65e Author: Oliver Lietz <[email protected]> AuthorDate: Thu Jun 5 15:12:09 2014 +0000 SLING-3649 add initial version of Apache Sling Scripting Thymeleaf git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/thymeleaf@1600678 13f79535-47bb-0310-9956-ffa450edef68 --- README.md | 7 + pom.xml | 167 ++++++++++++++ .../sling/scripting/thymeleaf/SlingContext.java | 50 +++++ .../scripting/thymeleaf/SlingMessageResolver.java | 46 ++++ .../scripting/thymeleaf/SlingResourceResolver.java | 52 +++++ .../scripting/thymeleaf/SlingTemplateResolver.java | 62 ++++++ .../scripting/thymeleaf/ThymeleafScriptEngine.java | 67 ++++++ .../thymeleaf/ThymeleafScriptEngineFactory.java | 87 ++++++++ .../html/AbstractHtmlTemplateParser.java | 248 +++++++++++++++++++++ .../OSGI-INF/metatype/metatype.properties | 24 ++ 10 files changed, 810 insertions(+) diff --git a/README.md b/README.md new file mode 100644 index 0000000..693fcae --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Apache Sling Scripting Thymeleaf +================================ + +scripting engine for Thymeleaf templates + +* http://www.thymeleaf.org +* https://github.com/thymeleaf/thymeleaf diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..9d0ef77 --- /dev/null +++ b/pom.xml @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>20-SNAPSHOT</version> + <relativePath>../../../parent/pom.xml</relativePath> + </parent> + + <artifactId>org.apache.sling.scripting.thymeleaf</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>Apache Sling Scripting Thymeleaf</name> + <description>Apache Sling Scripting Thymeleaf</description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <sling.java.version>7</sling.java.version> + </properties> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/thymeleaf</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/thymeleaf</developerConnection> + <url>http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/thymeleaf</url> + </scm> + + <dependencies> + <!-- javax --> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <scope>provided</scope> + </dependency> + <!-- OSGi --> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <!-- Apache Commons --> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + <scope>provided</scope> + </dependency> + <!-- Apache Sling --> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.api</artifactId> + <version>2.7.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.scripting.api</artifactId> + <version>2.1.6</version> + <scope>provided</scope> + </dependency> + <!-- Apache Felix --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + <scope>provided</scope> + </dependency> + <!-- Thymeleaf --> + <dependency> + <groupId>org.thymeleaf</groupId> + <artifactId>thymeleaf</artifactId> + <version>2.1.3.RELEASE</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.unbescape</groupId> + <artifactId>unbescape</artifactId> + <version>1.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>net.sourceforge.nekohtml</groupId> + <artifactId>nekohtml</artifactId> + <version>1.9.21</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>xerces</groupId> + <artifactId>xercesImpl</artifactId> + <version>2.11.0</version> + <scope>provided</scope> + </dependency> + <!-- logging --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.7</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-Category>sling</Bundle-Category> + <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> + <Export-Package/> + <Import-Package> + org.apache.commons.io.input;version="1.4.9999", + * + </Import-Package> + <Embed-Dependency> + *;scope=compile;inline=true + </Embed-Dependency> + <ScriptEngine-Name>${project.name}</ScriptEngine-Name> + <ScriptEngine-Version>${project.version}</ScriptEngine-Version> + <_removeheaders> + Embed-Dependency, + Private-Package, + Include-Resource + </_removeheaders> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java new file mode 100644 index 0000000..733614a --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java @@ -0,0 +1,50 @@ +/* + * 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.Locale; +import java.util.Map; + +import org.thymeleaf.context.Context; + +// TODO WebContext? +public class SlingContext extends Context { + + 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; + } + +} diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java new file mode 100644 index 0000000..cf811e0 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingMessageResolver.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.scripting.thymeleaf; + +import org.thymeleaf.Arguments; +import org.thymeleaf.messageresolver.IMessageResolver; +import org.thymeleaf.messageresolver.MessageResolution; + +public class SlingMessageResolver implements IMessageResolver { + + @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() { + } + +} diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java new file mode 100644 index 0000000..51eea3e --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingResourceResolver.java @@ -0,0 +1,52 @@ +/* + * 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.InputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.input.ReaderInputStream; +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 { + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public InputStream getResourceAsStream(final TemplateProcessingParameters templateProcessingParameters, final String resourceName) { + + Validate.notNull(templateProcessingParameters, "Template Processing Parameters cannot be null"); + + final IContext context = templateProcessingParameters.getContext(); + if (context instanceof SlingContext) { + final SlingContext slingContext = (SlingContext) context; + return new ReaderInputStream(slingContext.getReader(), StandardCharsets.UTF_8); + } else { + throw new TemplateProcessingException("Cannot handle context: " + context.getClass().getName()); + } + } + +} diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java new file mode 100644 index 0000000..173a31a --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingTemplateResolver.java @@ -0,0 +1,62 @@ +/* + * 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/ThymeleafScriptEngine.java b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java new file mode 100644 index 0000000..f21d6d7 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngine.java @@ -0,0 +1,67 @@ +/* + * 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.Locale; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; + +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.thymeleaf.context.IContext; + +public class ThymeleafScriptEngine extends AbstractSlingScriptEngine { + + private final TemplateEngine templateEngine; + + public ThymeleafScriptEngine(final ScriptEngineFactory scriptEngineFactory, final TemplateEngine templateEngine) { + super(scriptEngineFactory); + this.templateEngine = templateEngine; + } + + @Override + public Object eval(Reader reader, ScriptContext scriptContext) throws ScriptException { + final Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); + final SlingScriptHelper helper = (SlingScriptHelper) bindings.get(SlingBindings.SLING); + + if (helper == null) { + throw new ScriptException("SlingScriptHelper missing from bindings"); + } + + final Locale locale = helper.getRequest().getLocale(); + final String scriptName = helper.getScript().getScriptResource().getPath(); + + try { + final IContext context = new SlingContext(locale, bindings, reader); + templateEngine.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); + } + + 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 new file mode 100644 index 0000000..781770f --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/thymeleaf/ThymeleafScriptEngineFactory.java @@ -0,0 +1,87 @@ +/* + * 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 javax.script.ScriptEngine; + +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.api.AbstractScriptEngineFactory; +import org.osgi.framework.Constants; +import org.thymeleaf.TemplateEngine; + +@Component( + name = "org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory", + label = "%org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.label", + description = "%org.apache.sling.scripting.thymeleaf.ThymeleafScriptEngineFactory.description", + immediate = true, + metatype = true +) +@Service +@Properties({ + @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation"), + @Property(name = Constants.SERVICE_DESCRIPTION, value = "scripting engine for Thymeleaf templates"), + @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false) +}) +public class ThymeleafScriptEngineFactory extends AbstractScriptEngineFactory { + + private SlingResourceResolver resourceResolver; + + private SlingTemplateResolver templateResolver; + + private SlingMessageResolver messageResolver; + + private TemplateEngine templateEngine; + + 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); + } + + @Override + public String getLanguageName() { + return "Thymeleaf"; + } + + @Override + public String getLanguageVersion() { + return "2.1"; // TODO get version from Thymeleaf + } + + @Override + public ScriptEngine getScriptEngine() { + return new ThymeleafScriptEngine(this, templateEngine); + } + +} diff --git a/src/main/java/org/thymeleaf/templateparser/html/AbstractHtmlTemplateParser.java b/src/main/java/org/thymeleaf/templateparser/html/AbstractHtmlTemplateParser.java new file mode 100755 index 0000000..b9a95ef --- /dev/null +++ b/src/main/java/org/thymeleaf/templateparser/html/AbstractHtmlTemplateParser.java @@ -0,0 +1,248 @@ +/* + * ============================================================================= + * + * Copyright (c) 2011-2013, The THYMELEAF team (http://www.thymeleaf.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============================================================================= + */ +package org.thymeleaf.templateparser.html; + +import java.io.Reader; +import java.io.StringReader; +import java.util.List; + +import org.apache.xerces.parsers.DOMParser; +import org.cyberneko.html.HTMLConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.thymeleaf.Configuration; +import org.thymeleaf.dom.Document; +import org.thymeleaf.dom.Node; +import org.thymeleaf.exceptions.ConfigurationException; +import org.thymeleaf.exceptions.TemplateInputException; +import org.thymeleaf.exceptions.TemplateProcessingException; +import org.thymeleaf.templateparser.EntityResolver; +import org.thymeleaf.templateparser.ErrorHandler; +import org.thymeleaf.templateparser.ITemplateParser; +import org.thymeleaf.templateparser.TemplatePreprocessingReader; +import org.thymeleaf.util.ResourcePool; +import org.thymeleaf.util.StandardDOMTranslator; +import org.xml.sax.InputSource; + +// NOTE: This is a slightly modified class. The nasty class loader stuff is removed to not break on OSGi. + +/** + * <p> + * Document parser implementation for non-XML HTML documents. + * </p> + * + * @since 2.0.0 + * + * @author Daniel Fernández + */ +public abstract class AbstractHtmlTemplateParser implements ITemplateParser { + + private static final int BUFFER_SIZE = 8192; + + private final String templateModeName; + private final NekoBasedHtmlParser parser; + + + protected AbstractHtmlTemplateParser(final String templateModeName, final int poolSize) { + this.templateModeName = templateModeName; + parser = new NekoBasedHtmlParser(poolSize); + } + + + + + + public final Document parseTemplate(final Configuration configuration, final String documentName, final Reader reader) { + return this.parser.parseTemplate(configuration, documentName, getTemplatePreprocessingReader(reader)); + } + + + + + public final List<Node> parseFragment(final Configuration configuration, final String fragment) { + final String wrappedFragment = wrapFragment(fragment); + final Document document = + parseTemplate( + configuration, + null, // documentName + new StringReader(wrappedFragment)); + return unwrapFragment(document); + } + + + protected abstract String wrapFragment(final String fragment); + protected abstract List<Node> unwrapFragment(final Document document); + + + + + + /* + * This is defined in a class apart so that the classloader does not always try to load + * neko and xerces classes that might not be in the classpath. + */ + private static class NekoBasedHtmlParser { + + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + // The org.apache.xerces.parsers.DOMParser is not used here as a type + // parameter to avoid the class loader to try to load this xerces class + // (and fail) before we control the error at the constructor. + private final ResourcePool<Object> pool; + private boolean canResetParsers = true; + + + private NekoBasedHtmlParser(final int poolSize) { + super(); + this.pool = new ResourcePool<Object>(new HtmlTemplateParserFactory(), poolSize); + } + + + + + public final Document parseTemplate(final Configuration configuration, final String documentName, + final TemplatePreprocessingReader templateReader) { + + final DOMParser domParser = (DOMParser) this.pool.allocate(); + + try { + + domParser.setErrorHandler(ErrorHandler.INSTANCE); + domParser.setEntityResolver(new EntityResolver(configuration)); + + domParser.parse(new InputSource(templateReader)); + final org.w3c.dom.Document domDocument = domParser.getDocument(); + + if (this.canResetParsers) { + try { + /* + * Reset the parser so that it can be used again. + */ + domParser.reset(); + } catch (final UnsupportedOperationException ignored) { + if (this.logger.isWarnEnabled()) { + this.logger.warn( + "[THYMELEAF] The HTML Parser implementation being used (\"{}\") does not implement " + + "the \"reset\" operation. This will force Thymeleaf to re-create parser instances " + + "each time they are needed for parsing templates, which is more costly. Enabling template " + + "cache is recommended, and also using a parser library which implements \"reset\" such as " + + "nekoHTML version 1.9.15 or newer.", + domParser.getClass().getName()); + } + this.canResetParsers = false; + } + } + + return StandardDOMTranslator.translateDocument(domDocument, documentName, templateReader.getDocTypeClause()); + + } catch (final TemplateProcessingException e) { + throw e; + } catch (final Exception e) { + throw new TemplateInputException("Exception parsing document", e); + } finally { + + if (templateReader != null) { + try { + templateReader.close(); + } catch (final Exception ignored) { + // ignored + } + } + + if (this.canResetParsers) { + this.pool.release(domParser); + } else { + this.pool.discardAndReplace(domParser); + } + + } + } + + + } + + + + static class HtmlTemplateParserFactory implements ResourcePool.IResourceFactory<Object> { + + HtmlTemplateParserFactory() { + super(); + } + + + public Object createResource() { + + try { + + final HTMLConfiguration config = new HTMLConfiguration(); + + config.setFeature("http://xml.org/sax/features/namespaces", false); + config.setFeature("http://cyberneko.org/html/features/override-doctype", true); + config.setFeature("http://cyberneko.org/html/features/scanner/cdata-sections", true); + + // Avoids the inclusion of <HTML><BODY>, etc. around template fragments. Tag balancing will only + // be performed inside the fragments' root nodes. + config.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment", true); + + config.setProperty("http://cyberneko.org/html/properties/doctype/pubid", ""); + config.setProperty("http://cyberneko.org/html/properties/doctype/sysid", ""); + config.setProperty("http://cyberneko.org/html/properties/names/elems", "match"); + config.setProperty("http://cyberneko.org/html/properties/names/attrs", "no-change"); + + return new DOMParser(config); + + } catch(final Exception e) { + throw new ConfigurationException( + "Error while creating nekoHTML-based parser for " + + "LEGACYHTML5 template modes.", e); + } + + } + + + } + + + + + /** + * @since 2.0.11 + */ + protected boolean shouldAddThymeleafRootToParser() { + return false; + } + + + + /** + * @since 2.0.11 + */ + protected TemplatePreprocessingReader getTemplatePreprocessingReader(final Reader reader) { + if (reader instanceof TemplatePreprocessingReader) { + final TemplatePreprocessingReader templatePreprocessingReader = (TemplatePreprocessingReader) reader; + return new TemplatePreprocessingReader( + templatePreprocessingReader.getInnerReader(), BUFFER_SIZE, shouldAddThymeleafRootToParser()); + } + return new TemplatePreprocessingReader(reader, BUFFER_SIZE, shouldAddThymeleafRootToParser()); + } + + + +} diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties new file mode 100644 index 0000000..b86149e --- /dev/null +++ b/src/main/resources/OSGI-INF/metatype/metatype.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +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 -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
