blob: 6d259efc043014d30caeb97fbf1052d9bed76aa9 [file] [log] [blame]
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ 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.servlets.resolver.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;
}
}
}