You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2020/03/20 10:35:54 UTC
[sling-org-apache-sling-scripting-jsp] branch master updated:
SLING-9206 - Add support for executing precompiled JSP scripts
This is an automated email from the ASF dual-hosted git repository.
radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-jsp.git
The following commit(s) were added to refs/heads/master by this push:
new 8ef3313 SLING-9206 - Add support for executing precompiled JSP scripts
8ef3313 is described below
commit 8ef33131205f47cd34f2d5a206ac445102d631ca
Author: Radu Cotescu <17...@users.noreply.github.com>
AuthorDate: Fri Mar 20 11:35:46 2020 +0100
SLING-9206 - Add support for executing precompiled JSP scripts
* added an optional import for org.apache.sling.scripting.bundle.tracker
* added the PrecompiledJSPRunner which registers as a service if the
previous API is available
* if the PrecompiledJSPRunner is available, the JSPScriptEngine will try
to execute a precompiled JSP, if one was available in the script context,
otherwise it will try to compile the script matching the request
* documented that the o.a.s.scripting.jsp.jasper.runtime package should
only be used by precompiled JSP scripts
---
bnd.bnd | 2 +
pom.xml | 10 +-
.../scripting/jsp/JspScriptEngineFactory.java | 303 ++++++++++-----------
.../sling/scripting/jsp/JspServletConfig.java | 6 +-
.../sling/scripting/jsp/PrecompiledJSPRunner.java | 114 ++++++++
.../scripting/jsp/jasper/runtime/package-info.java | 25 ++
.../jsp/jasper/servlet/JspServletWrapper.java | 8 +-
7 files changed, 305 insertions(+), 163 deletions(-)
diff --git a/bnd.bnd b/bnd.bnd
index 7e39640..568655a 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -1,3 +1,5 @@
ScriptEngine-Name:${project.name}
ScriptEngine-Version:${project.version}
+Import-Package: org.apache.sling.scripting.bundle.tracker.*;resolution:=optional, \\
+ *
-conditionalpackage: org.apache.el.*
diff --git a/pom.xml b/pom.xml
index 3d2093a..cdb1eb2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
</parent>
<artifactId>org.apache.sling.scripting.jsp</artifactId>
- <version>2.4.3-SNAPSHOT</version>
+ <version>2.5.0-SNAPSHOT</version>
<name>Apache Sling Scripting JSP</name>
<description>Support for JSP scripting</description>
@@ -107,7 +107,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.scripting.api</artifactId>
- <version>2.1.6</version>
+ <version>2.1.12</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -144,5 +144,11 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.scripting.bundle.tracker</artifactId>
+ <version>0.1.1-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
index d1a09ec..69a8f44 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
@@ -16,15 +16,15 @@
*/
package org.apache.sling.scripting.jsp;
-import static org.apache.sling.api.scripting.SlingBindings.SLING;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
+import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.script.Bindings;
import javax.script.ScriptContext;
@@ -33,9 +33,7 @@ import javax.script.ScriptException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
-import org.apache.sling.api.SlingException;
import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.SlingIOException;
import org.apache.sling.api.SlingServletException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
@@ -43,8 +41,6 @@ import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.api.scripting.SlingScript;
-import org.apache.sling.api.scripting.SlingScriptConstants;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.commons.classloader.ClassLoaderWriter;
import org.apache.sling.commons.classloader.ClassLoaderWriterListener;
@@ -52,6 +48,7 @@ import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
import org.apache.sling.commons.compiler.JavaCompiler;
import org.apache.sling.scripting.api.AbstractScriptEngineFactory;
import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
+import org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
import org.apache.sling.scripting.jsp.jasper.compiler.JspRuntimeContext;
import org.apache.sling.scripting.jsp.jasper.compiler.JspRuntimeContext.JspFactoryHandler;
import org.apache.sling.scripting.jsp.jasper.runtime.AnnotationProcessor;
@@ -66,12 +63,15 @@ import org.osgi.service.component.annotations.Deactivate;
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.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.sling.api.scripting.SlingBindings.SLING;
+
/**
* The JSP engine (a.k.a Jasper).
*
@@ -171,29 +171,36 @@ public class JspScriptEngineFactory
/** Default logger */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ private static final Object BINDINGS_NOT_SWAPPED = new Object();
+
private ServletContext slingServletContext;
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY)
+ private PrecompiledJSPRunner precompiledJSPRunner;
+
@Reference
private ClassLoaderWriter classLoaderWriter;
+ @Reference
+ private JavaCompiler javaCompiler;
+
+ @Reference
+ private ScriptingResourceResolverProvider scriptingResourceResolverProvider;
+
private DynamicClassLoaderManager dynamicClassLoaderManager;
private ClassLoader dynamicClassLoader;
- @Reference
- private JavaCompiler javaCompiler;
-
/** The io provider for reading and writing. */
private SlingIOProvider ioProvider;
private SlingTldLocationsCache tldLocationsCache;
private JspRuntimeContext jspRuntimeContext;
+ private ReentrantReadWriteLock jspRuntimeContextLock = new ReentrantReadWriteLock();
private JspServletOptions options;
- private JspServletContext jspServletContext;
-
private JspServletConfig servletConfig;
private boolean defaultIsSession;
@@ -246,105 +253,7 @@ public class JspScriptEngineFactory
return super.getParameter(name);
}
- /**
- * Call the error page
- * @param bindings The bindings
- * @param scriptHelper Script helper service
- * @param context The script context
- * @param scriptName The name of the script
- */
- private void callErrorPageJsp(final Bindings bindings,
- final SlingScriptHelper scriptHelper,
- final ScriptContext context,
- final String scriptName) throws RuntimeException {
- final SlingBindings slingBindings = new SlingBindings();
- slingBindings.putAll(bindings);
-
- ResourceResolver resolver = (ResourceResolver) context.getAttribute(SlingScriptConstants.ATTR_SCRIPT_RESOURCE_RESOLVER,
- SlingScriptConstants.SLING_SCOPE);
- if ( resolver == null ) {
- resolver = scriptHelper.getScript().getScriptResource().getResourceResolver();
- }
- final SlingIOProvider io = this.ioProvider;
- final JspFactoryHandler jspfh = this.jspFactoryHandler;
-
- // abort if JSP Support is shut down concurrently (SLING-2704)
- if (io == null || jspfh == null) {
- throw new RuntimeException("callJsp: JSP Script Engine seems to be shut down concurrently; not calling "+
- scriptHelper.getScript().getScriptResource().getPath());
- }
-
- final ResourceResolver oldResolver = io.setRequestResourceResolver(resolver);
- jspfh.incUsage();
- try {
- final JspServletWrapper errorJsp = getJspWrapper(scriptName, slingBindings);
- errorJsp.service(slingBindings);
-
- // The error page could be inside an include.
- final SlingHttpServletRequest request = slingBindings.getRequest();
- final Throwable t = (Throwable)request.getAttribute("javax.servlet.jsp.jspException");
-
- final Object newException = request
- .getAttribute("javax.servlet.error.exception");
-
- // t==null means the attribute was not set.
- if ((newException != null) && (newException == t)) {
- request.removeAttribute("javax.servlet.error.exception");
- }
-
- // now clear the error code - to prevent double handling.
- request.removeAttribute("javax.servlet.error.status_code");
- request.removeAttribute("javax.servlet.error.request_uri");
- request.removeAttribute("javax.servlet.error.status_code");
- request.removeAttribute("javax.servlet.jsp.jspException");
- } finally {
- jspfh.decUsage();
- io.resetRequestResourceResolver(oldResolver);
- }
- }
-
- /**
- * Call a JSP script
- * @param bindings The bindings
- * @param scriptHelper Script helper service
- * @param context The script context
- * @throws SlingServletException
- * @throws SlingIOException
- */
- private void callJsp(final Bindings bindings,
- final SlingScriptHelper scriptHelper,
- final ScriptContext context) throws RuntimeException {
-
- ResourceResolver resolver = (ResourceResolver) context.getAttribute(SlingScriptConstants.ATTR_SCRIPT_RESOURCE_RESOLVER,
- SlingScriptConstants.SLING_SCOPE);
- if ( resolver == null ) {
- resolver = scriptHelper.getScript().getScriptResource().getResourceResolver();
- }
- final SlingIOProvider io = this.ioProvider;
- final JspFactoryHandler jspfh = this.jspFactoryHandler;
- // abort if JSP Support is shut down concurrently (SLING-2704)
- if (io == null || jspfh == null) {
- throw new RuntimeException("callJsp: JSP Script Engine seems to be shut down concurrently; not calling "+
- scriptHelper.getScript().getScriptResource().getPath());
- }
-
- final ResourceResolver oldResolver = io.setRequestResourceResolver(resolver);
- jspfh.incUsage();
- try {
- final SlingBindings slingBindings = new SlingBindings();
- slingBindings.putAll(bindings);
-
- final JspServletWrapper jsp = getJspWrapper(scriptHelper, slingBindings);
- // create a SlingBindings object
- jsp.service(slingBindings);
- } finally {
- jspfh.decUsage();
- io.resetRequestResourceResolver(oldResolver);
- }
- }
-
- private JspServletWrapper getJspWrapper(final String scriptName, final SlingBindings bindings)
- throws SlingException {
+ private JspServletWrapper getJspWrapper(final String scriptName) {
JspRuntimeContext rctxt = this.getJspRuntimeContext();
JspServletWrapper wrapper = rctxt.getWrapper(scriptName);
@@ -372,13 +281,6 @@ public class JspScriptEngineFactory
return wrapper;
}
- private JspServletWrapper getJspWrapper(final SlingScriptHelper scriptHelper, final SlingBindings bindings)
- throws SlingException {
- final SlingScript script = scriptHelper.getScript();
- final String scriptName = script.getScriptResource().getPath();
- return getJspWrapper(scriptName, bindings);
- }
-
// ---------- SCR integration ----------------------------------------------
/**
@@ -407,7 +309,7 @@ public class JspScriptEngineFactory
options = new JspServletOptions(slingServletContext, ioProvider,
properties, tldLocationsCache);
- jspServletContext = new JspServletContext(ioProvider,
+ JspServletContext jspServletContext = new JspServletContext(ioProvider,
slingServletContext, tldLocationsCache);
servletConfig = new JspServletConfig(jspServletContext, options.getProperties());
@@ -454,16 +356,14 @@ public class JspScriptEngineFactory
private void checkJasperConfig() {
boolean changed = false;
InputStream is = null;
- try {
+ try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
is = this.classLoaderWriter.getInputStream(CONFIG_PATH);
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ( ( length = is.read(buffer)) != -1 ) {
baos.write(buffer, 0, length);
}
- baos.close();
- final String oldKey = new String(baos.toByteArray(), "UTF-8");
+ final String oldKey = new String(baos.toByteArray(), StandardCharsets.UTF_8);
changed = !oldKey.equals(this.servletConfig.getConfigKey());
if ( changed ) {
logger.info("Removing all class files due to jsp configuration change");
@@ -480,20 +380,10 @@ public class JspScriptEngineFactory
}
}
if ( changed ) {
- OutputStream os = null;
- try {
- os = this.classLoaderWriter.getOutputStream(CONFIG_PATH);
- os.write(this.servletConfig.getConfigKey().getBytes("UTF-8"));
- } catch ( final IOException ignore ) {
+ try (OutputStream os = this.classLoaderWriter.getOutputStream(CONFIG_PATH)) {
+ os.write(this.servletConfig.getConfigKey().getBytes(StandardCharsets.UTF_8));
+ } catch (final IOException ignore) {
// ignore
- } finally {
- if ( os != null ) {
- try {
- os.close();
- } catch ( final IOException ignore ) {
- // ignore
- }
- }
}
this.classLoaderWriter.delete("/org/apache/jsp");
}
@@ -540,7 +430,7 @@ public class JspScriptEngineFactory
/**
* Bind the class load provider.
*
- * @param repositoryClassLoaderProvider the new provider
+ * @param rclp the new provider
*/
@Reference(cardinality=ReferenceCardinality.MANDATORY, policy=ReferencePolicy.STATIC)
protected void bindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
@@ -552,7 +442,7 @@ public class JspScriptEngineFactory
/**
* Unbind the class loader provider.
- * @param repositoryClassLoaderProvider the old provider
+ * @param rclp the old provider
*/
protected void unbindDynamicClassLoaderManager(final DynamicClassLoaderManager rclp) {
if ( this.dynamicClassLoaderManager == rclp ) {
@@ -584,10 +474,97 @@ public class JspScriptEngineFactory
super(JspScriptEngineFactory.this);
}
+ /**
+ * Call a JSP script
+ * @param slingBindings The bindings
+ */
+ private void callJsp(final SlingBindings slingBindings) {
+ SlingScriptHelper scriptHelper = slingBindings.getSling();
+ if (scriptHelper == null) {
+ throw new IllegalStateException(String.format("The %s variable is missing from the bindings.", SLING));
+ }
+ ResourceResolver resolver = scriptingResourceResolverProvider.getRequestScopedResourceResolver();
+ if ( resolver == null ) {
+ resolver = scriptHelper.getScript().getScriptResource().getResourceResolver();
+ }
+ final SlingIOProvider io = ioProvider;
+ final JspFactoryHandler jspfh = jspFactoryHandler;
+ // abort if JSP Support is shut down concurrently (SLING-2704)
+ if (io == null || jspfh == null) {
+ throw new RuntimeException("callJsp: JSP Script Engine seems to be shut down concurrently; not calling "+
+ scriptHelper.getScript().getScriptResource().getPath());
+ }
+
+ final ResourceResolver oldResolver = io.setRequestResourceResolver(resolver);
+ jspfh.incUsage();
+ try {
+ final JspServletWrapper jsp = getJspWrapper(scriptHelper.getScript().getScriptResource().getPath());
+ jsp.service(slingBindings);
+ } finally {
+ jspfh.decUsage();
+ io.resetRequestResourceResolver(oldResolver);
+ }
+ }
+
+ /**
+ * Call the error page
+ * @param slingBindings The bindings
+ * @param scriptName The name of the script
+ */
+ private void callErrorPageJsp(final SlingBindings slingBindings, final String scriptName) {
+ SlingScriptHelper scriptHelper = slingBindings.getSling();
+ if (scriptHelper == null) {
+ throw new IllegalStateException(String.format("The %s variable is missing from the bindings.", SLING));
+ }
+ ResourceResolver resolver = scriptingResourceResolverProvider.getRequestScopedResourceResolver();
+ if ( resolver == null ) {
+ resolver = scriptHelper.getScript().getScriptResource().getResourceResolver();
+ }
+ final SlingIOProvider io = ioProvider;
+ final JspFactoryHandler jspfh = jspFactoryHandler;
+
+ // abort if JSP Support is shut down concurrently (SLING-2704)
+ if (io == null || jspfh == null) {
+ throw new RuntimeException("callJsp: JSP Script Engine seems to be shut down concurrently; not calling "+
+ scriptHelper.getScript().getScriptResource().getPath());
+ }
+
+ final ResourceResolver oldResolver = io.setRequestResourceResolver(resolver);
+ jspfh.incUsage();
+ try {
+ final JspServletWrapper errorJsp = getJspWrapper(scriptName);
+ errorJsp.service(slingBindings);
+
+ // The error page could be inside an include.
+ final SlingHttpServletRequest request = slingBindings.getRequest();
+ if (request != null) {
+ final Throwable t = (Throwable) request.getAttribute("javax.servlet.jsp.jspException");
+
+ final Object newException = request
+ .getAttribute("javax.servlet.error.exception");
+
+ // t==null means the attribute was not set.
+ if ((newException != null) && (newException == t)) {
+ request.removeAttribute("javax.servlet.error.exception");
+ }
+
+ // now clear the error code - to prevent double handling.
+ request.removeAttribute("javax.servlet.error.status_code");
+ request.removeAttribute("javax.servlet.error.request_uri");
+ request.removeAttribute("javax.servlet.error.status_code");
+ request.removeAttribute("javax.servlet.jsp.jspException");
+ }
+ } finally {
+ jspfh.decUsage();
+ io.resetRequestResourceResolver(oldResolver);
+ }
+ }
+
@Override
- public Object eval(final Reader script, final ScriptContext context)
- throws ScriptException {
+ public Object eval(final Reader script, final ScriptContext context) throws ScriptException {
Bindings props = context.getBindings(ScriptContext.ENGINE_SCOPE);
+ SlingBindings slingBindings = new SlingBindings();
+ slingBindings.putAll(props);
SlingScriptHelper scriptHelper = (SlingScriptHelper) props.get(SLING);
if (scriptHelper != null) {
@@ -596,8 +573,20 @@ public class JspScriptEngineFactory
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(dynamicClassLoader);
+ SlingHttpServletRequest request = slingBindings.getRequest();
+ Object oldSlingBindings = BINDINGS_NOT_SWAPPED;
+ if (request != null) {
+ oldSlingBindings = request.getAttribute(SlingBindings.class.getName());
+ request.setAttribute(SlingBindings.class.getName(), slingBindings);
+ }
try {
- callJsp(props, scriptHelper, context);
+ boolean contextHasPrecompiledJsp = false;
+ if (precompiledJSPRunner != null) {
+ contextHasPrecompiledJsp = precompiledJSPRunner.callPrecompiledJSP(jspFactoryHandler, servletConfig, slingBindings);
+ }
+ if (!contextHasPrecompiledJsp) {
+ callJsp(slingBindings);
+ }
} catch (final SlingServletException e) {
// ServletExceptions use getRootCause() instead of getCause(),
// so we have to extract the actual root cause and pass it as
@@ -618,9 +607,8 @@ public class JspScriptEngineFactory
throw new BetterScriptException(e.getMessage(), e);
} catch (final SlingPageException sje) {
try {
- callErrorPageJsp(props, scriptHelper, context, sje.getErrorPage());
- }
- catch (final Exception e) {
+ callErrorPageJsp(slingBindings, sje.getErrorPage());
+ } catch (final Exception e) {
throw new BetterScriptException(e.getMessage(), e);
}
@@ -634,7 +622,9 @@ public class JspScriptEngineFactory
// make sure the context loader is reset after setting up the
// JSP runtime context
Thread.currentThread().setContextClassLoader(old);
-
+ if (request != null && oldSlingBindings != BINDINGS_NOT_SWAPPED) {
+ request.setAttribute(SlingBindings.class.getName(), oldSlingBindings);
+ }
}
}
return null;
@@ -654,16 +644,23 @@ public class JspScriptEngineFactory
}
private JspRuntimeContext getJspRuntimeContext() {
- if ( this.jspRuntimeContext == null ) {
- synchronized ( this ) {
- if ( this.jspRuntimeContext == null ) {
- // Initialize the JSP Runtime Context
- this.jspRuntimeContext = new JspRuntimeContext(slingServletContext,
- options, ioProvider);
- }
+ jspRuntimeContextLock.readLock().lock();
+ if (jspRuntimeContext == null) {
+ jspRuntimeContextLock.readLock().unlock();
+ jspRuntimeContextLock.writeLock().lock();
+ try {
+ jspRuntimeContext = new JspRuntimeContext(slingServletContext,
+ options, ioProvider);
+ jspRuntimeContextLock.readLock().lock();
+ } finally {
+ jspRuntimeContextLock.writeLock().unlock();
}
}
- return this.jspRuntimeContext;
+ try {
+ return jspRuntimeContext;
+ } finally {
+ jspRuntimeContextLock.readLock().unlock();
+ }
}
/**
@@ -717,7 +714,7 @@ public class JspScriptEngineFactory
};
t.start();
}
-
+
@Override
public void onClassLoaderClear(String context) {
final JspRuntimeContext rctxt = this.jspRuntimeContext;
diff --git a/src/main/java/org/apache/sling/scripting/jsp/JspServletConfig.java b/src/main/java/org/apache/sling/scripting/jsp/JspServletConfig.java
index 70d5cf8..ab616b7 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/JspServletConfig.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/JspServletConfig.java
@@ -76,4 +76,8 @@ class JspServletConfig implements ServletConfig {
}
return sb.toString();
}
-}
\ No newline at end of file
+
+ public Map<String, String> getProperties() {
+ return Collections.unmodifiableMap(properties);
+ }
+}
diff --git a/src/main/java/org/apache/sling/scripting/jsp/PrecompiledJSPRunner.java b/src/main/java/org/apache/sling/scripting/jsp/PrecompiledJSPRunner.java
new file mode 100644
index 0000000..e39cbc4
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/jsp/PrecompiledJSPRunner.java
@@ -0,0 +1,114 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.jsp;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.naming.NamingException;
+import javax.servlet.ServletException;
+
+import org.apache.sling.api.SlingException;
+import org.apache.sling.api.SlingIOException;
+import org.apache.sling.api.SlingServletException;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.commons.compiler.source.JavaEscapeHelper;
+import org.apache.sling.scripting.bundle.tracker.BundledRenderUnit;
+import org.apache.sling.scripting.jsp.jasper.compiler.JspRuntimeContext;
+import org.apache.sling.scripting.jsp.jasper.runtime.AnnotationProcessor;
+import org.apache.sling.scripting.jsp.jasper.runtime.HttpJspBase;
+import org.osgi.framework.Bundle;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = {PrecompiledJSPRunner.class})
+public class PrecompiledJSPRunner {
+
+ private final ConcurrentHashMap<HttpJspBase, Object> locks = new ConcurrentHashMap<>();
+
+ boolean callPrecompiledJSP(JspRuntimeContext.JspFactoryHandler jspFactoryHandler, JspServletConfig jspServletConfig,
+ SlingBindings bindings) {
+ boolean found = false;
+ HttpJspBase jsp = null;
+ try {
+ jspFactoryHandler.incUsage();
+ BundledRenderUnit bundledRenderUnit = (BundledRenderUnit) bindings.get(BundledRenderUnit.VARIABLE);
+ if (bundledRenderUnit != null && bundledRenderUnit.getUnit() instanceof HttpJspBase) {
+ found = true;
+ jsp = (HttpJspBase) bundledRenderUnit.getUnit();
+ if (jsp.getServletConfig() == null) {
+ Object lock = locks.computeIfAbsent(jsp, key -> new Object());
+ synchronized (lock) {
+ if (jsp.getServletConfig() == null) {
+ PrecompiledServletConfig servletConfig = new PrecompiledServletConfig(jspServletConfig, bundledRenderUnit);
+ AnnotationProcessor annotationProcessor =
+ (AnnotationProcessor) jspServletConfig.getServletContext()
+ .getAttribute(AnnotationProcessor.class.getName());
+ if (annotationProcessor != null) {
+ annotationProcessor.processAnnotations(jsp);
+ annotationProcessor.postConstruct(jsp);
+ }
+ jsp.init(servletConfig);
+ }
+ }
+ }
+ jsp.service(bindings.getRequest(), bindings.getResponse());
+
+ }
+ } catch (IllegalAccessException | InvocationTargetException | NamingException e) {
+ throw new SlingException("Unable to process annotations for servlet " + jsp.getClass().getName() + ".", e);
+ } catch (NoClassDefFoundError ignored) {
+ // wave your hands like we don't care - we're missing support for precompiled JSPs
+ } catch (IOException e) {
+ throw new SlingIOException(e);
+ } catch (ServletException e) {
+ throw new SlingServletException(e);
+ } finally {
+ jspFactoryHandler.decUsage();
+ if (jsp != null) {
+ locks.remove(jsp);
+ }
+ }
+ return found;
+ }
+
+ private static class PrecompiledServletConfig extends JspServletConfig {
+
+ private final BundledRenderUnit bundledRenderUnit;
+ private String servletName;
+
+ PrecompiledServletConfig(JspServletConfig jspServletConfig, BundledRenderUnit bundledRenderUnit) {
+ super(jspServletConfig.getServletContext(), new HashMap<>(jspServletConfig.getProperties()));
+ this.bundledRenderUnit = bundledRenderUnit;
+ }
+
+ @Override
+ public String getServletName() {
+ if (servletName == null && bundledRenderUnit.getUnit() != null) {
+ Bundle bundle = bundledRenderUnit.getBundle();
+ Object jsp = bundledRenderUnit.getUnit();
+ String originalName =
+ JavaEscapeHelper.unescapeAll(jsp.getClass().getPackage().getName()) + "/" + JavaEscapeHelper.unescapeAll(jsp.getClass().getSimpleName());
+ servletName = bundle.getSymbolicName() + ": " + originalName;
+ }
+ return servletName;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/scripting/jsp/jasper/runtime/package-info.java b/src/main/java/org/apache/sling/scripting/jsp/jasper/runtime/package-info.java
new file mode 100644
index 0000000..62839ca
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/jsp/jasper/runtime/package-info.java
@@ -0,0 +1,25 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+/**
+ * This package should only be used by compiled JSP scripts when being executed on the platform.
+ */
+@Version("2.5.0")
+package org.apache.sling.scripting.jsp.jasper.runtime;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java b/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
index d4eb1a2..6845d8b 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
@@ -41,7 +41,6 @@ import javax.servlet.jsp.tagext.TagInfo;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.sling.api.SlingException;
-import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingIOException;
import org.apache.sling.api.SlingServletException;
import org.apache.sling.api.scripting.ScriptEvaluationException;
@@ -442,11 +441,8 @@ public class JspServletWrapper {
* request parameter has an illegal value.
*/
public void service(final SlingBindings bindings) {
- final SlingHttpServletRequest request = bindings.getRequest();
- final Object oldValue = request.getAttribute(SlingBindings.class.getName());
try {
- request.setAttribute(SlingBindings.class.getName(), bindings);
- service(request, bindings.getResponse());
+ service(bindings.getRequest(), bindings.getResponse());
} catch (SlingException se) {
// rethrow as is
throw se;
@@ -454,8 +450,6 @@ public class JspServletWrapper {
throw new SlingIOException(ioe);
} catch (ServletException se) {
throw new SlingServletException(se);
- } finally {
- request.setAttribute(SlingBindings.class.getName(), oldValue);
}
}