Support for wildcard paths in PropertiesLauncher
This commit is contained in:
@@ -11,7 +11,7 @@ opposed to explicitly on the classpath). In the case of the
|
||||
those locations if you want more. The `PropertiesLauncher` looks in
|
||||
`lib/` by default, but you can add additional locations by setting an
|
||||
environment variable `LOADER_PATH`or `loader.path` in
|
||||
`application.properties` (colon-separated list of directories).
|
||||
`application.properties` (colon-separated list of directories or archives).
|
||||
|
||||
> **Note:** The quickest way to build a compatible archive is to use the
|
||||
> [spring-boot-maven-plugin](../spring-boot-maven-plugin) or
|
||||
|
||||
@@ -343,6 +343,12 @@ public class PropertiesLauncher extends Launcher {
|
||||
Archive archive = new ExplodedArchive(file);
|
||||
lib.add(archive);
|
||||
}
|
||||
Archive archive = getArchive(file);
|
||||
if (archive != null) {
|
||||
this.logger.info("Adding classpath entries from nested " + archive.getUrl()
|
||||
+ root);
|
||||
lib.add(archive);
|
||||
}
|
||||
Archive nested = getNestedArchive(root);
|
||||
if (nested != null) {
|
||||
this.logger.info("Adding classpath entries from nested " + nested.getUrl()
|
||||
@@ -352,6 +358,14 @@ public class PropertiesLauncher extends Launcher {
|
||||
return lib;
|
||||
}
|
||||
|
||||
private Archive getArchive(File file) throws IOException {
|
||||
String name = file.getName().toLowerCase();
|
||||
if (name.endsWith(".jar") || name.endsWith(".zip")) {
|
||||
return new JarFileArchive(file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Archive getNestedArchive(final String root) throws Exception {
|
||||
Archive parent = createArchive();
|
||||
if (root.startsWith("/") || parent.getUrl().equals(this.home.toURI().toURL())) {
|
||||
@@ -401,9 +415,17 @@ public class PropertiesLauncher extends Launcher {
|
||||
|
||||
private String cleanupPath(String path) {
|
||||
path = path.trim();
|
||||
// Always a directory
|
||||
if (!path.endsWith("/")) {
|
||||
path = path + "/";
|
||||
if (path.toLowerCase().endsWith(".jar") || path.toLowerCase().endsWith(".zip")) {
|
||||
return path;
|
||||
}
|
||||
if (path.endsWith("/*")) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
else {
|
||||
// It's a directory
|
||||
if (!path.endsWith("/")) {
|
||||
path = path + "/";
|
||||
}
|
||||
}
|
||||
// No need for current dir path
|
||||
if (path.startsWith("./")) {
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* Capture output from System.out and System.err.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class OutputCapture implements TestRule {
|
||||
|
||||
private CaptureOutputStream captureOut;
|
||||
|
||||
private CaptureOutputStream captureErr;
|
||||
|
||||
private ByteArrayOutputStream copy;
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
captureOutput();
|
||||
try {
|
||||
base.evaluate();
|
||||
}
|
||||
finally {
|
||||
releaseOutput();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void captureOutput() {
|
||||
this.copy = new ByteArrayOutputStream();
|
||||
this.captureOut = new CaptureOutputStream(System.out, this.copy);
|
||||
this.captureErr = new CaptureOutputStream(System.err, this.copy);
|
||||
System.setOut(new PrintStream(this.captureOut));
|
||||
System.setErr(new PrintStream(this.captureErr));
|
||||
}
|
||||
|
||||
protected void releaseOutput() {
|
||||
System.setOut(this.captureOut.getOriginal());
|
||||
System.setErr(this.captureErr.getOriginal());
|
||||
this.copy = null;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
try {
|
||||
this.captureOut.flush();
|
||||
this.captureErr.flush();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
flush();
|
||||
return this.copy.toString();
|
||||
}
|
||||
|
||||
private static class CaptureOutputStream extends OutputStream {
|
||||
|
||||
private final PrintStream original;
|
||||
|
||||
private final OutputStream copy;
|
||||
|
||||
public CaptureOutputStream(PrintStream original, OutputStream copy) {
|
||||
this.original = original;
|
||||
this.copy = copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
this.copy.write(b);
|
||||
this.original.write(b);
|
||||
this.original.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
this.copy.write(b, off, len);
|
||||
this.original.write(b, off, len);
|
||||
}
|
||||
|
||||
public PrintStream getOriginal() {
|
||||
return this.original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
this.copy.flush();
|
||||
this.original.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,10 +21,12 @@ import java.io.IOException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertiesLauncher}.
|
||||
@@ -33,6 +35,9 @@ import static org.junit.Assert.assertEquals;
|
||||
*/
|
||||
public class PropertiesLauncherTests {
|
||||
|
||||
@Rule
|
||||
public OutputCapture output = new OutputCapture();
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
System.setProperty("loader.home",
|
||||
@@ -65,13 +70,34 @@ public class PropertiesLauncherTests {
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedConfigName() throws Exception {
|
||||
|
||||
System.setProperty("loader.config.name", "foo");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertEquals("my.Application", launcher.getMainClass());
|
||||
assertEquals("[etc/]", ReflectionTestUtils.getField(launcher, "paths").toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/*");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertEquals("[jars/]", ReflectionTestUtils.getField(launcher, "paths")
|
||||
.toString());
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedJarPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/app.jar");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertEquals("[jars/app.jar]", ReflectionTestUtils.getField(launcher, "paths")
|
||||
.toString());
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedConfigPathWins() throws Exception {
|
||||
|
||||
@@ -95,4 +121,15 @@ public class PropertiesLauncherTests {
|
||||
assertEquals("demo.Application", System.getProperty("loader.main"));
|
||||
}
|
||||
|
||||
private void waitFor(String value) throws Exception {
|
||||
int count = 0;
|
||||
boolean timeout = false;
|
||||
while (!timeout && count < 100) {
|
||||
count++;
|
||||
Thread.sleep(50L);
|
||||
timeout = this.output.toString().contains(value);
|
||||
}
|
||||
assertTrue("Timed out waiting for (" + value + ")", timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user