Allow PropertyLauncher loader.path to be configured using manifest

Closes gh-7178
pull/7262/head
Andy Wilkinson 8 years ago
parent a638dcd51b
commit ee7141cf63

@ -200,12 +200,12 @@ the appropriate launcher:
properties (System properties, environment variables, manifest entries or
`application.properties`).
[cols="2,4"]
|===
|Key |Purpose
|`loader.path`
|Comma-separated Classpath, e.g. `lib,${HOME}/app/lib`. Earlier entries take precedence, just like a regular `-classpath` on the `javac` command line.
|Comma-separated Classpath, e.g. `lib,${HOME}/app/lib`. Earlier entries take precedence,
just like a regular `-classpath` on the `javac` command line.
|`loader.home`
|Location of additional properties file, e.g. `file:///opt/app`
@ -227,25 +227,52 @@ properties (System properties, environment variables, manifest entries or
|`loader.system`
|Boolean flag to indicate that all properties should be added to System properties
(defaults to `false`)
|===
Manifest entry keys are formed by capitalizing initial letters of words and changing the
separator to "`-`" from "`.`" (e.g. `Loader-Path`). The exception is `loader.main` which
is looked up as `Start-Class` in the manifest for compatibility with `JarLauncher`).
When specified as environment variables or manifest entries, the following names should
be used:
|===
|Key | Manifest entry | Environment variable
|`loader.path`
|`Loader-Path`
|`LOADER_PATH`
|`loader.home`
|
|`LOADER_HOME`
|`loader.args`
|`Loader-Args`
|`LOADER_ARGS`
|`loader.main`
|`Start-Class`
|`LOADER_MAIN`
|`loader.config.location`
|
|`LOADER_CONFIG_LOCATION`
|`loader.system`
|
|`LOADER_SYSTEM`
|===
TIP: Build plugins automatically move the `Main-Class` attribute to `Start-Class` when
the fat jar is built. If you are using that, specify the name of the class to launch using
the `Main-Class` attribute and leave out `Start-Class`.
Environment variables can be capitalized with underscore separators instead of periods.
* `loader.home` is the directory location of an additional properties file (overriding
the default) as long as `loader.config.location` is not specified.
the default) as long as `loader.config.location` is not specified.
* `loader.path` can contain directories (scanned recursively for jar and zip files),
archive paths, or wildcard patterns (for the default JVM behavior).
* `loader.path` (if empty) defaults to `lib` (meaning a local directory or a nested one if
running from an archive). Because of this `PropertiesLauncher` behaves the same as
`JarLauncher` when no additional configuration is provided.
* `loader.path` (if empty) defaults to `BOOT-INF/lib` (meaning a local directory or a
nested one if running from an archive). Because of this `PropertiesLauncher` behaves the
same as `JarLauncher` when no additional configuration is provided.
* Placeholder replacement is done from System and environment variables plus the
properties file itself on all values before use.

@ -132,7 +132,7 @@ public class PropertiesLauncher extends Launcher {
public PropertiesLauncher() {
try {
this.home = getHomeDirectory();
initializeProperties(this.home);
initializeProperties();
initializePaths();
this.parent = createArchive();
}
@ -146,7 +146,7 @@ public class PropertiesLauncher extends Launcher {
.resolvePlaceholders(System.getProperty(HOME, "${user.dir}")));
}
private void initializeProperties(File home) throws Exception, IOException {
private void initializeProperties() throws Exception, IOException {
String config = "classpath:BOOT-INF/classes/"
+ SystemPropertyUtils.resolvePlaceholders(
SystemPropertyUtils.getProperty(CONFIG_NAME, "application"))
@ -273,14 +273,10 @@ public class PropertiesLauncher extends Launcher {
}
}
private void initializePaths() throws IOException {
String path = SystemPropertyUtils.getProperty(PATH);
if (path == null) {
path = this.properties.getProperty(PATH);
}
private void initializePaths() throws Exception {
String path = getProperty(PATH);
if (path != null) {
this.paths = parsePathsProperty(
SystemPropertyUtils.resolvePlaceholders(path));
this.paths = parsePathsProperty(path);
}
log("Nested archive paths: " + this.paths);
}

@ -17,16 +17,21 @@
package org.springframework.boot.loader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.loader.archive.Archive;
@ -45,6 +50,9 @@ public class PropertiesLauncherTests {
@Rule
public InternalOutputCapture output = new InternalOutputCapture();
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void setup() throws IOException {
MockitoAnnotations.initMocks(this);
@ -207,6 +215,23 @@ public class PropertiesLauncherTests {
.isEqualTo("[foo, bar]");
}
@SuppressWarnings("unchecked")
@Test
public void testLoadPathCustomizedUsingManifest() throws Exception {
System.setProperty("loader.home",
this.temporaryFolder.getRoot().getAbsolutePath());
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
manifest.getMainAttributes().putValue("Loader-Path", "/foo.jar, /bar");
File manifestFile = new File(this.temporaryFolder.getRoot(),
"META-INF/MANIFEST.MF");
manifestFile.getParentFile().mkdirs();
manifest.write(new FileOutputStream(manifestFile));
PropertiesLauncher launcher = new PropertiesLauncher();
assertThat((List<String>) ReflectionTestUtils.getField(launcher, "paths"))
.containsExactly("/foo.jar", "/bar/");
}
private void waitFor(String value) throws Exception {
int count = 0;
boolean timeout = false;

Loading…
Cancel
Save