This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git
commit bd126b1734ef34c2511eb2311d404c6ad529f3f2 Author: Robert Munteanu <[email protected]> AuthorDate: Wed Jun 24 22:39:35 2020 +0200 SLING-9526 - Allow launching feature model applications in external processes, non-blocking Advanced with a very basic implementation, but good enough to start launchpad-testing. --- .../launcher/{Processes.java => Launch.java} | 38 +++++-- .../{Processes.java => LauncherArguments.java} | 16 +-- .../sling/maven/feature/launcher/Processes.java | 13 ++- .../sling/maven/feature/launcher/StartMojo.java | 123 +++++++++++++++------ .../sling/maven/feature/launcher/StopMojo.java | 19 ++-- 5 files changed, 146 insertions(+), 63 deletions(-) diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java similarity index 56% copy from src/main/java/org/apache/sling/maven/feature/launcher/Processes.java copy to src/main/java/org/apache/sling/maven/feature/launcher/Launch.java index 85eed28..0b98119 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java @@ -18,18 +18,36 @@ */ package org.apache.sling.maven.feature.launcher; -import java.util.Optional; +import org.apache.maven.model.Dependency; -// TODO - refactor to a Mojo Component -public class Processes { +public class Launch { - private static Process process; - - public static void set(Process process) { - Processes.process = process; + private String id; + private Dependency feature; + private LauncherArguments launcherArguments; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; } - - public static Optional<Process> get() { - return Optional.ofNullable(process); + + public Dependency getFeature() { + return feature; + } + + public void setFeature(Dependency feature) { + this.feature = feature; } + + public LauncherArguments getLauncherArguments() { + return launcherArguments; + } + + public void setLauncherArguments(LauncherArguments launcherArguments) { + this.launcherArguments = launcherArguments; + } + } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java b/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java similarity index 69% copy from src/main/java/org/apache/sling/maven/feature/launcher/Processes.java copy to src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java index 85eed28..c96958f 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java @@ -18,18 +18,18 @@ */ package org.apache.sling.maven.feature.launcher; -import java.util.Optional; +import java.util.HashMap; +import java.util.Map; -// TODO - refactor to a Mojo Component -public class Processes { +public class LauncherArguments { - private static Process process; + private Map<String, String> frameworkProperties = new HashMap<>(); - public static void set(Process process) { - Processes.process = process; + public Map<String, String> getFrameworkProperties() { + return frameworkProperties; } - public static Optional<Process> get() { - return Optional.ofNullable(process); + public void setFrameworkProperties(Map<String, String> frameworkProperties) { + this.frameworkProperties = frameworkProperties; } } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java b/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java index 85eed28..79d7351 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/Processes.java @@ -18,18 +18,21 @@ */ package org.apache.sling.maven.feature.launcher; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; // TODO - refactor to a Mojo Component public class Processes { - private static Process process; + private static final Map<String, Process> processes = new HashMap<>(); - public static void set(Process process) { - Processes.process = process; + public static void addProcess(String id, Process process) { + // TODO - check for duplicates + processes.put(id, process); } - public static Optional<Process> get() { - return Optional.ofNullable(process); + public static Optional<Process> get(String id) { + return Optional.ofNullable(processes.get(id)); } } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java index 4b39d99..7ec48ab 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java @@ -19,12 +19,15 @@ package org.apache.sling.maven.feature.launcher; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.ProcessBuilder.Redirect; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; @@ -54,12 +57,22 @@ public class StartMojo @Parameter( defaultValue = "${project.build.directory}", property = "outputDir", required = true ) private File outputDirectory; - // TODO - support multiple dependencies and also have proper parameter names @Parameter(required = true) - private Dependency toLaunch; - - @Parameter - private Map<String, String> frameworkProperties = new HashMap<String, String>(); + private List<Launch> launches; + + // <launches> + // <launch> + // <id>...</id> + // <dependency>...</dependency> + // <launcherArguments> + // <frameworkProperties> + // <org.osgi.service.http.port>8090</org.osgi.service.http.port> + // </framweworkProperties> + // ... + // </launcherArguments> + // <environment> + // <JAVA_HOME>...</JAVA_HOME> + // </environment> @Component private ArtifactResolver resolver; @@ -76,11 +89,6 @@ public class StartMojo try { RepositorySystemSession repositorySession = mavenSession.getRepositorySession(); - Artifact artifact = toArtifact(toLaunch); - - ArtifactResult result = resolver.resolveArtifact(repositorySession, new ArtifactRequest(artifact, null, null)); - File featureFile = result.getArtifact().getFile(); - // TODO - this should be inferred from the plugin's pom.xml dependency (not the project's pom.xml) Dependency featureLauncherDep = project.getDependencies().stream() @@ -97,28 +105,79 @@ public class StartMojo File workDir = new File(outputDirectory, "launchers"); workDir.mkdirs(); - List<String> args = new ArrayList<>(); - args.add(System.getenv("JAVA_HOME") + File.separatorChar + "bin" + File.separatorChar + "java"); - args.add("-jar"); - args.add(launcher.getAbsolutePath()); - args.add("-f"); - args.add(featureFile.getAbsolutePath()); + for ( Launch launch : launches ) { - for ( var frameworkProperty : frameworkProperties.entrySet() ) { - args.add("-D"); - args.add(frameworkProperty.getKey()+"="+frameworkProperty.getValue()); + // TODO - validate it is actually a feature + Artifact artifact = toArtifact(launch.getFeature()); + + ArtifactResult result = resolver.resolveArtifact(repositorySession, new ArtifactRequest(artifact, null, null)); + File featureFile = result.getArtifact().getFile(); + + List<String> args = new ArrayList<>(); + args.add(System.getenv("JAVA_HOME") + File.separatorChar + "bin" + File.separatorChar + "java"); + args.add("-jar"); + args.add(launcher.getAbsolutePath()); + args.add("-f"); + args.add(featureFile.getAbsolutePath()); + args.add("-p"); + args.add(launch.getId()); // TODO - validate launch id is a valid file name + + for ( var frameworkProperty : launch.getLauncherArguments().getFrameworkProperties().entrySet() ) { + args.add("-D"); + args.add(frameworkProperty.getKey()+"="+frameworkProperty.getValue()); + } + + // TODO - add support for all arguments supported by the feature launcher + ProcessBuilder pb = new ProcessBuilder(args); + pb.redirectOutput(Redirect.INHERIT); + pb.redirectInput(Redirect.INHERIT); + pb.directory(workDir); + + getLog().info("Starting launch with id " + launch.getId()); + + CountDownLatch latch = new CountDownLatch(1); + + Process process = pb.start(); + + Thread monitor = new Thread("launch-monitor-" + launch.getId()) { + @Override + public void run() { + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); + String line; + try { + while ( (line = reader.readLine()) != null ) { + System.out.println(line); +// getLog().info("Checking line '" + line); + if ( line.contains("Framework started")) { +// getLog().info("STARTED!"); + latch.countDown(); + break; + } + } + } catch (IOException e) { + getLog().warn(e.getMessage(), e); + } + } + }; + monitor.start(); + getLog().info("Waiting for " + launch.getId() + " to start"); + boolean started = latch.await(30, TimeUnit.SECONDS); + if ( !started ) { + process.destroy(); + boolean stopped = process.waitFor(30, TimeUnit.SECONDS); + if ( !stopped ) + process.destroyForcibly(); + throw new MojoExecutionException("Launch " + launch.getId() + " failed to start in the allocated time."); + } + + + // TODO - reliably stop started processes in case 'stop' is not invoked + + Processes.addProcess(launch.getId(), process); } - - // TODO - add support for all arguments supported by the feature launcher - ProcessBuilder pb = new ProcessBuilder(args); - pb.inheritIO(); - pb.directory(workDir); - Process process = pb.start(); - - // TODO - reliably stop started processes in case 'stop' is not invoked - - Processes.set(process); - } catch (ArtifactResolutionException | IOException e) { + + // TODO - properly handle interrupted exception + } catch (ArtifactResolutionException | IOException | InterruptedException e) { throw new MojoExecutionException(e.getMessage(), e); } } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java b/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java index 837a0c2..d3b10bf 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java @@ -18,6 +18,7 @@ */ package org.apache.sling.maven.feature.launcher; +import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.maven.plugin.AbstractMojo; @@ -25,22 +26,24 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; @Mojo( name = "stop", defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST) public class StopMojo extends AbstractMojo { + @Parameter(required = true) + private List<Launch> launches; + @Override public void execute() throws MojoExecutionException, MojoFailureException { try { - // TODO - for testing only, remove once the IT does something meaningful - Thread.sleep(30 * 1000); - - Process process = Processes.get() - .get(); - - process.destroy(); - process.waitFor(30, TimeUnit.SECONDS); + for ( Launch launch : launches ) { + getLog().info("Stopping launch with id " + launch.getId()); + Process process = Processes.get(launch.getId()).get(); + process.destroy(); + process.waitFor(30, TimeUnit.SECONDS); + } } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
