Skip to content

Commit 97f15d6

Browse files
committed
Auto-detect fork value in stop goal
So far, one has to set the "fork" value to both the start and stop goals. Since they have the same name, sharing them in a global configuration element does the trick. However, the plugin also supports auto-detection of the fork value according to other parameters: typically if an agent or jvm arguments are set, forking will be automatically enabled. This is a problem since the stop goal is not aware of that. This commit transmits the value in a property attached to the `MavenProject`. That way, the stop goal can retrieve that value and apply the same defaults. This has the side effect that specifying the fork value isn't necessary anymore. Closes gh-6747
1 parent a5c6b09 commit 97f15d6

File tree

7 files changed

+176
-8
lines changed

7 files changed

+176
-8
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
invoker.goals=clean verify
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>org.springframework.boot.maven.it</groupId>
6+
<artifactId>start-stop-automatic-fork</artifactId>
7+
<version>0.0.1.BUILD-SNAPSHOT</version>
8+
<properties>
9+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
10+
</properties>
11+
<build>
12+
<plugins>
13+
<plugin>
14+
<groupId>org.codehaus.mojo</groupId>
15+
<artifactId>build-helper-maven-plugin</artifactId>
16+
<executions>
17+
<execution>
18+
<id>reserve-jmx-port</id>
19+
<goals>
20+
<goal>reserve-network-port</goal>
21+
</goals>
22+
<phase>process-resources</phase>
23+
<configuration>
24+
<portNames>
25+
<portName>jmx.port</portName>
26+
</portNames>
27+
</configuration>
28+
</execution>
29+
</executions>
30+
</plugin>
31+
<plugin>
32+
<groupId>@project.groupId@</groupId>
33+
<artifactId>@project.artifactId@</artifactId>
34+
<version>@project.version@</version>
35+
<executions>
36+
<execution>
37+
<id>pre-integration-test</id>
38+
<goals>
39+
<goal>start</goal>
40+
</goals>
41+
<configuration>
42+
<jvmArguments>-Dfoo=bar</jvmArguments>
43+
</configuration>
44+
</execution>
45+
<execution>
46+
<id>post-integration-test</id>
47+
<goals>
48+
<goal>stop</goal>
49+
</goals>
50+
</execution>
51+
</executions>
52+
<configuration>
53+
<jmxPort>${jmx.port}</jmxPort>
54+
</configuration>
55+
</plugin>
56+
</plugins>
57+
</build>
58+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.test;
18+
19+
import java.lang.management.ManagementFactory;
20+
21+
import javax.management.MBeanServer;
22+
import javax.management.ObjectName;
23+
24+
/**
25+
* This sample app simulates the JMX Mbean that is exposed by the Spring Boot application.
26+
*/
27+
public class SampleApplication {
28+
29+
private static final Object lock = new Object();
30+
31+
public static void main(String[] args) throws Exception {
32+
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
33+
ObjectName name = new ObjectName(
34+
"org.springframework.boot:type=Admin,name=SpringApplication");
35+
SpringApplicationAdmin mbean = new SpringApplicationAdmin();
36+
mbs.registerMBean(mbean, name);
37+
38+
// Flag the app as ready
39+
mbean.ready = true;
40+
41+
int waitAttempts = 0;
42+
while (!mbean.shutdownInvoked) {
43+
if (waitAttempts > 30) {
44+
throw new IllegalStateException(
45+
"Shutdown should have been invoked by now");
46+
}
47+
synchronized (lock) {
48+
lock.wait(250);
49+
}
50+
waitAttempts++;
51+
}
52+
}
53+
54+
public interface SpringApplicationAdminMXBean {
55+
56+
boolean isReady();
57+
58+
void shutdown();
59+
60+
}
61+
62+
static class SpringApplicationAdmin implements SpringApplicationAdminMXBean {
63+
64+
private boolean ready;
65+
66+
private boolean shutdownInvoked;
67+
68+
@Override
69+
public boolean isReady() {
70+
System.out.println("isReady: " + this.ready);
71+
return this.ready;
72+
}
73+
74+
@Override
75+
public void shutdown() {
76+
this.shutdownInvoked = true;
77+
System.out.println("Shutdown requested");
78+
}
79+
80+
}
81+
82+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import static org.junit.Assert.assertTrue
2+
3+
def file = new File(basedir, "build.log")
4+
assertTrue 'Start should have waited for application to be ready', file.text.contains("isReady: true")
5+
assertTrue 'Shutdown should have been invoked', file.text.contains("Shutdown requested")

spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
9090
/**
9191
* JVM arguments that should be associated with the forked process used to run the
9292
* application. On command line, make sure to wrap multiple values between quotes.
93+
* NOTE: the use of JVM arguments means that processes will be started by forking
94+
* a new JVM.
9395
* @since 1.1
9496
*/
9597
@Parameter(property = "run.jvmArguments")
@@ -137,8 +139,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
137139
private File classesDirectory;
138140

139141
/**
140-
* Flag to indicate if the run processes should be forked. By default process forking
141-
* is only used if an agent or jvmArguments are specified.
142+
* Flag to indicate if the run processes should be forked. {@code fork } is
143+
* automatically enabled if an agent or jvmArguments are specified.
142144
* @since 1.2
143145
*/
144146
@Parameter(property = "fork")
@@ -212,7 +214,10 @@ private void findAgent() {
212214
private void run(String startClassName)
213215
throws MojoExecutionException, MojoFailureException {
214216
findAgent();
215-
if (isFork()) {
217+
boolean forkEnabled = isFork();
218+
this.project.getProperties().setProperty("_spring.boot.fork.enabled",
219+
Boolean.toString(forkEnabled));
220+
if (forkEnabled) {
216221
doRunWithForkedJvm(startClassName);
217222
}
218223
else {

spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ private void waitForSpringApplication(long wait, int maxAttempts)
181181
private void waitForSpringApplication()
182182
throws MojoFailureException, MojoExecutionException {
183183
try {
184-
if (Boolean.TRUE.equals(isFork())) {
184+
if (isFork()) {
185185
waitForForkedSpringApplication();
186186
}
187187
else {

spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.maven.plugins.annotations.LifecyclePhase;
3030
import org.apache.maven.plugins.annotations.Mojo;
3131
import org.apache.maven.plugins.annotations.Parameter;
32+
import org.apache.maven.project.MavenProject;
3233

3334
/**
3435
* Stop a spring application that has been started by the "start" goal. Typically invoked
@@ -41,9 +42,17 @@
4142
public class StopMojo extends AbstractMojo {
4243

4344
/**
44-
* Flag to indicate if the run processes should be forked. Must be aligned to the
45-
* value used to {@link StartMojo start} the process
46-
* @since 1.2
45+
* The Maven project.
46+
* @since 1.4.1
47+
*/
48+
@Parameter(defaultValue = "${project}", readonly = true, required = true)
49+
private MavenProject project;
50+
51+
/**
52+
* Flag to indicate if process to stop was forked. By default, the value is inherited
53+
* from the {@link MavenProject}. If it is set, it must match the value used to
54+
* {@link StartMojo start} the process.
55+
* @since 1.3
4756
*/
4857
@Parameter(property = "fork")
4958
private Boolean fork;
@@ -77,7 +86,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
7786
}
7887
getLog().info("Stopping application...");
7988
try {
80-
if (Boolean.TRUE.equals(this.fork)) {
89+
if (isForked()) {
8190
stopForkedProcess();
8291
}
8392
else {
@@ -90,6 +99,14 @@ public void execute() throws MojoExecutionException, MojoFailureException {
9099
}
91100
}
92101

102+
private boolean isForked() {
103+
if (this.fork != null) {
104+
return this.fork;
105+
}
106+
String property = this.project.getProperties().getProperty("_spring.boot.fork.enabled");
107+
return Boolean.valueOf(property);
108+
}
109+
93110
private void stopForkedProcess()
94111
throws IOException, MojoFailureException, MojoExecutionException {
95112
JMXConnector connector = SpringApplicationAdminClient.connect(this.jmxPort);

0 commit comments

Comments
 (0)