Further re-organization of launcher code
This commit is contained in:
parent
0e0eb7d3fa
commit
15bc25dc29
|
|
@ -13,14 +13,15 @@
|
||||||
<main.basedir>${basedir}/../..</main.basedir>
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- TODO: maybe put these in the parent? -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>jcl-over-slf4j</artifactId>
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 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.File;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.security.CodeSource;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for launchers that can start an application with a fully configured
|
|
||||||
* classpath.
|
|
||||||
*
|
|
||||||
* @author Phillip Webb
|
|
||||||
* @author Dave Syer
|
|
||||||
*/
|
|
||||||
public abstract class AbstractLauncher implements ArchiveFilter {
|
|
||||||
|
|
||||||
private Logger logger = Logger.getLogger(AbstractLauncher.class.getName());
|
|
||||||
|
|
||||||
private LaunchHelper helper = new LaunchHelper();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the application. This method is the initial entry point that should be
|
|
||||||
* called by a subclass {@code public static void main(String[] args)} method.
|
|
||||||
* @param args the incoming arguments
|
|
||||||
*/
|
|
||||||
public void launch(String[] args) {
|
|
||||||
try {
|
|
||||||
launch(args, getClass().getProtectionDomain());
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the application given the protection domain.
|
|
||||||
* @param args the incoming arguments
|
|
||||||
* @param protectionDomain the protection domain
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected void launch(String[] args, ProtectionDomain protectionDomain)
|
|
||||||
throws Exception {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
Archive archive = (root.isDirectory() ? new ExplodedArchive(root)
|
|
||||||
: new JarFileArchive(root));
|
|
||||||
launch(args, archive);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the application given the archive file
|
|
||||||
* @param args the incoming arguments
|
|
||||||
* @param archive the underlying (zip/war/jar) archive
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected void launch(String[] args, Archive archive) throws Exception {
|
|
||||||
List<Archive> lib = new ArrayList<Archive>();
|
|
||||||
lib.addAll(this.helper.findNestedArchives(archive, this));
|
|
||||||
this.logger.fine("Added " + lib.size() + " entries");
|
|
||||||
postProcessLib(archive, lib);
|
|
||||||
String mainClass = this.helper.getMainClass(archive);
|
|
||||||
this.helper.launch(args, mainClass, lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to post-process lib entries before they are used. Implementations can add
|
|
||||||
* and remove entries.
|
|
||||||
* @param archive the archive
|
|
||||||
* @param lib the existing lib
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected void postProcessLib(Archive archive, List<Archive> lib) throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* 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.File;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
|
||||||
|
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.JarFileArchive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for executable archive {@link Launcher}s.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||||
|
|
||||||
|
private final Archive archive;
|
||||||
|
|
||||||
|
public ExecutableArchiveLauncher() {
|
||||||
|
try {
|
||||||
|
this.archive = createArchive();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Archive getArchive() {
|
||||||
|
return this.archive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMainClass() throws Exception {
|
||||||
|
return this.archive.getMainClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Archive> getClassPathArchives() throws Exception {
|
||||||
|
List<Archive> archives = new ArrayList<Archive>(
|
||||||
|
this.archive.getNestedArchives(new EntryFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(Entry entry) {
|
||||||
|
return isNestedArchive(entry);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
postProcessClassPathArchives(archives);
|
||||||
|
return archives;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the specified {@link JarEntry} is a nested item that should be added
|
||||||
|
* to the classpath. The method is called once for each entry.
|
||||||
|
* @param entry the jar entry
|
||||||
|
* @return {@code true} if the entry is a nested item (jar or folder)
|
||||||
|
*/
|
||||||
|
protected abstract boolean isNestedArchive(Archive.Entry entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to post-process archive entries before they are used. Implementations can
|
||||||
|
* add and remove entries.
|
||||||
|
* @param archives the archives
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,26 +18,27 @@ package org.springframework.boot.loader;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.archive.Archive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AbstractLauncher} for JAR based archives. This launcher assumes that dependency
|
* {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are
|
||||||
* jars are included inside a {@code /lib} directory.
|
* included inside a {@code /lib} directory.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
public class JarLauncher extends AbstractLauncher {
|
public class JarLauncher extends ExecutableArchiveLauncher {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new JarLauncher().launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isArchive(Archive.Entry entry) {
|
protected boolean isNestedArchive(Archive.Entry entry) {
|
||||||
return !entry.isDirectory() && entry.getName().startsWith("lib/");
|
return !entry.isDirectory() && entry.getName().startsWith("lib/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void postProcessLib(Archive archive, List<Archive> lib) throws Exception {
|
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
|
||||||
lib.add(0, archive);
|
archives.add(0, getArchive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new JarLauncher().launch(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import java.security.PrivilegedExceptionAction;
|
||||||
import org.springframework.boot.loader.jar.RandomAccessJarFile;
|
import org.springframework.boot.loader.jar.RandomAccessJarFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ClassLoader} used by the {@link AbstractLauncher}.
|
* {@link ClassLoader} used by the {@link Launcher}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2013 the original author or authors.
|
* Copyright 2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -22,79 +22,64 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.archive.Archive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common convenience methods shared by launcher implementations.
|
* Base class for launchers that can start an application with a fully configured
|
||||||
|
* classpath backed by one or more {@link Archive}s.
|
||||||
*
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public class LaunchHelper {
|
public abstract class Launcher {
|
||||||
|
|
||||||
private Logger logger = Logger.getLogger(LaunchHelper.class.getName());
|
protected Logger logger = Logger.getLogger(Launcher.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main runner class. This must be loaded by the created ClassLoader so cannot be
|
* The main runner class. This must be loaded by the created ClassLoader so cannot be
|
||||||
* directly referenced.
|
* directly referenced.
|
||||||
*/
|
*/
|
||||||
private static final String RUNNER_CLASS = AbstractLauncher.class.getPackage()
|
private static final String RUNNER_CLASS = Launcher.class.getPackage().getName()
|
||||||
.getName() + ".MainMethodRunner";
|
+ ".MainMethodRunner";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Launch the application. This method is the initial entry point that should be
|
||||||
|
* called by a subclass {@code public static void main(String[] args)} method.
|
||||||
* @param args the incoming arguments
|
* @param args the incoming arguments
|
||||||
* @param mainClass the main class
|
|
||||||
* @param lib a collection of archives (zip/jar/war or directory)
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public void launch(String[] args, String mainClass, List<Archive> lib)
|
protected void launch(String[] args) {
|
||||||
throws Exception {
|
try {
|
||||||
ClassLoader classLoader = createClassLoader(lib);
|
ClassLoader classLoader = createClassLoader(getClassPathArchives());
|
||||||
launch(args, mainClass, classLoader);
|
launch(args, getMainClass(), classLoader);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param archive the archive to search
|
* Create a classloader for the specified archives.
|
||||||
* @return an accumulation of nested archives
|
* @param archives the archives
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public List<Archive> findNestedArchives(Archive archive, ArchiveFilter filter)
|
|
||||||
throws Exception {
|
|
||||||
List<Archive> lib = new ArrayList<Archive>();
|
|
||||||
for (Archive.Entry entry : archive.getEntries()) {
|
|
||||||
if (filter.isArchive(entry)) {
|
|
||||||
this.logger.fine("Adding: " + entry.getName());
|
|
||||||
lib.add(archive.getNestedArchive(entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the main class that should be used to launch the application. By default
|
|
||||||
* this method uses a {@code Start-Class} manifest entry.
|
|
||||||
* @param archive the archive
|
|
||||||
* @return the main class
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public String getMainClass(Archive archive) throws Exception {
|
|
||||||
String mainClass = archive.getManifest().getMainAttributes()
|
|
||||||
.getValue("Start-Class");
|
|
||||||
if (mainClass == null) {
|
|
||||||
throw new IllegalStateException("No 'Start-Class' manifest entry specified");
|
|
||||||
}
|
|
||||||
return mainClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a classloader for the specified lib.
|
|
||||||
* @param lib the lib
|
|
||||||
* @return the classloader
|
* @return the classloader
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected ClassLoader createClassLoader(List<Archive> lib) throws Exception {
|
protected ClassLoader createClassLoader(List<Archive> archives) throws Exception {
|
||||||
URL[] urls = new URL[lib.size()];
|
List<URL> urls = new ArrayList<URL>(archives.size());
|
||||||
for (int i = 0; i < urls.length; i++) {
|
for (Archive archive : archives) {
|
||||||
urls[i] = lib.get(i).getUrl();
|
urls.add(archive.getUrl());
|
||||||
}
|
}
|
||||||
return createClassLoader(urls);
|
return createClassLoader(urls.toArray(new URL[urls.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a classloader for the specified URLs
|
||||||
|
* @param urls the URLs
|
||||||
|
* @return the classloader
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected ClassLoader createClassLoader(URL[] urls) throws Exception {
|
||||||
|
return new LaunchedURLClassLoader(urls, getClass().getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -113,16 +98,6 @@ public class LaunchHelper {
|
||||||
runnerThread.start();
|
runnerThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a classloader for the specified URLs
|
|
||||||
* @param urls the URLs
|
|
||||||
* @return the classloader
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected ClassLoader createClassLoader(URL[] urls) throws Exception {
|
|
||||||
return new LaunchedURLClassLoader(urls, getClass().getClassLoader());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the {@code MainMethodRunner} used to launch the application.
|
* Create the {@code MainMethodRunner} used to launch the application.
|
||||||
* @param mainClass the main class
|
* @param mainClass the main class
|
||||||
|
|
@ -139,4 +114,17 @@ public class LaunchHelper {
|
||||||
return (Runnable) constructor.newInstance(mainClass, args);
|
return (Runnable) constructor.newInstance(mainClass, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the main class that should be launched.
|
||||||
|
* @return the name of the main class
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected abstract String getMainClass() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the archives that will be used to construct the class path.
|
||||||
|
* @return the class path archives
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected abstract List<Archive> getClassPathArchives() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
@ -19,8 +19,8 @@ package org.springframework.boot.loader;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class that used by {@link AbstractLauncher}s to call a main method. This class allows
|
* Utility class that used by {@link Launcher}s to call a main method. This class allows
|
||||||
* methods to be executed within a thread configured with a specific context classloader.
|
* methods to be executed within a thread configured with a specific context class loader.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,15 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
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.util.SystemPropertyUtils;
|
import org.springframework.boot.loader.util.SystemPropertyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AbstractLauncher} for archives with user-configured classpath and main class via
|
* {@link Launcher} for archives with user-configured classpath and main class via a
|
||||||
* a properties file. This model is often more flexible and more amenable to creating
|
* properties file. This model is often more flexible and more amenable to creating
|
||||||
* well-behaved OS-level services than a model based on executable jars.
|
* well-behaved OS-level services than a model based on executable jars.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
|
@ -60,9 +64,9 @@ import org.springframework.boot.loader.util.SystemPropertyUtils;
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public class PropertiesLauncher implements ArchiveFilter {
|
public class PropertiesLauncher extends Launcher {
|
||||||
|
|
||||||
private Logger logger = Logger.getLogger(AbstractLauncher.class.getName());
|
private Logger logger = Logger.getLogger(Launcher.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties key for main class
|
* Properties key for main class
|
||||||
|
|
@ -105,92 +109,28 @@ public class PropertiesLauncher implements ArchiveFilter {
|
||||||
|
|
||||||
private static final List<String> DEFAULT_PATHS = Arrays.asList("lib/");
|
private static final List<String> DEFAULT_PATHS = Arrays.asList("lib/");
|
||||||
|
|
||||||
|
private final File home;
|
||||||
|
|
||||||
private List<String> paths = new ArrayList<String>(DEFAULT_PATHS);
|
private List<String> paths = new ArrayList<String>(DEFAULT_PATHS);
|
||||||
|
|
||||||
private Properties properties = new Properties();
|
private Properties properties = new Properties();
|
||||||
|
|
||||||
private LaunchHelper helper = new LaunchHelper();
|
public PropertiesLauncher() {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new PropertiesLauncher().launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the application. This method is the initial entry point that should be
|
|
||||||
* called by a subclass {@code public static void main(String[] args)} method.
|
|
||||||
* @param args the incoming arguments
|
|
||||||
*/
|
|
||||||
public void launch(String[] args) {
|
|
||||||
try {
|
try {
|
||||||
File home = getHomeDirectory();
|
this.home = getHomeDirectory();
|
||||||
initialize(home);
|
initializeProperties(this.home);
|
||||||
this.helper.launch(args, getMainClass(home), getLibrary(home, this.paths));
|
initializePaths();
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
throw new IllegalStateException(ex);
|
||||||
System.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isArchive(Archive.Entry entry) {
|
|
||||||
return entry.isDirectory() || isArchive(entry.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected File getHomeDirectory() {
|
protected File getHomeDirectory() {
|
||||||
return new File(SystemPropertyUtils.resolvePlaceholders(System.getProperty(HOME,
|
return new File(SystemPropertyUtils.resolvePlaceholders(System.getProperty(HOME,
|
||||||
"${user.dir}")));
|
"${user.dir}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getMainClass(File home) throws Exception {
|
|
||||||
if (System.getProperty(MAIN) != null) {
|
|
||||||
return SystemPropertyUtils.resolvePlaceholders(System.getProperty(MAIN));
|
|
||||||
}
|
|
||||||
if (this.properties.containsKey(MAIN)) {
|
|
||||||
return SystemPropertyUtils.resolvePlaceholders(this.properties
|
|
||||||
.getProperty(MAIN));
|
|
||||||
}
|
|
||||||
return this.helper.getMainClass(new ExplodedArchive(home));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void initialize(File home) throws Exception {
|
|
||||||
initializeProperties(home);
|
|
||||||
initializePaths();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isArchive(String name) {
|
|
||||||
return name.endsWith(".jar") || name.endsWith(".zip");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the configured paths and look for nested archives.
|
|
||||||
*
|
|
||||||
* @param home the home directory for this launch
|
|
||||||
* @param paths the directory roots for classpath entries
|
|
||||||
* @return a library of archives that can be used as a classpath
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private List<Archive> getLibrary(File home, List<String> paths) throws Exception {
|
|
||||||
List<Archive> lib = new ArrayList<Archive>();
|
|
||||||
for (String path : paths) {
|
|
||||||
String root = cleanupPath(stripFileUrlPrefix(path));
|
|
||||||
File file = new File(root);
|
|
||||||
if (!root.startsWith("/")) {
|
|
||||||
file = new File(home, root);
|
|
||||||
}
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
this.logger.info("Adding classpath entries from " + path);
|
|
||||||
Archive archive = new ExplodedArchive(file);
|
|
||||||
lib.addAll(this.helper.findNestedArchives(archive, this));
|
|
||||||
lib.add(0, archive);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.logger.info("No directory found at " + path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeProperties(File home) throws Exception, IOException {
|
private void initializeProperties(File home) throws Exception, IOException {
|
||||||
String config = SystemPropertyUtils.resolvePlaceholders(System.getProperty(
|
String config = SystemPropertyUtils.resolvePlaceholders(System.getProperty(
|
||||||
CONFIG_NAME, "application")) + ".properties";
|
CONFIG_NAME, "application")) + ".properties";
|
||||||
|
|
@ -346,6 +286,46 @@ public class PropertiesLauncher implements ArchiveFilter {
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMainClass() throws Exception {
|
||||||
|
if (System.getProperty(MAIN) != null) {
|
||||||
|
return SystemPropertyUtils.resolvePlaceholders(System.getProperty(MAIN));
|
||||||
|
}
|
||||||
|
if (this.properties.containsKey(MAIN)) {
|
||||||
|
return SystemPropertyUtils.resolvePlaceholders(this.properties
|
||||||
|
.getProperty(MAIN));
|
||||||
|
}
|
||||||
|
return new ExplodedArchive(this.home).getMainClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Archive> getClassPathArchives() throws Exception {
|
||||||
|
List<Archive> lib = new ArrayList<Archive>();
|
||||||
|
for (String path : this.paths) {
|
||||||
|
String root = cleanupPath(stripFileUrlPrefix(path));
|
||||||
|
File file = new File(root);
|
||||||
|
if (!root.startsWith("/")) {
|
||||||
|
file = new File(this.home, root);
|
||||||
|
}
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
this.logger.info("Adding classpath entries from " + path);
|
||||||
|
Archive archive = new ExplodedArchive(file);
|
||||||
|
lib.addAll(archive.getNestedArchives(new EntryFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(Entry entry) {
|
||||||
|
return entry.isDirectory() || entry.getName().endsWith(".jar")
|
||||||
|
|| entry.getName().endsWith(".zip");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
lib.add(0, archive);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.logger.info("No directory found at " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
private String cleanupPath(String path) {
|
private String cleanupPath(String path) {
|
||||||
path = path.trim();
|
path = path.trim();
|
||||||
// Always a directory
|
// Always a directory
|
||||||
|
|
@ -359,4 +339,8 @@ public class PropertiesLauncher implements ArchiveFilter {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new PropertiesLauncher().launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,21 +19,19 @@ package org.springframework.boot.loader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.archive.Archive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AbstractLauncher} for WAR based archives. This launcher for standard WAR
|
* {@link Launcher} for WAR based archives. This launcher for standard WAR archives.
|
||||||
* archives. Supports dependencies in {@code WEB-INF/lib} as well as
|
* Supports dependencies in {@code WEB-INF/lib} as well as {@code WEB-INF/lib-provided},
|
||||||
* {@code WEB-INF/lib-provided}, classes are loaded from {@code WEB-INF/classes}.
|
* classes are loaded from {@code WEB-INF/classes}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
public class WarLauncher extends AbstractLauncher {
|
public class WarLauncher extends ExecutableArchiveLauncher {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new WarLauncher().launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isArchive(Archive.Entry entry) {
|
public boolean isNestedArchive(Archive.Entry entry) {
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
return entry.getName().equals("WEB-INF/classes/");
|
return entry.getName().equals("WEB-INF/classes/");
|
||||||
}
|
}
|
||||||
|
|
@ -44,20 +42,18 @@ public class WarLauncher extends AbstractLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void postProcessLib(Archive archive, List<Archive> lib) throws Exception {
|
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
|
||||||
lib.add(0, filterArchive(archive));
|
archives.add(0, getFilteredArchive());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter the specified WAR file to exclude elements that should not appear on the
|
* Filter the specified WAR file to exclude elements that should not appear on the
|
||||||
* classpath.
|
* classpath.
|
||||||
* @param archive the source archive
|
|
||||||
* @return the filtered archive
|
* @return the filtered archive
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
protected Archive filterArchive(Archive archive) throws IOException {
|
protected Archive getFilteredArchive() throws IOException {
|
||||||
return archive.getFilteredArchive(new Archive.EntryFilter() {
|
return getArchive().getFilteredArchive(new Archive.EntryRenameFilter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String apply(String entryName, Archive.Entry entry) {
|
public String apply(String entryName, Archive.Entry entry) {
|
||||||
if (entryName.startsWith("META-INF/") || entryName.startsWith("WEB-INF/")) {
|
if (entryName.startsWith("META-INF/") || entryName.startsWith("WEB-INF/")) {
|
||||||
|
|
@ -68,4 +64,7 @@ public class WarLauncher extends AbstractLauncher {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new WarLauncher().launch(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,48 +14,67 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.Launcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An archive that can be launched by the {@link AbstractLauncher}.
|
* An archive that can be launched by the {@link Launcher}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @see JarFileArchive
|
* @see JarFileArchive
|
||||||
*/
|
*/
|
||||||
public interface Archive {
|
public abstract class Archive {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the manifest of the archive.
|
|
||||||
* @return the manifest
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
Manifest getManifest() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns archive entries.
|
|
||||||
* @return the archive entries
|
|
||||||
*/
|
|
||||||
Iterable<Entry> getEntries();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a URL that can be used to load the archive.
|
* Returns a URL that can be used to load the archive.
|
||||||
* @return the archive URL
|
* @return the archive URL
|
||||||
* @throws MalformedURLException
|
* @throws MalformedURLException
|
||||||
*/
|
*/
|
||||||
URL getUrl() throws MalformedURLException;
|
public abstract URL getUrl() throws MalformedURLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a nest archive from on the the contained entries.
|
* Obtain the main class that should be used to launch the application. By default
|
||||||
* @param entry the entry (may be a directory or file)
|
* this method uses a {@code Start-Class} manifest entry.
|
||||||
* @return the nested archive
|
* @return the main class
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String getMainClass() throws Exception {
|
||||||
|
String mainClass = getManifest().getMainAttributes().getValue("Start-Class");
|
||||||
|
if (mainClass == null) {
|
||||||
|
throw new IllegalStateException("No 'Start-Class' manifest entry specified");
|
||||||
|
}
|
||||||
|
return mainClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the manifest of the archive.
|
||||||
|
* @return the manifest
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
Archive getNestedArchive(Entry entry) throws IOException;
|
public abstract Manifest getManifest() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all entries from the archive.
|
||||||
|
* @return the archive entries
|
||||||
|
*/
|
||||||
|
public abstract Collection<Entry> getEntries();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nested {@link Archive}s for entries that match the specified filter.
|
||||||
|
* @param filter the filter used to limit entries
|
||||||
|
* @return nested archives
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public abstract List<Archive> getNestedArchives(EntryFilter filter)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a filtered version of the archive.
|
* Returns a filtered version of the archive.
|
||||||
|
|
@ -63,7 +82,8 @@ public interface Archive {
|
||||||
* @return a filter archive
|
* @return a filter archive
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
Archive getFilteredArchive(EntryFilter filter) throws IOException;
|
public abstract Archive getFilteredArchive(EntryRenameFilter filter)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single entry in the archive.
|
* Represents a single entry in the archive.
|
||||||
|
|
@ -85,10 +105,24 @@ public interface Archive {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter for archive entries.
|
* Strategy interface to filter {@link Entry Entries}.
|
||||||
*/
|
*/
|
||||||
public static interface EntryFilter {
|
public static interface EntryFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the jar entry filter.
|
||||||
|
* @param entry the entry to filter
|
||||||
|
* @return {@code true} if the filter matches
|
||||||
|
*/
|
||||||
|
boolean matches(Entry entry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strategy interface to filter or rename {@link Entry Entries}.
|
||||||
|
*/
|
||||||
|
public static interface EntryRenameFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the jar entry filter.
|
* Apply the jar entry filter.
|
||||||
* @param entryName the current entry name. This may be different that the
|
* @param entryName the current entry name. This may be different that the
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
@ -24,10 +24,13 @@ import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.net.URLStreamHandler;
|
import java.net.URLStreamHandler;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
|
@ -37,7 +40,7 @@ import java.util.jar.Manifest;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
public class ExplodedArchive implements Archive {
|
public class ExplodedArchive extends Archive {
|
||||||
|
|
||||||
private static final Set<String> SKIPPED_NAMES = new HashSet<String>(Arrays.asList(
|
private static final Set<String> SKIPPED_NAMES = new HashSet<String>(Arrays.asList(
|
||||||
".", ".."));
|
".", ".."));
|
||||||
|
|
@ -82,6 +85,12 @@ public class ExplodedArchive implements Archive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getUrl() throws MalformedURLException {
|
||||||
|
FilteredURLStreamHandler handler = new FilteredURLStreamHandler();
|
||||||
|
return new URL("file", "", -1, this.root.getAbsolutePath() + "/", handler);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Manifest getManifest() throws IOException {
|
public Manifest getManifest() throws IOException {
|
||||||
if (this.manifest == null && this.entries.containsKey(MANIFEST_ENTRY_NAME)) {
|
if (this.manifest == null && this.entries.containsKey(MANIFEST_ENTRY_NAME)) {
|
||||||
|
|
@ -98,25 +107,28 @@ public class ExplodedArchive implements Archive {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<Entry> getEntries() {
|
public List<Archive> getNestedArchives(EntryFilter filter) throws IOException {
|
||||||
return this.entries.values();
|
List<Archive> nestedArchives = new ArrayList<Archive>();
|
||||||
|
for (Entry entry : getEntries()) {
|
||||||
|
if (filter.matches(entry)) {
|
||||||
|
nestedArchives.add(getNestedArchive(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(nestedArchives);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getUrl() throws MalformedURLException {
|
public Collection<Entry> getEntries() {
|
||||||
FilteredURLStreamHandler handler = new FilteredURLStreamHandler();
|
return Collections.unmodifiableCollection(this.entries.values());
|
||||||
return new URL("file", "", -1, this.root.getAbsolutePath() + "/", handler);
|
|
||||||
// return this.root.toURI().toURL();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected Archive getNestedArchive(Entry entry) throws IOException {
|
||||||
public Archive getNestedArchive(Entry entry) throws IOException {
|
|
||||||
File file = ((FileEntry) entry).getFile();
|
File file = ((FileEntry) entry).getFile();
|
||||||
return (file.isDirectory() ? new ExplodedArchive(file) : new JarFileArchive(file));
|
return (file.isDirectory() ? new ExplodedArchive(file) : new JarFileArchive(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Archive getFilteredArchive(EntryFilter filter) throws IOException {
|
public Archive getFilteredArchive(EntryRenameFilter filter) throws IOException {
|
||||||
Map<String, Entry> filteredEntries = new LinkedHashMap<String, Archive.Entry>();
|
Map<String, Entry> filteredEntries = new LinkedHashMap<String, Archive.Entry>();
|
||||||
for (Map.Entry<String, Entry> entry : this.entries.entrySet()) {
|
for (Map.Entry<String, Entry> entry : this.entries.entrySet()) {
|
||||||
String filteredName = filter.apply(entry.getKey(), entry.getValue());
|
String filteredName = filter.apply(entry.getKey(), entry.getValue());
|
||||||
|
|
@ -14,13 +14,14 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -35,7 +36,7 @@ import org.springframework.boot.loader.jar.RandomAccessJarFile;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
public class JarFileArchive implements Archive {
|
public class JarFileArchive extends Archive {
|
||||||
|
|
||||||
private final RandomAccessJarFile jarFile;
|
private final RandomAccessJarFile jarFile;
|
||||||
|
|
||||||
|
|
@ -55,30 +56,40 @@ public class JarFileArchive implements Archive {
|
||||||
this.entries = Collections.unmodifiableList(jarFileEntries);
|
this.entries = Collections.unmodifiableList(jarFileEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Manifest getManifest() throws IOException {
|
|
||||||
return this.jarFile.getManifest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterable<Entry> getEntries() {
|
|
||||||
return this.entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getUrl() throws MalformedURLException {
|
public URL getUrl() throws MalformedURLException {
|
||||||
return this.jarFile.getUrl();
|
return this.jarFile.getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Archive getNestedArchive(Entry entry) throws IOException {
|
public Manifest getManifest() throws IOException {
|
||||||
|
return this.jarFile.getManifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Archive> getNestedArchives(EntryFilter filter) throws IOException {
|
||||||
|
List<Archive> nestedArchives = new ArrayList<Archive>();
|
||||||
|
for (Entry entry : getEntries()) {
|
||||||
|
if (filter.matches(entry)) {
|
||||||
|
nestedArchives.add(getNestedArchive(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(nestedArchives);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Entry> getEntries() {
|
||||||
|
return Collections.unmodifiableCollection(this.entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Archive getNestedArchive(Entry entry) throws IOException {
|
||||||
JarEntry jarEntry = ((JarFileEntry) entry).getJarEntry();
|
JarEntry jarEntry = ((JarFileEntry) entry).getJarEntry();
|
||||||
RandomAccessJarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
|
RandomAccessJarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
|
||||||
return new JarFileArchive(jarFile);
|
return new JarFileArchive(jarFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Archive getFilteredArchive(final EntryFilter filter) throws IOException {
|
public Archive getFilteredArchive(final EntryRenameFilter filter) throws IOException {
|
||||||
RandomAccessJarFile filteredJar = this.jarFile
|
RandomAccessJarFile filteredJar = this.jarFile
|
||||||
.getFilteredJarFile(new JarEntryFilter() {
|
.getFilteredJarFile(new JarEntryFilter() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2013 the original author or authors.
|
* Copyright 2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,13 +14,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* Abstraction over logical Archives be they backed by a JAR file or unpacked into a
|
||||||
|
* folder.
|
||||||
|
*
|
||||||
|
* @see org.springframework.boot.loader.archive.Archive
|
||||||
*/
|
*/
|
||||||
public interface ArchiveFilter {
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
public boolean isArchive(Archive.Entry entry);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -17,63 +17,72 @@
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Tests for {@link PropertiesLauncher}.
|
||||||
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public class PropertiesLauncherTests {
|
public class PropertiesLauncherTests {
|
||||||
|
|
||||||
private PropertiesLauncher launcher = new PropertiesLauncher();
|
@Before
|
||||||
|
public void setup() throws IOException {
|
||||||
|
System.setProperty("loader.home",
|
||||||
|
new File("src/test/resources").getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void close() {
|
public void close() {
|
||||||
System.clearProperty("loader.system");
|
|
||||||
System.clearProperty("loader.home");
|
System.clearProperty("loader.home");
|
||||||
System.clearProperty("loader.path");
|
System.clearProperty("loader.path");
|
||||||
System.clearProperty("loader.main");
|
System.clearProperty("loader.main");
|
||||||
System.clearProperty("loader.config.name");
|
System.clearProperty("loader.config.name");
|
||||||
System.clearProperty("loader.config.location");
|
System.clearProperty("loader.config.location");
|
||||||
|
System.clearProperty("loader.system");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultHome() {
|
public void testDefaultHome() {
|
||||||
assertEquals(new File(System.getProperty("user.dir")),
|
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||||
this.launcher.getHomeDirectory());
|
assertEquals(new File(System.getProperty("loader.home")),
|
||||||
|
launcher.getHomeDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserSpecifiedMain() throws Exception {
|
public void testUserSpecifiedMain() throws Exception {
|
||||||
this.launcher.initialize(new File("."));
|
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||||
assertEquals("demo.Application", this.launcher.getMainClass(null));
|
assertEquals("demo.Application", launcher.getMainClass());
|
||||||
assertEquals(null, System.getProperty("loader.main"));
|
assertEquals(null, System.getProperty("loader.main"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserSpecifiedConfigName() throws Exception {
|
public void testUserSpecifiedConfigName() throws Exception {
|
||||||
|
|
||||||
System.setProperty("loader.config.name", "foo");
|
System.setProperty("loader.config.name", "foo");
|
||||||
this.launcher.initialize(new File("."));
|
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||||
assertEquals("my.Application", this.launcher.getMainClass(null));
|
assertEquals("my.Application", launcher.getMainClass());
|
||||||
assertEquals("[etc/]", ReflectionTestUtils.getField(this.launcher, "paths")
|
assertEquals("[etc/]", ReflectionTestUtils.getField(launcher, "paths").toString());
|
||||||
.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemPropertySpecifiedMain() throws Exception {
|
public void testSystemPropertySpecifiedMain() throws Exception {
|
||||||
System.setProperty("loader.main", "foo.Bar");
|
System.setProperty("loader.main", "foo.Bar");
|
||||||
this.launcher.initialize(new File("."));
|
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||||
assertEquals("foo.Bar", this.launcher.getMainClass(null));
|
assertEquals("foo.Bar", launcher.getMainClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemPropertiesSet() throws Exception {
|
public void testSystemPropertiesSet() throws Exception {
|
||||||
System.setProperty("loader.system", "true");
|
System.setProperty("loader.system", "true");
|
||||||
this.launcher.initialize(new File("."));
|
new PropertiesLauncher();
|
||||||
assertEquals("demo.Application", System.getProperty("loader.main"));
|
assertEquals("demo.Application", System.getProperty("loader.main"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
@ -33,7 +33,10 @@ import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.springframework.boot.loader.Archive.Entry;
|
import org.springframework.boot.loader.TestJarCreator;
|
||||||
|
import org.springframework.boot.loader.archive.Archive;
|
||||||
|
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||||
|
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
@ -126,7 +129,7 @@ public class ExplodedArchiveTests {
|
||||||
@Test
|
@Test
|
||||||
public void getFilteredArchive() throws Exception {
|
public void getFilteredArchive() throws Exception {
|
||||||
Archive filteredArchive = this.archive
|
Archive filteredArchive = this.archive
|
||||||
.getFilteredArchive(new Archive.EntryFilter() {
|
.getFilteredArchive(new Archive.EntryRenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public String apply(String entryName, Entry entry) {
|
public String apply(String entryName, Entry entry) {
|
||||||
if (entryName.equals("1.dat")) {
|
if (entryName.equals("1.dat")) {
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.loader;
|
package org.springframework.boot.loader.archive;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
@ -25,9 +25,10 @@ import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.springframework.boot.loader.Archive;
|
import org.springframework.boot.loader.TestJarCreator;
|
||||||
import org.springframework.boot.loader.JarFileArchive;
|
import org.springframework.boot.loader.archive.Archive;
|
||||||
import org.springframework.boot.loader.Archive.Entry;
|
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||||
|
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
@ -83,7 +84,7 @@ public class JarFileArchiveTests {
|
||||||
@Test
|
@Test
|
||||||
public void getFilteredArchive() throws Exception {
|
public void getFilteredArchive() throws Exception {
|
||||||
Archive filteredArchive = this.archive
|
Archive filteredArchive = this.archive
|
||||||
.getFilteredArchive(new Archive.EntryFilter() {
|
.getFilteredArchive(new Archive.EntryRenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public String apply(String entryName, Entry entry) {
|
public String apply(String entryName, Entry entry) {
|
||||||
if (entryName.equals("1.dat")) {
|
if (entryName.equals("1.dat")) {
|
||||||
Loading…
Reference in New Issue