/*
 * Copyright 2012-2020 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.boot.web.embedded.jetty;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;

import javax.servlet.ServletContainerInitializer;

import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.webapp.WebAppContext;

import org.springframework.util.ClassUtils;

Jetty AbstractLifeCycle to initialize Jasper.
Author:Vladimir Tsanev, Phillip Webb
/** * Jetty {@link AbstractLifeCycle} to initialize Jasper. * * @author Vladimir Tsanev * @author Phillip Webb */
class JasperInitializer extends AbstractLifeCycle { private static final String[] INITIALIZER_CLASSES = { "org.eclipse.jetty.apache.jsp.JettyJasperInitializer", "org.apache.jasper.servlet.JasperInitializer" }; private final WebAppContext context; private final ServletContainerInitializer initializer; JasperInitializer(WebAppContext context) { this.context = context; this.initializer = newInitializer(); } private ServletContainerInitializer newInitializer() { for (String className : INITIALIZER_CLASSES) { try { Class<?> initializerClass = ClassUtils.forName(className, null); return (ServletContainerInitializer) initializerClass.getDeclaredConstructor().newInstance(); } catch (Exception ex) { // Ignore } } return null; } @Override protected void doStart() throws Exception { if (this.initializer == null) { return; } if (ClassUtils.isPresent("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", getClass().getClassLoader())) { TomcatURLStreamHandlerFactory.register(); } else { try { URL.setURLStreamHandlerFactory(new WarUrlStreamHandlerFactory()); } catch (Error ex) { // Ignore } } ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(this.context.getClassLoader()); try { setExtendedListenerTypes(true); this.initializer.onStartup(null, this.context.getServletContext()); } finally { setExtendedListenerTypes(false); } } finally { Thread.currentThread().setContextClassLoader(classLoader); } } private void setExtendedListenerTypes(boolean extended) { try { this.context.getServletContext().setExtendedListenerTypes(extended); } catch (NoSuchMethodError ex) { // Not available on Jetty 8 } }
URLStreamHandlerFactory to support war protocol.
/** * {@link URLStreamHandlerFactory} to support {@literal war} protocol. */
private static class WarUrlStreamHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("war".equals(protocol)) { return new WarUrlStreamHandler(); } return null; } }
URLStreamHandler for war protocol compatible with jasper's urls produced by getJarEntryURL.getJarEntryURL(URL, String).
/** * {@link URLStreamHandler} for {@literal war} protocol compatible with jasper's * {@link URL urls} produced by * {@link org.apache.tomcat.util.scan.JarFactory#getJarEntryURL(URL, String)}. */
private static class WarUrlStreamHandler extends URLStreamHandler { @Override protected void parseURL(URL u, String spec, int start, int limit) { String path = "jar:" + spec.substring("war:".length()); int separator = path.indexOf("*/"); if (separator >= 0) { path = path.substring(0, separator) + "!/" + path.substring(separator + 2); } setURL(u, u.getProtocol(), "", -1, null, null, path, null, null); } @Override protected URLConnection openConnection(URL u) throws IOException { return new WarURLConnection(u); } }
URLConnection to support war protocol.
/** * {@link URLConnection} to support {@literal war} protocol. */
private static class WarURLConnection extends URLConnection { private final URLConnection connection; protected WarURLConnection(URL url) throws IOException { super(url); this.connection = new URL(url.getFile()).openConnection(); } @Override public void connect() throws IOException { if (!this.connected) { this.connection.connect(); this.connected = true; } } @Override public InputStream getInputStream() throws IOException { connect(); return this.connection.getInputStream(); } } }