Reuse JavaProcessExecutor

See gh-31682
pull/31928/head
Stephane Nicoll 2 years ago
parent c3ae6519f4
commit b0bc7cd85b

@ -37,11 +37,9 @@ import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager; import org.apache.maven.toolchain.ToolchainManager;
import org.springframework.boot.loader.tools.FileUtils; import org.springframework.boot.loader.tools.FileUtils;
import org.springframework.boot.loader.tools.JavaExecutable;
/** /**
* Base class to run a Spring Boot application. * Base class to run a Spring Boot application.
@ -215,20 +213,24 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
addClasspath(args); addClasspath(args);
args.add(startClassName); args.add(startClassName);
addArgs(args); addArgs(args);
run((this.workingDirectory != null) ? this.workingDirectory : this.project.getBasedir(), args, JavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);
determineEnvironmentVariables()); File workingDirectoryToUse = (this.workingDirectory != null) ? this.workingDirectory
: this.project.getBasedir();
run(processExecutor, workingDirectoryToUse, args, determineEnvironmentVariables());
} }
/** /**
* Run with a forked VM, using the specified command line arguments. * Run the application.
* @param processExecutor the {@link JavaProcessExecutor} to use
* @param workingDirectory the working directory of the forked JVM * @param workingDirectory the working directory of the forked JVM
* @param args the arguments (JVM arguments and application arguments) * @param args the arguments (JVM arguments and application arguments)
* @param environmentVariables the environment variables * @param environmentVariables the environment variables
* @throws MojoExecutionException in case of MOJO execution errors * @throws MojoExecutionException in case of MOJO execution errors
* @throws MojoFailureException in case of MOJO failures * @throws MojoFailureException in case of MOJO failures
* @since 3.0.0
*/ */
protected abstract void run(File workingDirectory, List<String> args, Map<String, String> environmentVariables) protected abstract void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,
throws MojoExecutionException, MojoFailureException; Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException;
/** /**
* Resolve the application arguments to use. * Resolve the application arguments to use.
@ -241,16 +243,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
return runArguments; return runArguments;
} }
/**
* Provides access to the java binary executable, regardless of OS.
* @return the java executable
*/
protected String getJavaExecutable() {
Toolchain toolchain = this.toolchainManager.getToolchainFromBuildContext("jdk", this.session);
String javaExecutable = (toolchain != null) ? toolchain.findTool("java") : null;
return (javaExecutable != null) ? javaExecutable : new JavaExecutable().toString();
}
/** /**
* Resolve the environment variables to use. * Resolve the environment variables to use.
* @return an {@link EnvVariables} defining the environment variables * @return an {@link EnvVariables} defining the environment variables

@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoExecutionException;
@ -42,9 +43,23 @@ class JavaProcessExecutor {
private final ToolchainManager toolchainManager; private final ToolchainManager toolchainManager;
private final Consumer<RunProcess> runProcessCustomizer;
JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) { JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) {
this(mavenSession, toolchainManager, null);
}
private JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager,
Consumer<RunProcess> runProcessCustomizer) {
this.mavenSession = mavenSession; this.mavenSession = mavenSession;
this.toolchainManager = toolchainManager; this.toolchainManager = toolchainManager;
this.runProcessCustomizer = runProcessCustomizer;
}
JavaProcessExecutor withRunProcessCustomizer(Consumer<RunProcess> customizer) {
Consumer<RunProcess> combinedCustomizer = (this.runProcessCustomizer != null)
? this.runProcessCustomizer.andThen(customizer) : customizer;
return new JavaProcessExecutor(this.mavenSession, this.toolchainManager, combinedCustomizer);
} }
int run(File workingDirectory, List<String> args, Map<String, String> environmentVariables) int run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
@ -62,6 +77,18 @@ class JavaProcessExecutor {
} }
} }
RunProcess runAsync(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());
runProcess.run(false, args, environmentVariables);
return runProcess;
}
catch (IOException ex) {
throw new MojoExecutionException("Process execution failed", ex);
}
}
private boolean hasTerminatedSuccessfully(int exitCode) { private boolean hasTerminatedSuccessfully(int exitCode) {
return (exitCode == 0 || exitCode == EXIT_CODE_SIGINT); return (exitCode == 0 || exitCode == EXIT_CODE_SIGINT);
} }

@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Mojo;
@ -43,8 +44,6 @@ import org.springframework.boot.loader.tools.RunProcess;
@Execute(phase = LifecyclePhase.TEST_COMPILE) @Execute(phase = LifecyclePhase.TEST_COMPILE)
public class RunMojo extends AbstractRunMojo { public class RunMojo extends AbstractRunMojo {
private static final int EXIT_CODE_SIGINT = 130;
/** /**
* Whether the JVM's launch should be optimized. * Whether the JVM's launch should be optimized.
* @since 2.2.0 * @since 2.2.0
@ -62,25 +61,11 @@ public class RunMojo extends AbstractRunMojo {
} }
@Override @Override
protected void run(File workingDirectory, List<String> args, Map<String, String> environmentVariables) protected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,
throws MojoExecutionException { Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {
int exitCode = forkJvm(workingDirectory, args, environmentVariables); processExecutor.withRunProcessCustomizer(
if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) { (runProcess) -> Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess))))
return; .run(workingDirectory, args, environmentVariables);
}
throw new MojoExecutionException("Application finished with exit code: " + exitCode);
}
private int forkJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());
Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess)));
return runProcess.run(true, args, environmentVariables);
}
catch (Exception ex) {
throw new MojoExecutionException("Could not exec java", ex);
}
} }
private static final class RunProcessKiller implements Runnable { private static final class RunProcessKiller implements Runnable {

@ -86,9 +86,9 @@ public class StartMojo extends AbstractRunMojo {
private final Object lock = new Object(); private final Object lock = new Object();
@Override @Override
protected void run(File workingDirectory, List<String> args, Map<String, String> environmentVariables) protected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,
throws MojoExecutionException, MojoFailureException { Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables); RunProcess runProcess = processExecutor.runAsync(workingDirectory, args, environmentVariables);
try { try {
waitForSpringApplication(); waitForSpringApplication();
} }
@ -98,18 +98,6 @@ public class StartMojo extends AbstractRunMojo {
} }
} }
private RunProcess runProcess(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());
runProcess.run(false, args, environmentVariables);
return runProcess;
}
catch (Exception ex) {
throw new MojoExecutionException("Could not exec java", ex);
}
}
@Override @Override
protected RunArguments resolveApplicationArguments() { protected RunArguments resolveApplicationArguments() {
RunArguments applicationArguments = super.resolveApplicationArguments(); RunArguments applicationArguments = super.resolveApplicationArguments();

Loading…
Cancel
Save