blob: a95f24e2a893c916c99abd40f6eb752e4e99574d [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.oozie.server;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Helper class that is used to handle JSP requests in Oozie server.
*/
public class JspHandler {
private static final Logger LOG = LoggerFactory.getLogger(JspHandler.class);
private final File scratchDir;
private final WebRootResourceLocator webRootResourceLocator;
public JspHandler(final File scratchDir, final WebRootResourceLocator webRootResourceLocator) {
this.scratchDir = scratchDir;
this.webRootResourceLocator = webRootResourceLocator;
}
/**
* Establish Scratch directory for the servlet context (used by JSP compilation)
*/
private File getScratchDir() throws IOException
{
if (scratchDir.exists()) {
LOG.info(String.format("Scratch directory exists and will be reused: %s",
scratchDir.getAbsolutePath().replaceAll("[\r\n]","")));
return scratchDir;
}
if (!scratchDir.mkdirs()) {
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
LOG.info(String.format("Scratch directory created: %s", scratchDir.getAbsolutePath().replaceAll("[\r\n]","")));
return scratchDir;
}
/**
* Setup the basic application "context" for this application at "/"
* This is also known as the handler tree (in jetty speak)
* @param servletContextHandler the context handler
* @throws IOException in case of IO errors
* @throws URISyntaxException if the server URI is not well formatted
*/
public void setupWebAppContext(WebAppContext servletContextHandler)
throws IOException, URISyntaxException
{
Objects.requireNonNull(servletContextHandler, "servletContextHandler is null");
File scratchDir = getScratchDir();
servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir);
servletContextHandler.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$");
URI baseUri = webRootResourceLocator.getWebRootResourceUri();
servletContextHandler.setResourceBase(baseUri.toASCIIString());
servletContextHandler.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
servletContextHandler.addBean(new ServletContainerInitializersStarter(servletContextHandler), true);
servletContextHandler.setClassLoader(getUrlClassLoader());
servletContextHandler.addServlet(jspServletHolder(), "*.jsp");
servletContextHandler.addServlet(jspFileMappedServletHolder(), "/oozie/");
servletContextHandler.addServlet(defaultServletHolder(baseUri), "/");
}
/**
* Ensure the jsp engine is initialized correctly
*/
private List<ContainerInitializer> jspInitializers()
{
JettyJasperInitializer sci = new JettyJasperInitializer();
ContainerInitializer initializer = new ContainerInitializer(sci, null);
List<ContainerInitializer> initializers = new ArrayList<>();
initializers.add(initializer);
return initializers;
}
/**
* Set Classloader of Context to be sane (needed for JSTL)
* JSP requires a non-System classloader, this simply wraps the
* embedded System classloader in a way that makes it suitable
* for JSP to use
*/
private ClassLoader getUrlClassLoader()
{
ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
return jspClassLoader;
}
/**
* Create JSP Servlet (must be named "jsp")
*/
private ServletHolder jspServletHolder()
{
ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
holderJsp.setInitOrder(0);
holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
holderJsp.setInitParameter("fork", "false");
holderJsp.setInitParameter("xpoweredBy", "false");
holderJsp.setInitParameter("compilerTargetVM", "1.7");
holderJsp.setInitParameter("compilerSourceVM", "1.7");
holderJsp.setInitParameter("keepgenerated", "true");
return holderJsp;
}
/**
* Create Example of mapping jsp to path spec
*/
private ServletHolder jspFileMappedServletHolder()
{
ServletHolder holderAltMapping = new ServletHolder();
holderAltMapping.setName("index.jsp");
holderAltMapping.setForcedPath("/index.jsp");
return holderAltMapping;
}
/**
* Create Default Servlet (must be named "default")
*/
private ServletHolder defaultServletHolder(URI baseUri)
{
ServletHolder holderDefault = new ServletHolder("default", DefaultServlet.class);
holderDefault.setInitParameter("resourceBase", baseUri.toASCIIString());
holderDefault.setInitParameter("dirAllowed", "true");
return holderDefault;
}
}