Merge branch '1.4.x' into 1.5.x

pull/8474/merge
Andy Wilkinson 8 years ago
commit 1395f38ee7

@ -34,8 +34,6 @@ import org.springframework.util.FileCopyUtils;
*/
abstract class AbstractApplicationLauncher extends ExternalResource {
private final File serverPortFile = new File("target/server.port");
private final ApplicationBuilder applicationBuilder;
private Process process;
@ -62,8 +60,15 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
protected abstract List<String> getArguments(File archive);
protected abstract File getWorkingDirectory();
protected abstract String getDescription(String packaging);
private Process startApplication() throws Exception {
this.serverPortFile.delete();
File workingDirectory = getWorkingDirectory();
File serverPortFile = workingDirectory == null ? new File("target/server.port")
: new File(workingDirectory, "target/server.port");
serverPortFile.delete();
File archive = this.applicationBuilder.buildApplication();
List<String> arguments = new ArrayList<String>();
arguments.add(System.getProperty("java.home") + "/bin/java");
@ -72,14 +77,17 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
arguments.toArray(new String[arguments.size()]));
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
if (workingDirectory != null) {
processBuilder.directory(workingDirectory);
}
Process process = processBuilder.start();
this.httpPort = awaitServerPort(process);
this.httpPort = awaitServerPort(process, serverPortFile);
return process;
}
private int awaitServerPort(Process process) throws Exception {
private int awaitServerPort(Process process, File serverPortFile) throws Exception {
long end = System.currentTimeMillis() + 30000;
while (this.serverPortFile.length() == 0) {
while (serverPortFile.length() == 0) {
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(
"server.port file was not written within 30 seconds");
@ -89,8 +97,8 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
}
Thread.sleep(100);
}
return Integer.parseInt(
FileCopyUtils.copyToString(new FileReader(this.serverPortFile)));
return Integer
.parseInt(FileCopyUtils.copyToString(new FileReader(serverPortFile)));
}
}

