/*
* 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.FileCopyUtils;
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);
if (archive.getName().endsWith(".war")) {
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) throws IOException {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
File source = new File(this.exploded, getClassesPath(archive));
FileSystemUtils.copyRecursively(source, targetClasses);
FileSystemUtils.deleteRecursively(source);
return targetClasses;
}
private File populateDependencies(File archive) throws IOException {
File dependencies = new File(this.exploded, "dependencies");
dependencies.mkdirs();
List<String> libPaths = getLibPaths(archive);
for (String libPath : libPaths) {
File libDirectory = new File(this.exploded, libPath);
for (File jar : libDirectory.listFiles()) {
FileCopyUtils.copy(jar, new File(dependencies, jar.getName()));
}
FileSystemUtils.deleteRecursively(libDirectory);
}
return dependencies;
}
private void populateSrcMainWebapp() throws IOException {
File srcMainWebapp = new File(this.exploded, "src/main/webapp");
srcMainWebapp.mkdirs();
File source = new File(this.exploded, "webapp-resource.txt");
FileCopyUtils.copy(source, new File(srcMainWebapp, "webapp-resource.txt"));
source.delete();
}
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";
}
}