diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfiguration.java index 56e80062395..3bbbaa3aa5e 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfiguration.java @@ -43,7 +43,8 @@ import org.springframework.jmx.export.MBeanExporter; class SpringApplicationLifecycleAutoConfiguration { /** - * The property to use to customize the {@code ObjectName} of the application lifecycle mbean. + * The property to use to customize the {@code ObjectName} of the application + * lifecycle mbean. */ static final String JMX_NAME_PROPERTY = "spring.context.lifecycle.jmx-name"; @@ -61,10 +62,10 @@ class SpringApplicationLifecycleAutoConfiguration { @Bean public SpringApplicationLifecycleRegistrar springApplicationLifecycleRegistrar() throws MalformedObjectNameException { - - String jmxName = this.environment.getProperty(JMX_NAME_PROPERTY, DEFAULT_JMX_NAME); - if (mbeanExporter != null) { // Make sure to not register that MBean twice - mbeanExporter.addExcludedBean(jmxName); + String jmxName = this.environment + .getProperty(JMX_NAME_PROPERTY, DEFAULT_JMX_NAME); + if (this.mbeanExporter != null) { // Make sure to not register that MBean twice + this.mbeanExporter.addExcludedBean(jmxName); } return new SpringApplicationLifecycleRegistrar(jmxName); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfigurationTests.java index b7242d40c3a..3e97db6685a 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.context; import java.lang.management.ManagementFactory; + import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; @@ -28,7 +29,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -65,17 +65,16 @@ public class SpringApplicationLifecycleAutoConfigurationTests { } @Test - public void notRegisteredByDefault() throws MalformedObjectNameException, InstanceNotFoundException { + public void notRegisteredByDefault() throws MalformedObjectNameException, + InstanceNotFoundException { load(); - - thrown.expect(InstanceNotFoundException.class); + this.thrown.expect(InstanceNotFoundException.class); this.mBeanServer.getObjectInstance(createDefaultObjectName()); } @Test public void registeredWithProperty() throws Exception { load(ENABLE_LIFECYCLE_PROP); - ObjectName objectName = createDefaultObjectName(); ObjectInstance objectInstance = this.mBeanServer.getObjectInstance(objectName); assertNotNull("Lifecycle bean should have been registered", objectInstance); @@ -84,18 +83,17 @@ public class SpringApplicationLifecycleAutoConfigurationTests { @Test public void registerWithCustomJmxName() throws InstanceNotFoundException { String customJmxName = "org.acme:name=FooBar"; - System.setProperty(SpringApplicationLifecycleAutoConfiguration.JMX_NAME_PROPERTY, customJmxName); + System.setProperty(SpringApplicationLifecycleAutoConfiguration.JMX_NAME_PROPERTY, + customJmxName); try { load(ENABLE_LIFECYCLE_PROP); - try { this.mBeanServer.getObjectInstance(createObjectName(customJmxName)); } - catch (InstanceNotFoundException e) { + catch (InstanceNotFoundException ex) { fail("lifecycle MBean should have been exposed with custom name"); } - - thrown.expect(InstanceNotFoundException.class); // Should not be exposed + this.thrown.expect(InstanceNotFoundException.class); // Should not be exposed this.mBeanServer.getObjectInstance(createDefaultObjectName()); } finally { @@ -111,18 +109,18 @@ public class SpringApplicationLifecycleAutoConfigurationTests { try { return new ObjectName(jmxName); } - catch (MalformedObjectNameException e) { - throw new IllegalStateException("Invalid jmx name " + jmxName, e); + catch (MalformedObjectNameException ex) { + throw new IllegalStateException("Invalid jmx name " + jmxName, ex); } } private void load(String... environment) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(applicationContext, environment); - applicationContext.register(JmxAutoConfiguration.class, SpringApplicationLifecycleAutoConfiguration.class); + applicationContext.register(JmxAutoConfiguration.class, + SpringApplicationLifecycleAutoConfiguration.class); applicationContext.refresh(); this.context = applicationContext; } } - diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index 27e36a95215..f3b8bcf797a 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -55,13 +55,6 @@ public class RunProcess { return run(waitForProcess, Arrays.asList(args)); } - /** - * Kill this process. - */ - public void kill() { - doKill(); - } - protected int run(boolean waitForProcess, Collection args) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.command().addAll(args); @@ -131,7 +124,7 @@ public class RunProcess { return true; } } - catch (Exception e) { + catch (Exception ex) { return true; } return false; @@ -180,6 +173,13 @@ public class RunProcess { } + /** + * Kill this process. + */ + public void kill() { + doKill(); + } + private boolean doKill() { // destroy the running process Process process = this.process; @@ -194,7 +194,6 @@ public class RunProcess { Thread.currentThread().interrupt(); } } - return false; } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-fork/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-fork/src/main/java/org/test/SampleApplication.java index dade96cd80c..65a14623bc5 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-fork/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-fork/src/main/java/org/test/SampleApplication.java @@ -22,8 +22,7 @@ import javax.management.MBeanServer; import javax.management.ObjectName; /** - * This sample app simulates the JMX Mbean that is exposed by the Spring - * Boot application. + * This sample app simulates the JMX Mbean that is exposed by the Spring Boot application. */ public class SampleApplication { @@ -31,7 +30,8 @@ public class SampleApplication { public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName("org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"); + ObjectName name = new ObjectName( + "org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"); SpringApplicationLifecycle mbean = new SpringApplicationLifecycle(); mbs.registerMBean(mbean, name); @@ -41,7 +41,8 @@ public class SampleApplication { int waitAttempts = 0; while (!mbean.shutdownInvoked) { if (waitAttempts > 10) { - throw new IllegalStateException("Shutdown should have been invoked by now"); + throw new IllegalStateException( + "Shutdown should have been invoked by now"); } synchronized (lock) { lock.wait(250); @@ -50,7 +51,6 @@ public class SampleApplication { } } - public interface SpringApplicationLifecycleMXBean { boolean isReady(); @@ -76,5 +76,7 @@ public class SampleApplication { this.shutdownInvoked = true; System.out.println("Shutdown requested"); } + } -} \ No newline at end of file + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop/src/main/java/org/test/SampleApplication.java index b06530087ae..1d94c976d3f 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop/src/main/java/org/test/SampleApplication.java @@ -21,8 +21,7 @@ import javax.management.MBeanServer; import javax.management.ObjectName; /** - * This sample app simulates the JMX Mbean that is exposed by the Spring - * Boot application. + * This sample app simulates the JMX Mbean that is exposed by the Spring Boot application. */ public class SampleApplication { @@ -30,7 +29,8 @@ public class SampleApplication { public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName("org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"); + ObjectName name = new ObjectName( + "org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"); SpringApplicationLifecycle mbean = new SpringApplicationLifecycle(); mbs.registerMBean(mbean, name); @@ -40,7 +40,8 @@ public class SampleApplication { int waitAttempts = 0; while (!mbean.shutdownInvoked) { if (waitAttempts > 10) { - throw new IllegalStateException("Shutdown should have been invoked by now"); + throw new IllegalStateException( + "Shutdown should have been invoked by now"); } synchronized (lock) { lock.wait(250); @@ -49,7 +50,6 @@ public class SampleApplication { } } - public interface SpringApplicationLifecycleMXBean { boolean isReady(); @@ -75,5 +75,7 @@ public class SampleApplication { this.shutdownInvoked = true; System.out.println("Shutdown requested"); } + } -} \ No newline at end of file + +} 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 563a5ddec12..0eac1e87143 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 @@ -36,7 +36,6 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter; import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; - import org.springframework.boot.loader.tools.FileUtils; import org.springframework.boot.loader.tools.MainClassFinder; @@ -137,8 +136,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { * @return {@code true} if the application process should be forked */ protected boolean isFork() { - return (Boolean.TRUE.equals(this.fork) - || (this.fork == null && (hasAgent() || hasJvmArgs()))); + return (Boolean.TRUE.equals(this.fork) || (this.fork == null && (hasAgent() || hasJvmArgs()))); } private boolean hasAgent() { @@ -165,7 +163,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } CodeSource source = loaded.getProtectionDomain().getCodeSource(); if (source != null) { - this.agent = new File[] {new File(source.getLocation().getFile())}; + this.agent = new File[] { new File(source.getLocation().getFile()) }; } } } @@ -178,7 +176,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - private void run(String startClassName) throws MojoExecutionException, MojoFailureException { + private void run(String startClassName) throws MojoExecutionException, + MojoFailureException { findAgent(); if (isFork()) { doRunWithForkedJvm(startClassName); @@ -196,8 +195,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - private void doRunWithForkedJvm(String startClassName) - throws MojoExecutionException, MojoFailureException { + private void doRunWithForkedJvm(String startClassName) throws MojoExecutionException, + MojoFailureException { List args = new ArrayList(); addAgents(args); addJvmArgs(args); @@ -213,8 +212,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { * @throws MojoExecutionException * @throws MojoFailureException */ - protected abstract void runWithForkedJvm(List args) throws MojoExecutionException, MojoFailureException; - + protected abstract void runWithForkedJvm(List args) + throws MojoExecutionException, MojoFailureException; /** * Run with the current VM, using the specified arguments. @@ -277,8 +276,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { args.add("-cp"); args.add(classpath.toString()); } - catch (Exception e) { - throw new MojoExecutionException("Could not build classpath", e); + catch (Exception ex) { + throw new MojoExecutionException("Could not build classpath", ex); } } @@ -358,8 +357,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { getLog().debug(sb.toString().trim()); } - private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { + public TestArtifactFilter() { super("", Artifact.SCOPE_TEST); } @@ -368,6 +367,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { protected String getArtifactFeature(Artifact artifact) { return artifact.getScope(); } + } /** @@ -423,7 +423,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { if (!mainMethod.isAccessible()) { mainMethod.setAccessible(true); } - mainMethod.invoke(null, new Object[] {this.args}); + mainMethod.invoke(null, new Object[] { this.args }); } catch (NoSuchMethodException ex) { Exception wrappedEx = new Exception( diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java index 599e676b4f2..130ee89b8c8 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java @@ -42,7 +42,7 @@ class RunArguments { } public LinkedList getArgs() { - return args; + return this.args; } public String[] asArray() { diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index c15385fa171..8a7f6116679 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -24,7 +24,6 @@ import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; - import org.springframework.boot.loader.tools.JavaExecutable; import org.springframework.boot.loader.tools.RunProcess; @@ -41,15 +40,17 @@ public class RunMojo extends AbstractRunMojo { @Override protected void runWithForkedJvm(List args) throws MojoExecutionException { try { - new RunProcess(new JavaExecutable().toString()).run(true, args - .toArray(new String[args.size()])); + new RunProcess(new JavaExecutable().toString()).run(true, + args.toArray(new String[args.size()])); } catch (Exception ex) { throw new MojoExecutionException("Could not exec java", ex); } } - protected void runWithMavenJvm(String startClassName, String... arguments) throws MojoExecutionException { + @Override + protected void runWithMavenJvm(String startClassName, String... arguments) + throws MojoExecutionException { IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(startClassName); Thread launchThread = new Thread(threadGroup, new LaunchRunner(startClassName, arguments), startClassName + ".main()"); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java index df26ad9c2aa..e5c8b2e7406 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java @@ -17,6 +17,7 @@ package org.springframework.boot.maven; import java.io.IOException; + import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; @@ -35,20 +36,19 @@ import org.apache.maven.plugin.MojoExecutionException; * information about the lifecycle of a given Spring application. * * @author Stephane Nicoll - * @since 1.3.0 */ class SpringApplicationLifecycleClient { - //Note: see org.springframework.boot.autoconfigure.test.SpringApplicationLifecycleAutoConfiguration - static final String DEFAULT_OBJECT_NAME = - "org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"; + // Note: see SpringApplicationLifecycleAutoConfiguration + static final String DEFAULT_OBJECT_NAME = "org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"; - private final MBeanServerConnection mBeanServerConnection; + private final MBeanServerConnection connection; private final ObjectName objectName; - public SpringApplicationLifecycleClient(MBeanServerConnection mBeanServerConnection, String jmxName) { - this.mBeanServerConnection = mBeanServerConnection; + public SpringApplicationLifecycleClient(MBeanServerConnection connection, + String jmxName) { + this.connection = connection; this.objectName = toObjectName(jmxName); } @@ -66,30 +66,32 @@ class SpringApplicationLifecycleClient { } /** - * Check if the spring application managed by this instance is ready. - *

Returns {@code false} if the mbean is not yet deployed so this method - * should be repeatedly called until a timeout is reached. + * Check if the spring application managed by this instance is ready. Returns + * {@code false} if the mbean is not yet deployed so this method should be repeatedly + * called until a timeout is reached. * @return {@code true} if the application is ready to service requests * @throws MojoExecutionException if the JMX service could not be contacted */ public boolean isReady() throws MojoExecutionException { try { - return (Boolean) this.mBeanServerConnection.getAttribute(this.objectName, "Ready"); + return (Boolean) this.connection.getAttribute(this.objectName, "Ready"); } - catch (InstanceNotFoundException e) { + catch (InstanceNotFoundException ex) { return false; // Instance not available yet } - catch (AttributeNotFoundException e) { - throw new IllegalStateException("Unexpected: attribute 'Ready' not available", e); + catch (AttributeNotFoundException ex) { + throw new IllegalStateException( + "Unexpected: attribute 'Ready' not available", ex); } - catch (ReflectionException e) { - throw new MojoExecutionException("Failed to retrieve Ready attribute", e.getCause()); + catch (ReflectionException ex) { + throw new MojoExecutionException("Failed to retrieve Ready attribute", + ex.getCause()); } - catch (MBeanException e) { - throw new MojoExecutionException(e.getMessage(), e); + catch (MBeanException ex) { + throw new MojoExecutionException(ex.getMessage(), ex); } - catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); + catch (IOException ex) { + throw new MojoExecutionException(ex.getMessage(), ex); } } @@ -99,15 +101,16 @@ class SpringApplicationLifecycleClient { * @throws IOException if an I/O error occurs * @throws InstanceNotFoundException if the lifecycle mbean cannot be found */ - public void stop() throws MojoExecutionException, IOException, InstanceNotFoundException { + public void stop() throws MojoExecutionException, IOException, + InstanceNotFoundException { try { - this.mBeanServerConnection.invoke(this.objectName, "shutdown", null, null); + this.connection.invoke(this.objectName, "shutdown", null, null); } - catch (ReflectionException e) { - throw new MojoExecutionException("Shutdown failed", e.getCause()); + catch (ReflectionException ex) { + throw new MojoExecutionException("Shutdown failed", ex.getCause()); } - catch (MBeanException e) { - throw new MojoExecutionException("Could not invoke shutdown operation", e); + catch (MBeanException ex) { + throw new MojoExecutionException("Could not invoke shutdown operation", ex); } } 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 129af926914..e72ac351a48 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 @@ -22,6 +22,8 @@ import java.net.ConnectException; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; + import javax.management.MBeanServerConnection; import javax.management.ReflectionException; import javax.management.remote.JMXConnector; @@ -32,15 +34,14 @@ 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.plugins.annotations.ResolutionScope; - import org.springframework.boot.loader.tools.JavaExecutable; import org.springframework.boot.loader.tools.RunProcess; /** - * Start a spring application. Contrary to the {@code run} goal, this does not - * block and allows other goal to operate on the application. This goal is typically - * used in integration test scenario where the application is started before a test - * suite and stopped after. + * Start a spring application. Contrary to the {@code run} goal, this does not block and + * allows other goal to operate on the application. This goal is typically used in + * integration test scenario where the application is started before a test suite and + * stopped after. * * @author Stephane Nicoll * @since 1.3.0 @@ -54,30 +55,30 @@ public class StartMojo extends AbstractRunMojo { private static final String JMX_NAME_PROPERTY_PREFIX = "--spring.context.lifecycle.jmx-name="; /** - * The JMX name of the automatically deployed MBean managing the lifecycle - * of the spring application. + * The JMX name of the automatically deployed MBean managing the lifecycle of the + * spring application. */ @Parameter private String jmxName = SpringApplicationLifecycleClient.DEFAULT_OBJECT_NAME; /** - * The port to use to expose the platform MBeanServer if the application - * needs to be forked. + * The port to use to expose the platform MBeanServer if the application needs to be + * forked. */ @Parameter private int jmxPort = 9001; /** - * The number of milli-seconds to wait between each attempt to check if the - * spring application is ready. + * The number of milli-seconds to wait between each attempt to check if the spring + * application is ready. */ @Parameter private long wait = 500; /** - * The maximum number of attempts to check if the spring application is - * ready. Combined with the "wait" argument, this gives a global timeout - * value (30 sec by default) + * The maximum number of attempts to check if the spring application is ready. + * Combined with the "wait" argument, this gives a global timeout value (30 sec by + * default) */ @Parameter private int maxAttempts = 60; @@ -85,26 +86,30 @@ public class StartMojo extends AbstractRunMojo { private final Object lock = new Object(); @Override - protected void runWithForkedJvm(List args) throws MojoExecutionException, MojoFailureException { - RunProcess runProcess; - try { - runProcess = new RunProcess(new JavaExecutable().toString()); - runProcess.run(false, args.toArray(new String[args.size()])); - } - catch (Exception ex) { - throw new MojoExecutionException("Could not exec java", ex); - } - + protected void runWithForkedJvm(List args) throws MojoExecutionException, + MojoFailureException { + RunProcess runProcess = runProcess(args); try { waitForSpringApplication(); } - catch (MojoExecutionException e) { + catch (MojoExecutionException ex) { runProcess.kill(); - throw e; + throw ex; } - catch (MojoFailureException e) { + catch (MojoFailureException ex) { runProcess.kill(); - throw e; + throw ex; + } + } + + private RunProcess runProcess(List args) throws MojoExecutionException { + try { + RunProcess runProcess = new RunProcess(new JavaExecutable().toString()); + runProcess.run(false, args.toArray(new String[args.size()])); + return runProcess; + } + catch (Exception ex) { + throw new MojoExecutionException("Could not exec java", ex); } } @@ -113,7 +118,8 @@ public class StartMojo extends AbstractRunMojo { RunArguments applicationArguments = super.resolveApplicationArguments(); applicationArguments.getArgs().addLast(ENABLE_MBEAN_PROPERTY); if (isFork()) { - applicationArguments.getArgs().addLast(JMX_NAME_PROPERTY_PREFIX + this.jmxName); + applicationArguments.getArgs().addLast( + JMX_NAME_PROPERTY_PREFIX + this.jmxName); } return applicationArguments; } @@ -124,7 +130,7 @@ public class StartMojo extends AbstractRunMojo { if (isFork()) { List remoteJmxArguments = new ArrayList(); remoteJmxArguments.add("-Dcom.sun.management.jmxremote"); - remoteJmxArguments.add("-Dcom.sun.management.jmxremote.port=" + jmxPort); + remoteJmxArguments.add("-Dcom.sun.management.jmxremote.port=" + this.jmxPort); remoteJmxArguments.add("-Dcom.sun.management.jmxremote.authenticate=false"); remoteJmxArguments.add("-Dcom.sun.management.jmxremote.ssl=false"); jvmArguments.getArgs().addAll(remoteJmxArguments); @@ -132,18 +138,19 @@ public class StartMojo extends AbstractRunMojo { return jvmArguments; } - - protected void runWithMavenJvm(String startClassName, String... arguments) throws MojoExecutionException { + @Override + protected void runWithMavenJvm(String startClassName, String... arguments) + throws MojoExecutionException { IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(startClassName); Thread launchThread = new Thread(threadGroup, new LaunchRunner(startClassName, arguments), startClassName + ".main()"); launchThread.setContextClassLoader(new URLClassLoader(getClassPathUrls())); launchThread.start(); - waitForSpringApplication(this.wait, this.maxAttempts); } - private void waitForSpringApplication(long wait, int maxAttempts) throws MojoExecutionException { + private void waitForSpringApplication(long wait, int maxAttempts) + throws MojoExecutionException { SpringApplicationLifecycleClient helper = new SpringApplicationLifecycleClient( ManagementFactory.getPlatformMBeanServer(), this.jmxName); getLog().debug("Waiting for spring application to start..."); @@ -151,21 +158,26 @@ public class StartMojo extends AbstractRunMojo { if (helper.isReady()) { return; } - getLog().debug("Spring application is not ready yet, waiting " + wait + "ms (attempt " + (i + 1) + ")"); + String message = "Spring application is not ready yet, waiting " + wait + + "ms (attempt " + (i + 1) + ")"; + getLog().debug(message); synchronized (this.lock) { try { this.lock.wait(wait); } - catch (InterruptedException e) { - throw new IllegalStateException("Interrupted while waiting for Spring Boot app to start."); + catch (InterruptedException ex) { + throw new IllegalStateException( + "Interrupted while waiting for Spring Boot app to start."); } } } - throw new MojoExecutionException("Spring application did not start before the configured " + - "timeout (" + (wait * maxAttempts) + "ms"); + throw new MojoExecutionException( + "Spring application did not start before the configured timeout (" + + (wait * maxAttempts) + "ms"); } - private void waitForSpringApplication() throws MojoFailureException, MojoExecutionException { + private void waitForSpringApplication() throws MojoFailureException, + MojoExecutionException { try { if (Boolean.TRUE.equals(isFork())) { waitForForkedSpringApplication(); @@ -174,114 +186,133 @@ public class StartMojo extends AbstractRunMojo { doWaitForSpringApplication(ManagementFactory.getPlatformMBeanServer()); } } - catch (IOException e) { - throw new MojoFailureException("Could not contact Spring Boot application", e); + catch (IOException ex) { + throw new MojoFailureException("Could not contact Spring Boot application", + ex); } - catch (Exception e) { - throw new MojoExecutionException("Could not figure out if the application has started", e); + catch (Exception ex) { + throw new MojoExecutionException( + "Could not figure out if the application has started", ex); } - } - private void waitForForkedSpringApplication() throws IOException, MojoFailureException, MojoExecutionException { - final JMXConnector jmxConnector; + private void waitForForkedSpringApplication() throws IOException, + MojoFailureException, MojoExecutionException { try { getLog().debug("Connecting to local MBeanServer at port " + this.jmxPort); - jmxConnector = execute(wait, maxAttempts, new RetryCallback() { - @Override - public JMXConnector retry() throws Exception { - try { - return SpringApplicationLifecycleClient.createLocalJmxConnector(jmxPort); - } - catch (IOException e) { - if (hasCauseWithType(e, ConnectException.class)) { // Not there yet - getLog().debug("MBean server at port " + jmxPort + " is not up yet..."); - return null; - } - else { - throw e; - } - } - } - }); - if (jmxConnector == null) { - throw new MojoExecutionException("JMX MBean server was not reachable before the configured " + - "timeout (" + (this.wait * this.maxAttempts) + "ms"); + JMXConnector connector = execute(this.wait, this.maxAttempts, + new CreateJmxConnector(this.jmxPort)); + if (connector == null) { + throw new MojoExecutionException( + "JMX MBean server was not reachable before the configured " + + "timeout (" + (this.wait * this.maxAttempts) + "ms"); } getLog().debug("Connected to local MBeanServer at port " + this.jmxPort); try { - MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); - doWaitForSpringApplication(mBeanServerConnection); + MBeanServerConnection connection = connector.getMBeanServerConnection(); + doWaitForSpringApplication(connection); } finally { - jmxConnector.close(); + connector.close(); } } - catch (IOException e) { - throw e; + catch (IOException ex) { + throw ex; } - catch (Exception e) { - throw new MojoExecutionException("Failed to connect to MBean server at port " + this.jmxPort, e); + catch (Exception ex) { + throw new MojoExecutionException("Failed to connect to MBean server at port " + + this.jmxPort, ex); } } private void doWaitForSpringApplication(MBeanServerConnection connection) throws IOException, MojoExecutionException, MojoFailureException { - - final SpringApplicationLifecycleClient client = - new SpringApplicationLifecycleClient(connection, this.jmxName); + final SpringApplicationLifecycleClient client = new SpringApplicationLifecycleClient( + connection, this.jmxName); try { - execute(this.wait, this.maxAttempts, new RetryCallback() { + execute(this.wait, this.maxAttempts, new Callable() { + @Override - public Boolean retry() throws Exception { - boolean ready = client.isReady(); - // Wait until the app is ready - return (ready ? true : null); + public Boolean call() throws Exception { + return (client.isReady() ? true : null); } + }); } - catch (ReflectionException e) { - throw new MojoExecutionException("Unable to retrieve Ready attribute", e.getCause()); + catch (ReflectionException ex) { + throw new MojoExecutionException("Unable to retrieve 'ready' attribute", + ex.getCause()); } - catch (Exception e) { - throw new MojoFailureException("Could not invoke shutdown operation", e); + catch (Exception ex) { + throw new MojoFailureException("Could not invoke shutdown operation", ex); } } - public T execute(long wait, int maxAttempts, RetryCallback callback) throws Exception { + /** + * Execute a task, retrying it on failure. + * @param wait the wait time + * @param maxAttempts the maximum number of attempts + * @param callback the task to execute (possibly multiple times). The callback should + * return {@code null} to indicate that another attempt should be made + * @return the result + * @throws Exception + */ + public T execute(long wait, int maxAttempts, Callable callback) + throws Exception { getLog().debug("Waiting for spring application to start..."); for (int i = 0; i < maxAttempts; i++) { - T result = callback.retry(); + T result = callback.call(); if (result != null) { return result; } - getLog().debug("Spring application is not ready yet, waiting " + wait + "ms (attempt " + (i + 1) + ")"); + String message = "Spring application is not ready yet, waiting " + wait + + "ms (attempt " + (i + 1) + ")"; + getLog().debug(message); synchronized (this.lock) { try { this.lock.wait(wait); } - catch (InterruptedException e) { - throw new IllegalStateException("Interrupted while waiting for Spring Boot app to start."); + catch (InterruptedException ex) { + throw new IllegalStateException( + "Interrupted while waiting for Spring Boot app to start."); } } } - throw new MojoExecutionException("Spring application did not start before the configured " + - "timeout (" + (wait * maxAttempts) + "ms"); + throw new MojoExecutionException( + "Spring application did not start before the configured " + "timeout (" + + (wait * maxAttempts) + "ms"); } - private static boolean hasCauseWithType(Throwable t, Class type) { - return type.isAssignableFrom(t.getClass()) || t.getCause() != null && hasCauseWithType(t.getCause(), type); - } + private class CreateJmxConnector implements Callable { + private final int port; - interface RetryCallback { + public CreateJmxConnector(int port) { + this.port = port; + } + + @Override + public JMXConnector call() throws Exception { + try { + return SpringApplicationLifecycleClient + .createLocalJmxConnector(this.port); + } + catch (IOException ex) { + if (hasCauseWithType(ex, ConnectException.class)) { + String message = "MBean server at port " + this.port + + " is not up yet..."; + getLog().debug(message); + return null; + } + throw ex; + } + } + + private boolean hasCauseWithType(Throwable t, Class type) { + return type.isAssignableFrom(t.getClass()) || t.getCause() != null + && hasCauseWithType(t.getCause(), type); + } - /** - * Attempt to execute an operation. Throws an exception in case of fatal - * exception, returns {@code null} to indicate another attempt should be - * made if possible. - */ - T retry() throws Exception; } } 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 e103551d593..83b666daf55 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 @@ -18,6 +18,7 @@ package org.springframework.boot.maven; import java.io.IOException; import java.lang.management.ManagementFactory; + import javax.management.InstanceNotFoundException; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; @@ -40,23 +41,23 @@ 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 + * 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 */ @Parameter(property = "fork") private Boolean fork; /** - * The JMX name of the automatically deployed MBean managing the lifecycle - * of the application. + * The JMX name of the automatically deployed MBean managing the lifecycle of the + * application. */ @Parameter private String jmxName = SpringApplicationLifecycleClient.DEFAULT_OBJECT_NAME; /** - * The port to use to lookup the platform MBeanServer if the application - * has been forked. + * The port to use to lookup the platform MBeanServer if the application has been + * forked. */ @Parameter private int jmxPort = 9001; @@ -72,9 +73,22 @@ public class StopMojo extends AbstractMojo { stop(); } } - catch (IOException e) { + catch (IOException ex) { // The response won't be received as the server has died - ignoring - getLog().debug("Service is not reachable anymore (" + e.getMessage() + ")"); + getLog().debug("Service is not reachable anymore (" + ex.getMessage() + ")"); + } + } + + private void stopForkedProcess() throws IOException, MojoFailureException, + MojoExecutionException { + JMXConnector connector = SpringApplicationLifecycleClient + .createLocalJmxConnector(this.jmxPort); + try { + MBeanServerConnection connection = connector.getMBeanServerConnection(); + doStop(connection); + } + finally { + connector.close(); } } @@ -82,26 +96,15 @@ public class StopMojo extends AbstractMojo { doStop(ManagementFactory.getPlatformMBeanServer()); } - private void stopForkedProcess() throws IOException, MojoFailureException, MojoExecutionException { - JMXConnector jmxConnector = SpringApplicationLifecycleClient.createLocalJmxConnector(this.jmxPort); + private void doStop(MBeanServerConnection connection) throws IOException, + MojoExecutionException { try { - MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); - doStop(mBeanServerConnection); + new SpringApplicationLifecycleClient(connection, this.jmxName).stop(); } - finally { - jmxConnector.close(); - } - } - - private void doStop(MBeanServerConnection connection) - throws IOException, MojoExecutionException { - SpringApplicationLifecycleClient helper = new SpringApplicationLifecycleClient(connection, this.jmxName); - try { - helper.stop(); - } - catch (InstanceNotFoundException e) { - throw new MojoExecutionException("Spring application lifecycle JMX bean not found (fork is " + - "" + this.fork + "). Could not stop application gracefully", e); + catch (InstanceNotFoundException ex) { + throw new MojoExecutionException( + "Spring application lifecycle JMX bean not found (fork is " + "" + + this.fork + "). Could not stop application gracefully", ex); } } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrar.java index e76ad0fcb0a..cb2d2b27507 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrar.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrar.java @@ -17,13 +17,13 @@ package org.springframework.boot.context; import java.lang.management.ManagementFactory; + import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; @@ -52,50 +52,51 @@ public class SpringApplicationLifecycleRegistrar implements ApplicationContextAw private boolean ready = false; - public SpringApplicationLifecycleRegistrar(String name) throws MalformedObjectNameException { + public SpringApplicationLifecycleRegistrar(String name) + throws MalformedObjectNameException { this.objectName = new ObjectName(name); } @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + Assert.state(applicationContext instanceof ConfigurableApplicationContext, "ApplicationContext does not implement ConfigurableApplicationContext"); this.applicationContext = (ConfigurableApplicationContext) applicationContext; } @Override public void onApplicationEvent(ApplicationReadyEvent event) { - ready = true; + this.ready = true; } @Override public void afterPropertiesSet() throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - server.registerMBean(new SpringApplicationLifecycle(), objectName); + server.registerMBean(new SpringApplicationLifecycle(), this.objectName); if (logger.isDebugEnabled()) { - logger.debug("Application lifecycle MBean registered with name '" + objectName + "'"); + logger.debug("Application lifecycle MBean registered with name '" + + this.objectName + "'"); } } @Override public void destroy() throws Exception { - ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName); + ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.objectName); } - private class SpringApplicationLifecycle implements SpringApplicationLifecycleMXBean { @Override public boolean isReady() { - return ready; + return SpringApplicationLifecycleRegistrar.this.ready; } @Override public void shutdown() { logger.info("Application shutdown requested."); - applicationContext.close(); + SpringApplicationLifecycleRegistrar.this.applicationContext.close(); } } } - diff --git a/spring-boot/src/test/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrarTests.java b/spring-boot/src/test/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrarTests.java index 7b06862e548..5f761d6ae93 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrarTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrarTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.context; import java.lang.management.ManagementFactory; + import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; @@ -27,7 +28,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; @@ -75,15 +75,18 @@ public class SpringApplicationLifecycleRegistrarTests { @Override public void onApplicationEvent(ContextRefreshedEvent event) { try { - assertFalse("Application should not be ready yet", isCurrentApplicationReady(objectName)); + assertFalse("Application should not be ready yet", + isCurrentApplicationReady(objectName)); } - catch (Exception e) { - throw new IllegalStateException("Could not contact spring application lifecycle bean", e); + catch (Exception ex) { + throw new IllegalStateException( + "Could not contact spring application lifecycle bean", ex); } } }); this.context = application.run(); - assertTrue("application should be ready now", isCurrentApplicationReady(objectName)); + assertTrue("application should be ready now", + isCurrentApplicationReady(objectName)); } @Test @@ -95,8 +98,7 @@ public class SpringApplicationLifecycleRegistrarTests { assertTrue("application should be running", this.context.isRunning()); invokeShutdown(objectName); assertFalse("application should not be running", this.context.isRunning()); - - thrown.expect(InstanceNotFoundException.class); // JMX cleanup + this.thrown.expect(InstanceNotFoundException.class); // JMX cleanup this.mBeanServer.getObjectInstance(objectName); } @@ -127,16 +129,15 @@ public class SpringApplicationLifecycleRegistrarTests { } } - @Configuration static class Config { @Bean public SpringApplicationLifecycleRegistrar springApplicationLifecycle() throws MalformedObjectNameException { - return new SpringApplicationLifecycleRegistrar(OBJECT_NAME); } + } }