Extend PropertiesLauncher to load nested archives
PropertiesLauncher can now be used to run an executable jar, and by default it will pick up nested archives in lib/ (where the Boot tools puts them). User can provide loader.path (colon-separated) to change the nested path. [#58837492] [bs-330] Add tooling for PropertiesLauncher
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Tue Oct 15 09:46:33 EDT 2013
|
||||
git.commit.id.abbrev=be12635
|
||||
#Tue Oct 15 11:07:38 EDT 2013
|
||||
git.commit.id.abbrev=d3fa609
|
||||
git.commit.user.email=dsyer@gopivotal.com
|
||||
git.commit.message.full=Ensure env vars are consulted for PATH\n
|
||||
git.commit.id=be1263500df0c363ad45c0ccf387e4c06e6f5c7d
|
||||
git.commit.message.short=Ensure env vars are consulted for PATH
|
||||
git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n
|
||||
git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312
|
||||
git.commit.message.short=Extend PropertiesLauncher to load nested archives
|
||||
git.commit.user.name=Dave Syer
|
||||
git.build.user.name=Dave Syer
|
||||
git.build.user.email=dsyer@gopivotal.com
|
||||
git.branch=master
|
||||
git.commit.time=2013-10-14T16\:07\:50-0400
|
||||
git.build.time=2013-10-15T09\:46\:33-0400
|
||||
git.commit.time=2013-10-15T10\:51\:03-0400
|
||||
git.build.time=2013-10-15T11\:07\:38-0400
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Tue Oct 15 09:46:12 EDT 2013
|
||||
git.commit.id.abbrev=be12635
|
||||
#Tue Oct 15 11:07:33 EDT 2013
|
||||
git.commit.id.abbrev=d3fa609
|
||||
git.commit.user.email=dsyer@gopivotal.com
|
||||
git.commit.message.full=Ensure env vars are consulted for PATH\n
|
||||
git.commit.id=be1263500df0c363ad45c0ccf387e4c06e6f5c7d
|
||||
git.commit.message.short=Ensure env vars are consulted for PATH
|
||||
git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n
|
||||
git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312
|
||||
git.commit.message.short=Extend PropertiesLauncher to load nested archives
|
||||
git.commit.user.name=Dave Syer
|
||||
git.build.user.name=Dave Syer
|
||||
git.build.user.email=dsyer@gopivotal.com
|
||||
git.branch=master
|
||||
git.commit.time=2013-10-14T16\:07\:50-0400
|
||||
git.build.time=2013-10-15T09\:46\:12-0400
|
||||
git.commit.time=2013-10-15T10\:51\:03-0400
|
||||
git.build.time=2013-10-15T11\:07\:33-0400
|
||||
|
||||
@@ -21,10 +21,13 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -36,6 +39,7 @@ import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
import org.springframework.boot.loader.archive.Archive.EntryFilter;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.FilteredArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.boot.loader.util.SystemPropertyUtils;
|
||||
|
||||
@@ -286,14 +290,30 @@ public class PropertiesLauncher extends Launcher {
|
||||
|
||||
@Override
|
||||
protected String getMainClass() throws Exception {
|
||||
if (System.getProperty(MAIN) != null) {
|
||||
return SystemPropertyUtils.resolvePlaceholders(System.getProperty(MAIN));
|
||||
String property = SystemPropertyUtils.getProperty(MAIN);
|
||||
if (property != null) {
|
||||
String mainClass = SystemPropertyUtils.resolvePlaceholders(property);
|
||||
this.logger.info("Main class from environment: " + mainClass);
|
||||
return mainClass;
|
||||
}
|
||||
if (this.properties.containsKey(MAIN)) {
|
||||
return SystemPropertyUtils.resolvePlaceholders(this.properties
|
||||
String mainClass = SystemPropertyUtils.resolvePlaceholders(this.properties
|
||||
.getProperty(MAIN));
|
||||
this.logger.info("Main class from properties: " + mainClass);
|
||||
return mainClass;
|
||||
}
|
||||
try {
|
||||
// Prefer home dir for MANIFEST if there is one
|
||||
String mainClass = new ExplodedArchive(this.home).getMainClass();
|
||||
this.logger.info("Main class from home directory manifest: " + mainClass);
|
||||
return mainClass;
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
// Otherwise try the parent archive
|
||||
String mainClass = createArchive().getMainClass();
|
||||
this.logger.info("Main class from archive manifest: " + mainClass);
|
||||
return mainClass;
|
||||
}
|
||||
return new ExplodedArchive(this.home).getMainClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -302,14 +322,7 @@ public class PropertiesLauncher extends Launcher {
|
||||
for (String path : this.paths) {
|
||||
for (Archive archive : getClassPathArchives(path)) {
|
||||
List<Archive> nested = new ArrayList<Archive>(
|
||||
archive.getNestedArchives(new EntryFilter() {
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
return entry.isDirectory()
|
||||
|| entry.getName().endsWith(".jar")
|
||||
|| entry.getName().endsWith(".zip");
|
||||
}
|
||||
}));
|
||||
archive.getNestedArchives(new ArchiveEntryFilter()));
|
||||
nested.add(0, archive);
|
||||
lib.addAll(nested);
|
||||
}
|
||||
@@ -318,7 +331,7 @@ public class PropertiesLauncher extends Launcher {
|
||||
return lib;
|
||||
}
|
||||
|
||||
private List<Archive> getClassPathArchives(String path) {
|
||||
private List<Archive> getClassPathArchives(String path) throws Exception {
|
||||
String root = cleanupPath(stripFileUrlPrefix(path));
|
||||
List<Archive> lib = new ArrayList<Archive>();
|
||||
File file = new File(root);
|
||||
@@ -330,9 +343,46 @@ public class PropertiesLauncher extends Launcher {
|
||||
Archive archive = new ExplodedArchive(file);
|
||||
lib.add(archive);
|
||||
}
|
||||
Archive nested = getNestedArchive(root);
|
||||
if (nested != null) {
|
||||
this.logger.info("Adding classpath entries from nested " + nested.getUrl()
|
||||
+ root);
|
||||
lib.add(nested);
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
private Archive getNestedArchive(final String root) throws Exception {
|
||||
Archive parent = createArchive();
|
||||
if (root.startsWith("/") || parent.getUrl().equals(this.home.toURI().toURL())) {
|
||||
// If home dir is same as parent archive, no need to add it twice.
|
||||
return null;
|
||||
}
|
||||
EntryFilter filter = new PrefixMatchingArchiveFilter(root);
|
||||
if (parent.getNestedArchives(filter).isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// If there are more archives nested in this subdirectory (root) then create a new
|
||||
// virtual archive for them, and have it added to the classpath
|
||||
return new FilteredArchive(parent, filter);
|
||||
}
|
||||
|
||||
private Archive createArchive() throws Exception {
|
||||
ProtectionDomain protectionDomain = getClass().getProtectionDomain();
|
||||
CodeSource codeSource = protectionDomain.getCodeSource();
|
||||
URI location = (codeSource == null ? null : codeSource.getLocation().toURI());
|
||||
String path = (location == null ? null : location.getPath());
|
||||
if (path == null) {
|
||||
throw new IllegalStateException("Unable to determine code source archive");
|
||||
}
|
||||
File root = new File(path);
|
||||
if (!root.exists()) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to determine code source archive from " + root);
|
||||
}
|
||||
return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
|
||||
}
|
||||
|
||||
private void addParentClassLoaderEntries(List<Archive> lib) throws IOException,
|
||||
URISyntaxException {
|
||||
ClassLoader parentClassLoader = getClass().getClassLoader();
|
||||
@@ -366,4 +416,38 @@ public class PropertiesLauncher extends Launcher {
|
||||
new PropertiesLauncher().launch(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience class for finding nested archives (archive entries that can be
|
||||
* classpath entries).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
private static final class ArchiveEntryFilter implements EntryFilter {
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
return entry.isDirectory() || entry.getName().endsWith(".jar")
|
||||
|| entry.getName().endsWith(".zip");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience class for finding nested archives that have a prefix in their file path
|
||||
* (e.g. "lib/").
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
private static final class PrefixMatchingArchiveFilter implements EntryFilter {
|
||||
private final String prefix;
|
||||
private final ArchiveEntryFilter filter = new ArchiveEntryFilter();
|
||||
|
||||
private PrefixMatchingArchiveFilter(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
return entry.getName().startsWith(this.prefix) && this.filter.matches(entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.archive;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class FilteredArchive extends Archive {
|
||||
|
||||
private Archive parent;
|
||||
private EntryFilter filter;
|
||||
|
||||
public FilteredArchive(Archive parent, EntryFilter filter) {
|
||||
this.parent = parent;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
return this.parent.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMainClass() throws Exception {
|
||||
return this.parent.getMainClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
return this.parent.getManifest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Entry> getEntries() {
|
||||
List<Entry> nested = new ArrayList<Entry>();
|
||||
for (Entry entry : this.parent.getEntries()) {
|
||||
if (this.filter.matches(entry)) {
|
||||
nested.add(entry);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(nested);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Archive> getNestedArchives(final EntryFilter filter) throws IOException {
|
||||
return this.parent.getNestedArchives(new EntryFilter() {
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
return FilteredArchive.this.filter.matches(entry)
|
||||
&& filter.matches(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Archive getFilteredArchive(final EntryRenameFilter filter) throws IOException {
|
||||
return this.parent.getFilteredArchive(new EntryRenameFilter() {
|
||||
@Override
|
||||
public String apply(String entryName, Entry entry) {
|
||||
return FilteredArchive.this.filter.matches(entry) ? filter.apply(
|
||||
entryName, entry) : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Tue Oct 15 09:45:47 EDT 2013
|
||||
git.commit.id.abbrev=be12635
|
||||
#Tue Oct 15 11:07:32 EDT 2013
|
||||
git.commit.id.abbrev=d3fa609
|
||||
git.commit.user.email=dsyer@gopivotal.com
|
||||
git.commit.message.full=Ensure env vars are consulted for PATH\n
|
||||
git.commit.id=be1263500df0c363ad45c0ccf387e4c06e6f5c7d
|
||||
git.commit.message.short=Ensure env vars are consulted for PATH
|
||||
git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n
|
||||
git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312
|
||||
git.commit.message.short=Extend PropertiesLauncher to load nested archives
|
||||
git.commit.user.name=Dave Syer
|
||||
git.build.user.name=Dave Syer
|
||||
git.build.user.email=dsyer@gopivotal.com
|
||||
git.branch=master
|
||||
git.commit.time=2013-10-14T16\:07\:50-0400
|
||||
git.build.time=2013-10-15T09\:45\:47-0400
|
||||
git.commit.time=2013-10-15T10\:51\:03-0400
|
||||
git.build.time=2013-10-15T11\:07\:32-0400
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Tue Oct 15 09:46:13 EDT 2013
|
||||
git.commit.id.abbrev=be12635
|
||||
#Tue Oct 15 11:07:34 EDT 2013
|
||||
git.commit.id.abbrev=d3fa609
|
||||
git.commit.user.email=dsyer@gopivotal.com
|
||||
git.commit.message.full=Ensure env vars are consulted for PATH\n
|
||||
git.commit.id=be1263500df0c363ad45c0ccf387e4c06e6f5c7d
|
||||
git.commit.message.short=Ensure env vars are consulted for PATH
|
||||
git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n
|
||||
git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312
|
||||
git.commit.message.short=Extend PropertiesLauncher to load nested archives
|
||||
git.commit.user.name=Dave Syer
|
||||
git.build.user.name=Dave Syer
|
||||
git.build.user.email=dsyer@gopivotal.com
|
||||
git.branch=master
|
||||
git.commit.time=2013-10-14T16\:07\:50-0400
|
||||
git.build.time=2013-10-15T09\:46\:13-0400
|
||||
git.commit.time=2013-10-15T10\:51\:03-0400
|
||||
git.build.time=2013-10-15T11\:07\:34-0400
|
||||
|
||||
Reference in New Issue
Block a user