@ -19,6 +19,8 @@ package org.springframework.boot.context.embedded;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -47,29 +49,38 @@ public abstract class AbstractEmbeddedServletContainerIntegrationTests {
protected final RestTemplate rest = new RestTemplate();
public static Object[] parameters(String packaging) {
public static Object[] parameters(String packaging,
List<Class<? extends AbstractApplicationLauncher>> applicationLaunchers) {
List<Object> parameters = new ArrayList<Object>();
parameters.addAll(createParameters(packaging, "jetty", "current"));
parameters.addAll(
createParameters(packaging, "tomcat", "current", "8.0.41", "7.0.75"));
parameters.addAll(createParameters(packaging, "undertow", "current"));
parameters.addAll(createParameters(packaging, "jetty",
Arrays.asList("current", "9.3.16.v20170120"), applicationLaunchers));
parameters.addAll(createParameters(packaging, "tomcat",
Arrays.asList("current", "8.0.41", "7.0.75"), applicationLaunchers));
parameters.addAll(createParameters(packaging, "undertow",
Collections.singletonList("current"), applicationLaunchers));
return parameters.toArray(new Object[parameters.size()]);
}
private static List<Object> createParameters(String packaging, String container,
String... versions) {
List<String> versions,
List<Class<? extends AbstractApplicationLauncher>> applicationLaunchers) {
List<Object> parameters = new ArrayList<Object>();
for (String version : versions) {
ApplicationBuilder applicationBuilder = new ApplicationBuilder(
temporaryFolder, packaging, container, version);
parameters.add(new Object[] {
StringUtils.capitalise(container) + " " + version + " packaged "
+ packaging,
new PackagedApplicationLauncher(applicationBuilder) });
parameters.add(new Object[] {
StringUtils.capitalise(container) + " " + version + " exploded "
+ packaging,
new ExplodedApplicationLauncher(applicationBuilder) });
for (Class<? extends AbstractApplicationLauncher> launcherClass : applicationLaunchers) {
try {
AbstractApplicationLauncher launcher = launcherClass
.getDeclaredConstructor(ApplicationBuilder.class)
.newInstance(applicationBuilder);
String name = StringUtils.capitalise(container) + " " + version + ": "
+ launcher.getDescription(packaging);
parameters.add(new Object[] { name, launcher });
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
return parameters;
}

@ -0,0 +1,141 @@
/*
* Copyright 2012-2017 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.context.embedded;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
/**
* {@link AbstractApplicationLauncher} that launches a Spring Boot application with a
* classpath similar to that used when run with Maven or Gradle.
*
* @author Andy Wilkinson
*/
class BootRunApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/run");
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
}
@Override
protected List<String> getArguments(File archive) {
try {
explodeArchive(archive);
deleteLauncherClasses();
File targetClasses = populateTargetClasses(archive);
File dependencies = populateDependencies(archive);
populateSrcMainWebapp();
List<String> classpath = new ArrayList<String>();
classpath.add(targetClasses.getAbsolutePath());
for (File dependency : dependencies.listFiles()) {
classpath.add(dependency.getAbsolutePath());
}
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private void deleteLauncherClasses() {
FileSystemUtils.deleteRecursively(new File(this.exploded, "org"));
}
private File populateTargetClasses(File archive) {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
new File(this.exploded, getClassesPath(archive)).renameTo(targetClasses);
return targetClasses;
}
private File populateDependencies(File archive) {
File dependencies = new File(this.exploded, "dependencies");
dependencies.mkdirs();
List<String> libPaths = getLibPaths(archive);
for (String libPath : libPaths) {
for (File jar : new File(this.exploded, libPath).listFiles()) {
jar.renameTo(new File(dependencies, jar.getName()));
}
}
return dependencies;
}
private void populateSrcMainWebapp() {
File srcMainWebapp = new File(this.exploded, "src/main/webapp");
srcMainWebapp.mkdirs();
new File(this.exploded, "webapp-resource.txt")
.renameTo(new File(srcMainWebapp, "webapp-resource.txt"));
}
private String getClassesPath(File archive) {
return archive.getName().endsWith(".jar") ? "BOOT-INF/classes"
: "WEB-INF/classes";
}
private List<String> getLibPaths(File archive) {
return archive.getName().endsWith(".jar")
? Collections.singletonList("BOOT-INF/lib")
: Arrays.asList("WEB-INF/lib", "WEB-INF/lib-provided");
}
private void explodeArchive(File archive) throws IOException {
FileSystemUtils.deleteRecursively(this.exploded);
JarFile jarFile = new JarFile(archive);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
File extracted = new File(this.exploded, jarEntry.getName());
if (jarEntry.isDirectory()) {
extracted.mkdirs();
}
else {
FileOutputStream extractedOutputStream = new FileOutputStream(extracted);
StreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);
extractedOutputStream.close();
}
}
jarFile.close();
}
@Override
protected File getWorkingDirectory() {
return this.exploded;
}
@Override
protected String getDescription(String packaging) {
return "build system run " + packaging + " project";
}
}

@ -0,0 +1,67 @@
/*
* Copyright 2012-2017 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.context.embedded;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for Spring Boot's embedded servlet container support when developing
* a jar application.
*
* @author Andy Wilkinson
*/
@RunWith(Parameterized.class)
public class EmbeddedServletContainerJarDevelopmentIntegrationTests
extends AbstractEmbeddedServletContainerIntegrationTests {
@Parameters(name = "{0}")
public static Object[] parameters() {
return AbstractEmbeddedServletContainerIntegrationTests.parameters("jar", Arrays
.asList(BootRunApplicationLauncher.class, IdeApplicationLauncher.class));
}
public EmbeddedServletContainerJarDevelopmentIntegrationTests(String name,
AbstractApplicationLauncher launcher) {
super(name, launcher);
}
@Test
public void metaInfResourceFromDependencyIsAvailableViaHttp() throws Exception {
ResponseEntity<String> entity = this.rest
.getForEntity("/nested-meta-inf-resource.txt", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
public void metaInfResourceFromDependencyIsAvailableViaServletContext()
throws Exception {
ResponseEntity<String> entity = this.rest
.getForEntity("/nested-meta-inf-resource.txt", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}

@ -16,6 +16,8 @@
package org.springframework.boot.context.embedded;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@ -38,7 +40,9 @@ public class EmbeddedServletContainerJarPackagingIntegrationTests
@Parameters(name = "{0}")
public static Object[] parameters() {
return AbstractEmbeddedServletContainerIntegrationTests.parameters("jar");
return AbstractEmbeddedServletContainerIntegrationTests.parameters("jar",
Arrays.asList(PackagedApplicationLauncher.class,
ExplodedApplicationLauncher.class));
}
public EmbeddedServletContainerJarPackagingIntegrationTests(String name,

@ -0,0 +1,74 @@
/*
* Copyright 2012-2017 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.context.embedded;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for Spring Boot's embedded servlet container support when developing
* a war application.
*
* @author Andy Wilkinson
*/
@RunWith(Parameterized.class)
public class EmbeddedServletContainerWarDevelopmentIntegrationTests
extends AbstractEmbeddedServletContainerIntegrationTests {
@Parameters(name = "{0}")
public static Object[] parameters() {
return AbstractEmbeddedServletContainerIntegrationTests.parameters("war", Arrays
.asList(BootRunApplicationLauncher.class, IdeApplicationLauncher.class));
}
public EmbeddedServletContainerWarDevelopmentIntegrationTests(String name,
AbstractApplicationLauncher launcher) {
super(name, launcher);
}
@Test
public void metaInfResourceFromDependencyIsAvailableViaHttp() throws Exception {
ResponseEntity<String> entity = this.rest
.getForEntity("/nested-meta-inf-resource.txt", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
public void metaInfResourceFromDependencyIsAvailableViaServletContext()
throws Exception {
ResponseEntity<String> entity = this.rest
.getForEntity("/nested-meta-inf-resource.txt", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
public void webappResourcesAreAvailableViaHttp() throws Exception {
ResponseEntity<String> entity = this.rest.getForEntity("/webapp-resource.txt",
String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}

@ -16,6 +16,8 @@
package org.springframework.boot.context.embedded;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@ -38,7 +40,9 @@ public class EmbeddedServletContainerWarPackagingIntegrationTests
@Parameters(name = "{0}")
public static Object[] parameters() {
return AbstractEmbeddedServletContainerIntegrationTests.parameters("war");
return AbstractEmbeddedServletContainerIntegrationTests.parameters("war",
Arrays.asList(PackagedApplicationLauncher.class,
ExplodedApplicationLauncher.class));
}
public EmbeddedServletContainerWarPackagingIntegrationTests(String name,

@ -29,8 +29,8 @@ import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
/**
* {@link AbstractApplicationLauncher} that launches an exploded Spring Boot application
* using Spring Boot's Jar or War launcher.
* {@link AbstractApplicationLauncher} that launches a Spring Boot application using
* {@code JarLauncher} or {@code WarLauncher} and an exploded archive.
*
* @author Andy Wilkinson
*/
@ -42,6 +42,16 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
super(applicationBuilder);
}
@Override
protected File getWorkingDirectory() {
return this.exploded;
}
@Override
protected String getDescription(String packaging) {
return "exploded " + packaging;
}
@Override
protected List<String> getArguments(File archive) {
String mainClass = archive.getName().endsWith(".war")

@ -0,0 +1,152 @@
/*
* Copyright 2012-2017 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.context.embedded;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
/**
* {@link AbstractApplicationLauncher} that launches a Spring Boot application with a
* classpath similar to that used when run in an IDE.
*
* @author Andy Wilkinson
*/
class IdeApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/ide");
IdeApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
}
@Override
protected File getWorkingDirectory() {
return this.exploded;
}
@Override
protected String getDescription(String packaging) {
return "IDE run " + packaging + " project";
}
@Override
protected List<String> getArguments(File archive) {
try {
explodeArchive(archive, this.exploded);
deleteLauncherClasses();
File targetClasses = populateTargetClasses(archive);
File dependencies = populateDependencies(archive);
File resourcesProject = explodedResourcesProject(dependencies);
populateSrcMainWebapp();
List<String> classpath = new ArrayList<String>();
classpath.add(targetClasses.getAbsolutePath());
for (File dependency : dependencies.listFiles()) {
classpath.add(dependency.getAbsolutePath());
}
classpath.add(resourcesProject.getAbsolutePath());
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private File populateTargetClasses(File archive) {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
new File(this.exploded, getClassesPath(archive)).renameTo(targetClasses);
return targetClasses;
}
private File populateDependencies(File archive) {
File dependencies = new File(this.exploded, "dependencies");
dependencies.mkdirs();
List<String> libPaths = getLibPaths(archive);
for (String libPath : libPaths) {
for (File jar : new File(this.exploded, libPath).listFiles()) {
jar.renameTo(new File(dependencies, jar.getName()));
}
}
return dependencies;
}
private File explodedResourcesProject(File dependencies) throws IOException {
File resourcesProject = new File(this.exploded,
"resources-project/target/classes");
File resourcesJar = new File(dependencies, "resources-1.0.jar");
explodeArchive(resourcesJar, resourcesProject);
resourcesJar.delete();
return resourcesProject;
}
private void populateSrcMainWebapp() {
File srcMainWebapp = new File(this.exploded, "src/main/webapp");
srcMainWebapp.mkdirs();
new File(this.exploded, "webapp-resource.txt")
.renameTo(new File(srcMainWebapp, "webapp-resource.txt"));
}
private void deleteLauncherClasses() {
FileSystemUtils.deleteRecursively(new File(this.exploded, "org"));
}
private String getClassesPath(File archive) {
return archive.getName().endsWith(".jar") ? "BOOT-INF/classes"
: "WEB-INF/classes";
}
private List<String> getLibPaths(File archive) {
return archive.getName().endsWith(".jar")
? Collections.singletonList("BOOT-INF/lib")
: Arrays.asList("WEB-INF/lib", "WEB-INF/lib-provided");
}
private void explodeArchive(File archive, File destination) throws IOException {
FileSystemUtils.deleteRecursively(destination);
JarFile jarFile = new JarFile(archive);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
File extracted = new File(destination, jarEntry.getName());
if (jarEntry.isDirectory()) {
extracted.mkdirs();
}
else {
FileOutputStream extractedOutputStream = new FileOutputStream(extracted);
StreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);
extractedOutputStream.close();
}
}
jarFile.close();
}
}

@ -32,6 +32,16 @@ class PackagedApplicationLauncher extends AbstractApplicationLauncher {
super(applicationBuilder);
}
@Override
protected File getWorkingDirectory() {
return null;
}
@Override
protected String getDescription(String packaging) {
return "packaged " + packaging;
}
@Override
protected List<String> getArguments(File archive) {
return Arrays.asList("-jar", archive.getAbsolutePath());

@ -96,15 +96,23 @@ public abstract class AbstractEmbeddedServletContainerFactory
if (classLoader instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
try {
if ("file".equals(url.getProtocol())) {
File file = new File(url.getFile());
if (file.isDirectory()
&& new File(file, "META-INF/resources").isDirectory()) {
staticResourceUrls.add(url);
}
else if (isResourcesJar(file)) {
staticResourceUrls.add(url);
}
}
else {
URLConnection connection = url.openConnection();
if (connection instanceof JarURLConnection) {
JarURLConnection jarConnection = (JarURLConnection) connection;
JarFile jar = jarConnection.getJarFile();
if (jar.getName().endsWith(".jar")
&& jar.getJarEntry("META-INF/resources") != null) {
if (isResourcesJar((JarURLConnection) connection)) {
staticResourceUrls.add(url);
}
jar.close();
}
}
}
catch (IOException ex) {
@ -115,6 +123,34 @@ public abstract class AbstractEmbeddedServletContainerFactory
return staticResourceUrls;
}
private boolean isResourcesJar(JarURLConnection connection) {
try {
return isResourcesJar(connection.getJarFile());
}
catch (IOException ex) {
return false;
}
}
private boolean isResourcesJar(File file) {
try {
return isResourcesJar(new JarFile(file));
}
catch (IOException ex) {
return false;
}
}
private boolean isResourcesJar(JarFile jar) throws IOException {
try {
return jar.getName().endsWith(".jar")
&& (jar.getJarEntry("META-INF/resources") != null);
}
finally {
jar.close();
}
}
File getExplodedWarFileDocumentRoot(File codeSourceFile) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Code archive: " + codeSourceFile);

@ -414,8 +414,7 @@ public class JettyEmbeddedServletContainerFactory
root.isDirectory() ? Resource.newResource(root.getCanonicalFile())
: JarResource.newJarResource(Resource.newResource(root)));
for (URL resourceJarUrl : this.getUrlsOfJarsWithMetaInfResources()) {
Resource resource = Resource
.newResource(resourceJarUrl + "META-INF/resources");
Resource resource = createResource(resourceJarUrl);
// Jetty 9.2 and earlier do not support nested jars. See
// https://github.com/eclipse/jetty.project/issues/518
if (resource.exists() && resource.isDirectory()) {
@ -430,6 +429,16 @@ public class JettyEmbeddedServletContainerFactory
}
}
private Resource createResource(URL url) throws IOException {
if ("file".equals(url.getProtocol())) {
File file = new File(url.getFile());
if (file.isFile()) {
return Resource.newResource("jar:" + url + "!/META-INF/resources");
}
}
return Resource.newResource(url + "META-INF/resources");
}
/**
* Add Jetty's {@code DefaultServlet} to the given {@link WebAppContext}.
* @param context the jetty {@link WebAppContext}

@ -22,7 +22,6 @@ import java.net.URL;
import java.util.List;
import javax.naming.directory.DirContext;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.WebResourceRoot.ResourceSetType;
@ -57,6 +56,9 @@ abstract class TomcatResources {
}
addJar(jar);
}
else {
addDir(file, url);
}
}
}
@ -127,7 +129,7 @@ abstract class TomcatResources {
@Override
protected void addDir(String dir, URL url) {
if (getContext() instanceof ServletContext) {
if (getContext() instanceof StandardContext) {
try {
Class<?> fileDirContextClass = Class
.forName("org.apache.naming.resources.FileDirContext");

@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded.undertow;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
@ -465,11 +466,35 @@ public class UndertowEmbeddedServletContainerFactory
private ResourceManager getDocumentRootResourceManager() {
File root = getCanonicalDocumentRoot();
List<URL> metaInfResourceJarUrls = getUrlsOfJarsWithMetaInfResources();
List<URL> metaInfResourceUrls = getUrlsOfJarsWithMetaInfResources();
List<URL> resourceJarUrls = new ArrayList<URL>();
List<ResourceManager> resourceManagers = new ArrayList<ResourceManager>();
ResourceManager rootResourceManager = root.isDirectory()
? new FileResourceManager(root, 0) : new JarResourceManager(root);
return new CompositeResourceManager(rootResourceManager,
new MetaInfResourcesResourceManager(metaInfResourceJarUrls));
resourceManagers.add(rootResourceManager);
for (URL url : metaInfResourceUrls) {
if ("file".equals(url.getProtocol())) {
File file = new File(url.getFile());
if (file.isFile()) {
try {
resourceJarUrls.add(new URL("jar:" + url + "!/"));
}
catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
}
else {
resourceManagers.add(new FileResourceManager(
new File(file, "META-INF/resources"), 0));
}
}
else {
resourceJarUrls.add(url);
}
}
resourceManagers.add(new MetaInfResourcesResourceManager(resourceJarUrls));
return new CompositeResourceManager(
resourceManagers.toArray(new ResourceManager[resourceManagers.size()]));
}
/**
@ -619,14 +644,19 @@ public class UndertowEmbeddedServletContainerFactory
}
@Override
public Resource getResource(String path) throws IOException {
public Resource getResource(String path) {
for (URL url : this.metaInfResourceJarUrls) {
try {
URL resourceUrl = new URL(url + "META-INF/resources" + path);
URLConnection connection = resourceUrl.openConnection();
if (connection.getContentLength() >= 0) {
return new URLResource(resourceUrl, connection, path);
}
}
catch (IOException ex) {
// Continue
}
}
return null;
}

Loading…
Cancel
Save