/*******************************************************************************
* Copyright (c) 2013, 2017 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* GoPivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.launch.cli;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMRunner;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.VMRunnerConfiguration;
import org.springframework.ide.eclipse.boot.core.cli.BootCliUtils;
import org.springframework.ide.eclipse.boot.core.cli.install.IBootInstall;
import org.springframework.ide.eclipse.boot.launch.BootLaunchConfigurationDelegate;
import org.springframework.ide.eclipse.boot.util.Log;
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
/**
* Launch Configuration delegate able to start/shut down Spring Boot CLI processes
*
* @author Kris De Volder
* @author Alex Boyko
*
*/
public class BootCliLaunchConfigurationDelegate extends LaunchConfigurationDelegate {
private static String[] getSpringBootClasspath(ILaunchConfiguration conf, IBootInstall install) throws Exception {
File[] bootLibJars = install.getBootLibJars();
List<String> classpath = new ArrayList<>(2 + bootLibJars.length);
classpath.add(".");
Path extensions = install.getHome().toPath().resolve("lib/ext/");
if (Files.exists(extensions)) {
classpath.add(extensions.toString());
}
classpath.addAll(Arrays.stream(bootLibJars).map(jarFile -> jarFile.toString()).collect(Collectors.toList()));
return classpath.toArray(new String[classpath.size()]);
}
/**
* Spring Boot CLI main class to launch (Ideally this shouldn't be overriden)
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return main type class name
* @throws Exception
*/
protected String getMainTypeName(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
return "org.springframework.boot.loader.JarLauncher";
}
/**
* Environment variables for Spring Boot CLI process
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return environment variables as array of strings, where each string looks like <b>SPRING_HOME=/Users/me/spring-cli</b>
* @throws Exception
*/
protected String[] getEnv(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
List<String> env = new ArrayList<>(2);
IVMInstall vmInstall = verifyVMInstall(conf);
env.add("JAVA_HOME=" + vmInstall.getInstallLocation());
try {
env.add("SPRING_HOME=" + install.getHome());
} catch (Exception e) {
Log.log(e);
}
return env.toArray(new String[env.size()]);
}
/**
* VM arguments for launching the Spring Boot CLI
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return array of VM arguments to launch the CLI
* @throws Exception
*/
protected String[] getVmArgs(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
if (BootLaunchConfigurationDelegate.supportsAnsiConsoleOutput()) {
return new String[] {"-Dspring.output.ansi.enabled=always"};
} else {
return new String[0];
}
}
/**
* Specific VM attributes for launching Spring Boot CLI
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return specific VM attributes map
* @throws Exception
*/
protected Map<String, Object> getVmSpecificAttributesMap(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
return Collections.emptyMap();
}
/**
* Program arguments for the Spring Boot CLI. This is the typically overriden method to specify the spring cloud command, i.e. <code>["cloud", "--version"]</code>
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return Spring Boot CLI command as an array of strings
* @throws Exception
*/
protected String[] getProgramArgs(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
return new String[0];
}
/**
* Working directory for launching the Spring Boot CLI
* @param install Spring Boot CLI install
* @param launch Eclipse's launch
* @param conf Launch configuration
* @return working directory for the launch
* @throws Exception
*/
protected String getWorkingDirectory(IBootInstall install, ILaunch launch, ILaunchConfiguration conf) throws Exception {
return install.getHome().toString();
}
@Override
final public void launch(ILaunchConfiguration conf, String mode,
ILaunch launch, IProgressMonitor monitor) throws CoreException {
//TODO: some common things that Java launch configs do that this one does not (yet) do but probably should
// - offer to save unsaved files
// - check for errors in project
// - source locators (for debugging processes)
// - launching in debug mode
try {
IBootInstall install = BootCliUtils.getSpringBootInstall();
IVMInstall vm = verifyVMInstall(conf);
IVMRunner runner = vm.getVMRunner(mode);
String mainTypeName = getMainTypeName(install, launch, conf);
String[] classpath = getSpringBootClasspath(conf, install);
VMRunnerConfiguration runConfiguration = new VMRunnerConfiguration(mainTypeName, classpath);
runConfiguration.setProgramArguments(getProgramArgs(install, launch, conf));
runConfiguration.setVMArguments(getVmArgs(install, launch, conf));
runConfiguration.setWorkingDirectory(getWorkingDirectory(install, launch, conf));
runConfiguration.setEnvironment(getEnv(install, launch, conf));
runConfiguration.setVMSpecificAttributesMap(getVmSpecificAttributesMap(install, launch, conf));
runner.run(runConfiguration, launch, monitor);
} catch (Exception e) {
throw ExceptionUtil.coreException(e);
}
}
protected IVMInstall verifyVMInstall(ILaunchConfiguration conf) {
//Extremely simplistic implementation. Just gets the default JVM for this workspace.
//TODO: project specific JVM selection or maybe the JVM should be associated with
// spring boot installation.
return JavaRuntime.getDefaultVMInstall();
}
}