You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:14:20 UTC
[sling-org-apache-sling-scripting-thymeleaf] 18/39: SLING-5928 Use
Service ResourceResolver in SlingResourceTemplateResolver
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.scripting.thymeleaf-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-thymeleaf.git
commit 08237880e5c1f425ae4c3abfdccb896eac881380
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Sun Oct 23 17:38:16 2016 +0000
SLING-5928 Use Service ResourceResolver in SlingResourceTemplateResolver
* (re)add and use Sling contexts
* add a Sling engine context factory
* add preliminary request-scoped resource resolver provider (SLING-6165)
* improve logging in tests
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/org.apache.sling.scripting.thymeleaf@1766307 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 13 +-
.../scripting/thymeleaf/DefaultSlingContext.java | 41 ++++
.../sling/scripting/thymeleaf/SlingContext.java | 30 +++
.../thymeleaf/internal/SlingEngineContext.java | 44 ++++
.../internal/SlingEngineContextFactory.java | 63 ++++++
.../internal/SlingResourceTemplateResolver.java | 26 ++-
.../thymeleaf/internal/SlingWebContext.java | 70 +++++++
.../thymeleaf/internal/ThymeleafScriptEngine.java | 12 +-
.../internal/ThymeleafScriptEngineFactory.java | 19 +-
.../ThymeleafScriptEngineFactoryConfiguration.java | 2 +-
.../DelegatingResourceResolver.java | 231 +++++++++++++++++++++
.../RequestScopedResourceResolverProvider.java | 90 ++++++++
.../thymeleaf/it/tests/ThymeleafTestSupport.java | 40 +++-
src/test/resources/exam.properties | 19 ++
src/test/resources/logback.xml | 30 +++
src/test/resources/repoinit.txt | 34 +++
16 files changed, 747 insertions(+), 17 deletions(-)
diff --git a/pom.xml b/pom.xml
index e71dff2..6db782c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,6 +138,12 @@
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.serviceusermapper</artifactId>
+ <version>1.2.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.scripting.api</artifactId>
<version>2.1.8</version>
<scope>provided</scope>
@@ -151,7 +157,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.testing.paxexam</artifactId>
- <version>0.0.2</version>
+ <version>0.0.3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Thymeleaf -->
@@ -192,6 +198,11 @@
<version>1.9.1</version>
<scope>test</scope>
</dependency>
+ <!-- jsr305 -->
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ </dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java
new file mode 100644
index 0000000..f6d4d1d
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/DefaultSlingContext.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf;
+
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.thymeleaf.context.AbstractContext;
+
+public class DefaultSlingContext extends AbstractContext implements SlingContext {
+
+ private final ResourceResolver resourceResolver;
+
+ public DefaultSlingContext(final ResourceResolver resourceResolver, final Locale locale, final Map<String, Object> variables) {
+ super(locale, variables);
+ this.resourceResolver = resourceResolver;
+ }
+
+ @Override
+ public ResourceResolver getResourceResolver() {
+ return resourceResolver;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
new file mode 100644
index 0000000..4b2c282
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/SlingContext.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.osgi.annotation.versioning.ProviderType;
+import org.thymeleaf.context.IContext;
+
+@ProviderType
+public interface SlingContext extends IContext {
+
+ ResourceResolver getResourceResolver();
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java
new file mode 100644
index 0000000..c5dc3b6
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContext.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf.internal;
+
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.scripting.thymeleaf.SlingContext;
+import org.thymeleaf.IEngineConfiguration;
+import org.thymeleaf.context.EngineContext;
+import org.thymeleaf.engine.TemplateData;
+
+public class SlingEngineContext extends EngineContext implements SlingContext {
+
+ private final ResourceResolver resourceResolver;
+
+ public SlingEngineContext(final ResourceResolver resourceResolver, final IEngineConfiguration configuration, final TemplateData templateData, final Map<String, Object> templateResolutionAttributes, final Locale locale, final Map<String, Object> variables) {
+ super(configuration, templateData, templateResolutionAttributes, locale, variables);
+ this.resourceResolver = resourceResolver;
+ }
+
+ @Override
+ public ResourceResolver getResourceResolver() {
+ return resourceResolver;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java
new file mode 100644
index 0000000..e25715e
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingEngineContextFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf.internal;
+
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.scripting.thymeleaf.SlingContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Component;
+import org.thymeleaf.IEngineConfiguration;
+import org.thymeleaf.context.IContext;
+import org.thymeleaf.context.IEngineContext;
+import org.thymeleaf.context.IEngineContextFactory;
+import org.thymeleaf.engine.TemplateData;
+
+@Component(
+ immediate = true,
+ property = {
+ Constants.SERVICE_DESCRIPTION + "=Sling EngineContextFactory for Sling Scripting Thymeleaf",
+ Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
+ }
+)
+public class SlingEngineContextFactory implements IEngineContextFactory {
+
+ @Override
+ public IEngineContext createEngineContext(final IEngineConfiguration configuration, final TemplateData templateData, final Map<String, Object> templateResolutionAttributes, final IContext context) {
+ if (context instanceof SlingContext) {
+ // TODO web context
+ final SlingContext slingContext = (SlingContext) context;
+ final ResourceResolver resourceResolver = slingContext.getResourceResolver();
+ final Locale locale = context.getLocale();
+ final Set<String> variableNames = context.getVariableNames();
+ final Map<String, Object> variables = new LinkedHashMap<>(variableNames.size() + 1, 1.0f);
+ for (final String variableName : variableNames) {
+ variables.put(variableName, context.getVariable(variableName));
+ }
+ return new SlingEngineContext(resourceResolver, configuration, templateData, templateResolutionAttributes, locale, variables);
+ } else {
+ throw new IllegalStateException("context is not an instance of SlingContext");
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
index 5f53242..790cfdc 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingResourceTemplateResolver.java
@@ -22,7 +22,7 @@ import java.util.Map;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.scripting.thymeleaf.SlingContext;
import org.apache.sling.scripting.thymeleaf.TemplateModeProvider;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
@@ -111,15 +111,21 @@ public class SlingResourceTemplateResolver implements ITemplateResolver {
@Override
public TemplateResolution resolveTemplate(final IEngineConfiguration engineConfiguration, final IContext context, final String ownerTemplate, final String template, final Map<String, Object> templateResolutionAttributes) {
logger.debug("resolving template '{}'", template);
- final ResourceResolver resourceResolver = (ResourceResolver) context.getVariable(SlingBindings.RESOLVER);
- final Resource resource = resourceResolver.getResource(template);
- final ITemplateResource templateResource = new SlingTemplateResource(resource);
- final boolean templateResourceExistenceVerified = false;
- final TemplateMode templateMode = templateModeProvider.provideTemplateMode(resource);
- logger.debug("using template mode {} for template '{}'", templateMode, template);
- final boolean useDecoupledLogic = templateMode.isMarkup() && configuration.useDecoupledLogic();
- final ICacheEntryValidity validity = NonCacheableCacheEntryValidity.INSTANCE;
- return new TemplateResolution(templateResource, templateResourceExistenceVerified, templateMode, useDecoupledLogic, validity);
+ if (context instanceof SlingContext) {
+ final SlingContext slingContext = (SlingContext) context;
+ final ResourceResolver resourceResolver = slingContext.getResourceResolver();
+ final Resource resource = resourceResolver.getResource(template);
+ final ITemplateResource templateResource = new SlingTemplateResource(resource);
+ final boolean templateResourceExistenceVerified = false;
+ final TemplateMode templateMode = templateModeProvider.provideTemplateMode(resource);
+ logger.debug("using template mode {} for template '{}'", templateMode, template);
+ final boolean useDecoupledLogic = templateMode.isMarkup() && configuration.useDecoupledLogic();
+ final ICacheEntryValidity validity = NonCacheableCacheEntryValidity.INSTANCE;
+ return new TemplateResolution(templateResource, templateResourceExistenceVerified, templateMode, useDecoupledLogic, validity);
+ } else {
+ logger.error("context is not an instance of SlingContext");
+ return null;
+ }
}
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java
new file mode 100644
index 0000000..e977d46
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/SlingWebContext.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf.internal;
+
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.scripting.thymeleaf.DefaultSlingContext;
+import org.thymeleaf.context.IWebContext;
+
+public class SlingWebContext extends DefaultSlingContext implements IWebContext {
+
+ private final SlingHttpServletRequest servletRequest;
+
+ private final SlingHttpServletResponse servletResponse;
+
+ private final ServletContext servletContext;
+
+ public SlingWebContext(final SlingHttpServletRequest servletRequest, final SlingHttpServletResponse servletResponse, final ServletContext servletContext, final ResourceResolver resourceResolver, final Locale locale, final Map<String, Object> variables) {
+ super(resourceResolver, locale, variables);
+ this.servletRequest = servletRequest;
+ this.servletResponse = servletResponse;
+ this.servletContext = servletContext;
+ }
+
+ @Override
+ public HttpServletRequest getRequest() {
+ return servletRequest;
+ }
+
+ @Override
+ public HttpServletResponse getResponse() {
+ return servletResponse;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return servletRequest.getSession(false);
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
index 80ea877..d653556 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngine.java
@@ -25,13 +25,16 @@ import java.util.Locale;
import javax.script.Bindings;
import javax.script.ScriptContext;
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.resource.ResourceResolver;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.thymeleaf.context.Context;
import org.thymeleaf.context.IContext;
public final class ThymeleafScriptEngine extends AbstractSlingScriptEngine {
@@ -54,12 +57,17 @@ public final class ThymeleafScriptEngine extends AbstractSlingScriptEngine {
throw new ScriptException("SlingScriptHelper missing from bindings");
}
+ final SlingHttpServletRequest request = helper.getRequest();
+ final SlingHttpServletResponse response = helper.getResponse();
+ final ServletContext servletContext = null; // only used by Thymeleaf's ServletContextResourceResolver (TODO check if still true for 3.0)
+
final Locale locale = helper.getResponse().getLocale();
final String scriptName = helper.getScript().getScriptResource().getPath();
final Writer writer = scriptContext.getWriter();
try {
- final IContext context = new Context(locale, bindings);
+ final ResourceResolver resourceResolver = thymeleafScriptEngineFactory.getRequestScopedResourceResolver();
+ final IContext context = new SlingWebContext(request, response, servletContext, resourceResolver, locale, bindings);
thymeleafScriptEngineFactory.getTemplateEngine().process(scriptName, context, writer);
} catch (Exception e) {
logger.error("Failure rendering Thymeleaf template '{}': {}", scriptName, e.getMessage());
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
index f475925..846b210 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactory.java
@@ -28,7 +28,9 @@ import java.util.Set;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
+import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
+import org.apache.sling.scripting.thymeleaf.internal.resourceresolver.RequestScopedResourceResolverProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
@@ -120,7 +122,6 @@ public final class ThymeleafScriptEngineFactory extends AbstractScriptEngineFact
private volatile ICacheManager cacheManager;
@Reference(
- cardinality = ReferenceCardinality.OPTIONAL,
policy = ReferencePolicy.DYNAMIC,
policyOption = ReferencePolicyOption.GREEDY,
bind = "setEngineContextFactory",
@@ -128,6 +129,12 @@ public final class ThymeleafScriptEngineFactory extends AbstractScriptEngineFact
)
private volatile IEngineContextFactory engineContextFactory;
+ @Reference(
+ policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY
+ )
+ private volatile RequestScopedResourceResolverProvider resourceResolverProvider;
+
private ThymeleafScriptEngineFactoryConfiguration configuration;
private BundleContext bundleContext;
@@ -338,6 +345,12 @@ public final class ThymeleafScriptEngineFactory extends AbstractScriptEngineFact
logger.info("configuration is null, not setting up new template engine");
return;
}
+
+ if (!configuration.useStandardEngineContextFactory() && engineContextFactory == null) {
+ logger.info("no engine context factory available, not setting up new template engine");
+ return;
+ }
+
// setup template engine
final TemplateEngine templateEngine = new TemplateEngine();
// Template Resolvers
@@ -415,4 +428,8 @@ public final class ThymeleafScriptEngineFactory extends AbstractScriptEngineFact
}
}
+ ResourceResolver getRequestScopedResourceResolver() {
+ return resourceResolverProvider.getResourceResolver();
+ }
+
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
index 3830241..e73c710 100644
--- a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/ThymeleafScriptEngineFactoryConfiguration.java
@@ -92,6 +92,6 @@ import org.osgi.service.metatype.annotations.ObjectClassDefinition;
name = "use standard engine context factory",
description = "Enables Thymeleaf's standard engine context factory and uses it exclusively."
)
- boolean useStandardEngineContextFactory() default true;
+ boolean useStandardEngineContextFactory() default false;
}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/DelegatingResourceResolver.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/DelegatingResourceResolver.java
new file mode 100644
index 0000000..25b1c4d
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/DelegatingResourceResolver.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf.internal.resourceresolver;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DelegatingResourceResolver implements ResourceResolver {
+
+ private final ResourceResolver resourceResolver;
+
+ private final Logger logger = LoggerFactory.getLogger(DelegatingResourceResolver.class);
+
+ public DelegatingResourceResolver(final ResourceResolver resourceResolver) {
+ this.resourceResolver = resourceResolver;
+ }
+
+ void closeInternal() {
+ resourceResolver.close();
+ }
+
+ @Override
+ @Nonnull
+ public Resource resolve(@Nonnull HttpServletRequest httpServletRequest,@Nonnull String s) {
+ return resourceResolver.resolve(httpServletRequest, s);
+ }
+
+ @Override
+ @Nonnull
+ public Resource resolve(@Nonnull String s) {
+ return resourceResolver.resolve(s);
+ }
+
+ @Override
+ @Deprecated
+ @Nonnull
+ public Resource resolve(@Nonnull HttpServletRequest httpServletRequest) {
+ return resourceResolver.resolve(httpServletRequest);
+ }
+
+ @Override
+ @Nonnull
+ public String map(@Nonnull String s) {
+ return resourceResolver.map(s);
+ }
+
+ @Override
+ @CheckForNull
+ public String map(@Nonnull HttpServletRequest httpServletRequest, @Nonnull String s) {
+ return resourceResolver.map(httpServletRequest, s);
+ }
+
+ @Override
+ @CheckForNull
+ public Resource getResource(@Nonnull String s) {
+ return resourceResolver.getResource(s);
+ }
+
+ @Override
+ @CheckForNull
+ public Resource getResource(Resource resource, @Nonnull String s) {
+ return resourceResolver.getResource(resource, s);
+ }
+
+ @Override
+ @Nonnull
+ public String[] getSearchPath() {
+ return resourceResolver.getSearchPath();
+ }
+
+ @Override
+ @Nonnull
+ public Iterator<Resource> listChildren(@Nonnull Resource resource) {
+ return resourceResolver.listChildren(resource);
+ }
+
+ @Override
+ @CheckForNull
+ public Resource getParent(@Nonnull Resource resource) {
+ return resourceResolver.getParent(resource);
+ }
+
+ @Override
+ @Nonnull
+ public Iterable<Resource> getChildren(@Nonnull Resource resource) {
+ return resourceResolver.getChildren(resource);
+ }
+
+ @Override
+ @Nonnull
+ public Iterator<Resource> findResources(@Nonnull String s, String s1) {
+ return resourceResolver.findResources(s, s1);
+ }
+
+ @Override
+ @Nonnull
+ public Iterator<Map<String, Object>> queryResources(@Nonnull String s, String s1) {
+ return resourceResolver.queryResources(s, s1);
+ }
+
+ @Override
+ public boolean hasChildren(@Nonnull Resource resource) {
+ return resourceResolver.hasChildren(resource);
+ }
+
+ @Override
+ @Nonnull
+ public ResourceResolver clone(Map<String, Object> map) throws LoginException {
+ return resourceResolver.clone(map);
+ }
+
+ @Override
+ public boolean isLive() {
+ return resourceResolver.isLive();
+ }
+
+ @Override
+ public void close() {
+ // do not close
+ }
+
+ @Override
+ @CheckForNull
+ public String getUserID() {
+ return resourceResolver.getUserID();
+ }
+
+ @Override
+ @Nonnull
+ public Iterator<String> getAttributeNames() {
+ return resourceResolver.getAttributeNames();
+ }
+
+ @Override
+ @CheckForNull
+ public Object getAttribute(@Nonnull String s) {
+ return resourceResolver.getAttribute(s);
+ }
+
+ @Override
+ public void delete(@Nonnull Resource resource) throws PersistenceException {
+ resourceResolver.delete(resource);
+ }
+
+ @Override
+ @Nonnull
+ public Resource create(@Nonnull Resource resource, @Nonnull String s, Map<String, Object> map) throws PersistenceException {
+ return resourceResolver.create(resource, s, map);
+ }
+
+ @Override
+ public void revert() {
+ resourceResolver.revert();
+ }
+
+ @Override
+ public void commit() throws PersistenceException {
+ resourceResolver.commit();
+ }
+
+ @Override
+ public boolean hasChanges() {
+ return resourceResolver.hasChanges();
+ }
+
+ @Override
+ @CheckForNull
+ public String getParentResourceType(Resource resource) {
+ return resourceResolver.getParentResourceType(resource);
+ }
+
+ @Override
+ @CheckForNull
+ public String getParentResourceType(String s) {
+ return resourceResolver.getParentResourceType(s);
+ }
+
+ @Override
+ public boolean isResourceType(Resource resource, String s) {
+ return resourceResolver.isResourceType(resource, s);
+ }
+
+ @Override
+ public void refresh() {
+ resourceResolver.refresh();
+ }
+
+ @Override
+ public Resource copy(String s, String s1) throws PersistenceException {
+ return resourceResolver.copy(s, s1);
+ }
+
+ @Override
+ public Resource move(String s, String s1) throws PersistenceException {
+ return resourceResolver.move(s, s1);
+ }
+
+ @Override
+ @CheckForNull
+ public <AdapterType> AdapterType adaptTo(@Nonnull Class<AdapterType> aClass) {
+ return resourceResolver.adaptTo(aClass);
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/RequestScopedResourceResolverProvider.java b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/RequestScopedResourceResolverProvider.java
new file mode 100644
index 0000000..4da19ad
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/thymeleaf/internal/resourceresolver/RequestScopedResourceResolverProvider.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.thymeleaf.internal.resourceresolver;
+
+import org.apache.sling.api.request.SlingRequestEvent;
+import org.apache.sling.api.request.SlingRequestEvent.EventType;
+import org.apache.sling.api.request.SlingRequestListener;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.serviceusermapping.ServiceUserMapped;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+ service = {
+ RequestScopedResourceResolverProvider.class,
+ SlingRequestListener.class
+ },
+ immediate = true
+)
+public class RequestScopedResourceResolverProvider implements SlingRequestListener {
+
+ private final ThreadLocal<DelegatingResourceResolver> threadLocal = new ThreadLocal<>();
+
+ @Reference(
+ policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY
+ )
+ private volatile ResourceResolverFactory resourceResolverFactory;
+
+ @Reference(
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY
+ )
+ private volatile ServiceUserMapped serviceUserMapped;
+
+ private final Logger logger = LoggerFactory.getLogger(RequestScopedResourceResolverProvider.class);
+
+ public ResourceResolver getResourceResolver() {
+ DelegatingResourceResolver resourceResolver = threadLocal.get();
+ if (resourceResolver == null) {
+ try {
+ logger.debug("getting service resource resolver for thread {}", Thread.currentThread().getName());
+ final ResourceResolver delegate = resourceResolverFactory.getServiceResourceResolver(null);
+ resourceResolver = new DelegatingResourceResolver(delegate);
+ logger.debug("setting service resource resolver {} for thread {}", resourceResolver, Thread.currentThread().getName());
+ threadLocal.set(resourceResolver);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ return resourceResolver;
+ }
+
+ @Override
+ public void onEvent(final SlingRequestEvent slingRequestEvent) {
+ if (EventType.EVENT_DESTROY.equals(slingRequestEvent.getType())) {
+ final DelegatingResourceResolver resourceResolver = threadLocal.get();
+ logger.debug("removing service resource resolver {} for thread {}", resourceResolver, Thread.currentThread().getName());
+ threadLocal.remove();
+ if (resourceResolver != null) {
+ logger.debug("closing resource resolver {} for thread {}", resourceResolver, Thread.currentThread().getName());
+ resourceResolver.closeInternal();
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
index 693b94e..ef295be 100644
--- a/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
+++ b/src/test/java/org/apache/sling/scripting/thymeleaf/it/tests/ThymeleafTestSupport.java
@@ -25,12 +25,15 @@ import org.apache.sling.api.servlets.ServletResolver;
import org.apache.sling.auth.core.AuthenticationSupport;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.scripting.thymeleaf.it.app.Activator;
+import org.apache.sling.testing.paxexam.SlingOptions;
+import org.apache.sling.testing.paxexam.SlingVersionResolver;
import org.apache.sling.testing.paxexam.TestSupport;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.ProbeBuilder;
import org.ops4j.pax.exam.TestProbeBuilder;
import org.ops4j.pax.exam.util.Filter;
+import org.ops4j.pax.exam.util.PathUtils;
import org.osgi.framework.Constants;
import org.osgi.service.http.HttpService;
import org.thymeleaf.ITemplateEngine;
@@ -43,6 +46,9 @@ import static org.apache.sling.testing.paxexam.SlingOptions.slingScriptingJsp;
import static org.ops4j.pax.exam.CoreOptions.composite;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration;
+import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.newConfiguration;
public abstract class ThymeleafTestSupport extends TestSupport {
@@ -67,6 +73,14 @@ public abstract class ThymeleafTestSupport extends TestSupport {
@Configuration
public Option[] configuration() {
+ // SlingOptions.versionResolver.setVersionFromProject(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.scripting.api");
+ // SlingOptions.versionResolver.setVersionFromProject(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.scripting.core");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.api", "2.14.3-SNAPSHOT");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.jcr.base", "2.4.1-SNAPSHOT");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.jcr.oak.server", "1.1.1-SNAPSHOT");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.jcr.repoinit", "1.0.3-SNAPSHOT");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.jcr.resource", "2.8.1-SNAPSHOT");
+ SlingOptions.versionResolver.setVersion(SlingVersionResolver.SLING_GROUP_ID, "org.apache.sling.resourceresolver", "1.4.19-SNAPSHOT");
return new Option[]{
baseConfiguration(),
launchpad(),
@@ -76,7 +90,8 @@ public abstract class ThymeleafTestSupport extends TestSupport {
// testing
mavenBundle().groupId("org.jsoup").artifactId("jsoup").versionAsInProject(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
- junitBundles()
+ junitBundles(),
+ logging()
};
}
@@ -96,12 +111,33 @@ public abstract class ThymeleafTestSupport extends TestSupport {
protected Option launchpad() {
final int httpPort = findFreePort();
final String workingDirectory = workingDirectory();
+ final String repoinit = String.format("raw:file:%s/src/test/resources/repoinit.txt", PathUtils.getBaseDir());
return composite(
slingLaunchpadOakTar(workingDirectory, httpPort),
slingExtensionI18n(),
slingExtensionModels(),
slingScripting(),
- slingScriptingJsp()
+ slingScriptingJsp(),
+ newConfiguration("org.apache.sling.jcr.repoinit.impl.RepositoryInitializer")
+ .put("references", new String[]{repoinit})
+ .asOption(),
+ factoryConfiguration("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended")
+ .put("user.mapping", "org.apache.sling.scripting.thymeleaf=sling-scripting")
+ .asOption(),
+ newConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelistImpl")
+ .put("whitelist.regexp", "org.apache.sling.*")
+ .asOption()
+ );
+ }
+
+ protected Option logging() {
+ final String filename = String.format("file:%s/src/test/resources/logback.xml", PathUtils.getBaseDir());
+ return composite(
+ systemProperty("logback.configurationFile").value(filename),
+ mavenBundle().groupId("org.slf4j").artifactId("slf4j-api").version("1.7.21"),
+ mavenBundle().groupId("org.slf4j").artifactId("jcl-over-slf4j").version("1.7.21"),
+ mavenBundle().groupId("ch.qos.logback").artifactId("logback-core").version("1.1.7"),
+ mavenBundle().groupId("ch.qos.logback").artifactId("logback-classic").version("1.1.7")
);
}
diff --git a/src/test/resources/exam.properties b/src/test/resources/exam.properties
new file mode 100644
index 0000000..c98a668
--- /dev/null
+++ b/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+pax.exam.logging=none
diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml
new file mode 100644
index 0000000..d46a4ae
--- /dev/null
+++ b/src/test/resources/logback.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<configuration>
+ <appender name="file" class="ch.qos.logback.core.FileAppender">
+ <file>target/testing.log</file>
+ <encoder>
+ <pattern>%date %level [%thread] %logger{10} [%file : %line] %msg%n</pattern>
+ </encoder>
+ </appender>
+ <root level="debug">
+ <appender-ref ref="file"/>
+ </root>
+</configuration>
diff --git a/src/test/resources/repoinit.txt b/src/test/resources/repoinit.txt
new file mode 100644
index 0000000..fc4c50c
--- /dev/null
+++ b/src/test/resources/repoinit.txt
@@ -0,0 +1,34 @@
+################################################################################
+#
+# 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.
+#
+################################################################################
+
+create service user sling-scripting
+
+create path (sling:Folder) /apps
+create path (sling:Folder) /libs
+
+set ACL for sling-scripting
+ allow jcr:read on /apps
+ allow jcr:read on /libs
+end
+
+create path (sling:OrderedFolder) /content
+
+set ACL for everyone
+ allow jcr:read on /content
+end
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.