Reuse JavaProcessExecutor

See gh-31682
This commit is contained in:
Stephane Nicoll 2022-07-28 14:51:41 +02:00
parent c3ae6519f4
commit b0bc7cd85b
4 changed files with 45 additions and 53 deletions

View File

@ -37,11 +37,9 @@ import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import org.springframework.boot.loader.tools.FileUtils;
import org.springframework.boot.loader.tools.JavaExecutable;
/**
* Base class to run a Spring Boot application.
@ -215,20 +213,24 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
addClasspath(args);
args.add(startClassName);
addArgs(args);
run((this.workingDirectory != null) ? this.workingDirectory : this.project.getBasedir(), args,
determineEnvironmentVariables());
JavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);
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 args the arguments (JVM arguments and application arguments)
* @param environmentVariables the environment variables
* @throws MojoExecutionException in case of MOJO execution errors
* @throws MojoFailureException in case of MOJO failures
* @since 3.0.0
*/
protected abstract void run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
throws MojoExecutionException, MojoFailureException;
protected abstract void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,
Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException;
/**
* Resolve the application arguments to use.
@ -241,16 +243,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
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.
* @return an {@link EnvVariables} defining the environment variables

View File

@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
@ -42,9 +43,23 @@ class JavaProcessExecutor {
private final ToolchainManager toolchainManager;
private final Consumer<RunProcess> runProcessCustomizer;
JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) {
this(mavenSession, toolchainManager, null);
}
private JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager,
Consumer<RunProcess> runProcessCustomizer) {
this.mavenSession = mavenSession;
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)
@ -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) {
return (exitCode == 0 || exitCode == EXIT_CODE_SIGINT);
}

View File

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

View File

@ -86,9 +86,9 @@ public class StartMojo extends AbstractRunMojo {
private final Object lock = new Object();
@Override
protected void run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables);
protected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,
Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = processExecutor.runAsync(workingDirectory, args, environmentVariables);
try {
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
protected RunArguments resolveApplicationArguments() {
RunArguments applicationArguments = super.resolveApplicationArguments();