/*
 * Copyright 2015 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
 *
 *      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.springframework.boot.loader;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.util.AsciiBytes;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * A (possibly temporary) alternative to {@link JarLauncher} that provides a public
 * {@link #launch(String[])} method.
 *
 * Also, it restricts the classloader of the launched application to the contents of the uber-jar and the
 * extension classloader of the JVM.
 *
 * @author Mark Fisher
 * @author Marius Bogoevici
 */
public class ModuleJarLauncher extends ExecutableArchiveLauncher {

	private static final AsciiBytes LIB = new AsciiBytes("lib/");

	public ModuleJarLauncher(Archive archive) {
		super(archive);
	}

	@Override
	protected boolean isNestedArchive(Archive.Entry entry) {
		return !entry.isDirectory() && entry.getName().startsWith(LIB);
	}

	@Override
	protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
		archives.add(0, getArchive());
	}

	@Override
	// TODO: this method is protected in Spring Boot but we need it to be public here
	public void launch(String[] args) {
		super.launch(args);
	}

	@Override
	protected void launch(String[] args, String mainClass, ClassLoader classLoader)
			throws Exception {
		if (ClassUtils.isPresent(
				"org.apache.catalina.webresources.TomcatURLStreamHandlerFactory",
				classLoader)) {
			// Ensure the method is invoked on a class that is loaded by the provided
			// class loader (not the current context class loader):
			Method method = ReflectionUtils
					.findMethod(
							classLoader
							.loadClass("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory"),
							"disable");
			ReflectionUtils.invokeMethod(method, null);
		}
		super.launch(args, mainClass, classLoader);
	}

	@Override
	protected ClassLoader createClassLoader(URL[] urls) throws Exception {
		ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
		if (systemClassLoader instanceof URLClassLoader) {
			URLClassLoader classLoader = (URLClassLoader) systemClassLoader;
			URL[] toUse = new URL[urls.length + classLoader.getURLs().length];
			System.arraycopy(urls, 0, toUse, 0, urls.length);
			System.arraycopy(classLoader.getURLs(), 0, toUse, urls.length, classLoader.getURLs().length);
			return new LaunchedURLClassLoader(toUse, null);
		} else {
			return new LaunchedURLClassLoader(urls, systemClassLoader);
		}
	}

}

@@ -2786,24 +2786,204 @@
 %0A%09%09%09
-URLClassLoader c
+// add the URLs of the application classloader to the created classloader%0A%09%09%09// to compensate for LaunchedURLClassLoader not delegating to parent to retrieve resources%0A%09%09%09URLClassLoader systemUrlC
 lass
@@ -3036,21 +3036,26 @@
 %09%09URL%5B%5D 
-toUse
+mergedUrls
  = new U
@@ -3071,17 +3071,26 @@
 ength + 
-c
+systemUrlC
 lassLoad
@@ -3140,21 +3140,26 @@
 rls, 0, 
-toUse
+mergedUrls
 , 0, url
@@ -3189,17 +3189,26 @@
 raycopy(
-c
+systemUrlC
 lassLoad
@@ -3224,21 +3224,26 @@
 s(), 0, 
-toUse
+mergedUrls
 , urls.l
@@ -3248,18 +3248,32 @@
 .length,
- c
+%0A%09%09%09%09%09systemUrlC
 lassLoad
@@ -3301,53 +3301,170 @@
 %0A%09%09%09
-return new LaunchedURLClassLoader(toUse, null
+// add the extension classloader as parent to the created context, if accessible%0A%09%09%09return new LaunchedURLClassLoader(mergedUrls, systemUrlClassLoader.getParent()
 );%0A%09

Set extension classloader as parent for the module classloader