diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/invoker.properties b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/invoker.properties new file mode 100644 index 00000000000..793d89fcd37 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean verify \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/pom.xml new file mode 100644 index 00000000000..577fd23131e --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + org.springframework.boot.maven.it + start-stop-automatic-fork + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + reserve-jmx-port + + reserve-network-port + + process-resources + + + jmx.port + + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + pre-integration-test + + start + + + -Dfoo=bar + + + + post-integration-test + + stop + + + + + ${jmx.port} + + + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..b9c69d69c4b --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2016 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.test; + +import java.lang.management.ManagementFactory; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * This sample app simulates the JMX Mbean that is exposed by the Spring Boot application. + */ +public class SampleApplication { + + private static final Object lock = new Object(); + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName( + "org.springframework.boot:type=Admin,name=SpringApplication"); + SpringApplicationAdmin mbean = new SpringApplicationAdmin(); + mbs.registerMBean(mbean, name); + + // Flag the app as ready + mbean.ready = true; + + int waitAttempts = 0; + while (!mbean.shutdownInvoked) { + if (waitAttempts > 30) { + throw new IllegalStateException( + "Shutdown should have been invoked by now"); + } + synchronized (lock) { + lock.wait(250); + } + waitAttempts++; + } + } + + public interface SpringApplicationAdminMXBean { + + boolean isReady(); + + void shutdown(); + + } + + static class SpringApplicationAdmin implements SpringApplicationAdminMXBean { + + private boolean ready; + + private boolean shutdownInvoked; + + @Override + public boolean isReady() { + System.out.println("isReady: " + this.ready); + return this.ready; + } + + @Override + public void shutdown() { + this.shutdownInvoked = true; + System.out.println("Shutdown requested"); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/verify.groovy new file mode 100644 index 00000000000..5aa87af6830 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-automatic-fork/verify.groovy @@ -0,0 +1,5 @@ +import static org.junit.Assert.assertTrue + +def file = new File(basedir, "build.log") +assertTrue 'Start should have waited for application to be ready', file.text.contains("isReady: true") +assertTrue 'Shutdown should have been invoked', file.text.contains("Shutdown requested") diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index bc4721cce45..2031162b934 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -90,6 +90,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { /** * JVM arguments that should be associated with the forked process used to run the * application. On command line, make sure to wrap multiple values between quotes. + * NOTE: the use of JVM arguments means that processes will be started by forking + * a new JVM. * @since 1.1 */ @Parameter(property = "run.jvmArguments") @@ -137,8 +139,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { private File classesDirectory; /** - * Flag to indicate if the run processes should be forked. By default process forking - * is only used if an agent or jvmArguments are specified. + * Flag to indicate if the run processes should be forked. {@code fork } is + * automatically enabled if an agent or jvmArguments are specified. * @since 1.2 */ @Parameter(property = "fork") @@ -212,7 +214,10 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { private void run(String startClassName) throws MojoExecutionException, MojoFailureException { findAgent(); - if (isFork()) { + boolean forkEnabled = isFork(); + this.project.getProperties().setProperty("_spring.boot.fork.enabled", + Boolean.toString(forkEnabled)); + if (forkEnabled) { doRunWithForkedJvm(startClassName); } else { diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 0e45d747042..74fe47655c4 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -181,7 +181,7 @@ public class StartMojo extends AbstractRunMojo { private void waitForSpringApplication() throws MojoFailureException, MojoExecutionException { try { - if (Boolean.TRUE.equals(isFork())) { + if (isFork()) { waitForForkedSpringApplication(); } else { diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java index 5e04ad96873..aee5532e0c6 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java @@ -29,6 +29,7 @@ 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; +import org.apache.maven.project.MavenProject; /** * Stop a spring application that has been started by the "start" goal. Typically invoked @@ -41,9 +42,17 @@ import org.apache.maven.plugins.annotations.Parameter; public class StopMojo extends AbstractMojo { /** - * Flag to indicate if the run processes should be forked. Must be aligned to the - * value used to {@link StartMojo start} the process - * @since 1.2 + * The Maven project. + * @since 1.4.1 + */ + @Parameter(defaultValue = "${project}", readonly = true, required = true) + private MavenProject project; + + /** + * Flag to indicate if process to stop was forked. By default, the value is inherited + * from the {@link MavenProject}. If it is set, it must match the value used to + * {@link StartMojo start} the process. + * @since 1.3 */ @Parameter(property = "fork") private Boolean fork; @@ -77,7 +86,7 @@ public class StopMojo extends AbstractMojo { } getLog().info("Stopping application..."); try { - if (Boolean.TRUE.equals(this.fork)) { + if (isForked()) { stopForkedProcess(); } else { @@ -90,6 +99,14 @@ public class StopMojo extends AbstractMojo { } } + private boolean isForked() { + if (this.fork != null) { + return this.fork; + } + String property = this.project.getProperties().getProperty("_spring.boot.fork.enabled"); + return Boolean.valueOf(property); + } + private void stopForkedProcess() throws IOException, MojoFailureException, MojoExecutionException { JMXConnector connector = SpringApplicationAdminClient.connect(this.jmxPort);