diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfiguration.java deleted file mode 100644 index b79fe2d2e8e..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfiguration.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.autoconfigure.lifecycle; - -import javax.management.MalformedObjectNameException; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.jmx.export.MBeanExporter; - -/** - * Register a JMX component that allows to manage the lifecycle of the current - * application. Intended for internal use only. - * - * @author Stephane Nicoll - * @since 1.3.0 - * @see SpringApplicationLifecycleMXBean - */ -@Configuration -@AutoConfigureAfter(JmxAutoConfiguration.class) -@ConditionalOnProperty(value = "spring.application.lifecycle.enabled", havingValue = "true", matchIfMissing = false) -class SpringApplicationLifecycleAutoConfiguration { - - /** - * The property to use to customize the {@code ObjectName} of the application lifecycle mbean. - */ - static final String JMX_NAME_PROPERTY = "spring.application.lifecycle.jmx-name"; - - /** - * The default {@code ObjectName} of the application lifecycle mbean. - */ - static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"; - - @Autowired(required = false) - private MBeanExporter mbeanExporter; - - @Autowired - private Environment environment; - - @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); - } - return new SpringApplicationLifecycleRegistrar(jmxName); - } - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleMXBean.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleMXBean.java deleted file mode 100644 index 56b0a41e71a..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleMXBean.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.autoconfigure.lifecycle; - -/** - * A simple MBean contract to control the lifecycle of a {@code SpringApplication} via - * JMX. Intended for internal use only. - * - * @author Stephane Nicoll - * @since 1.3.0 - */ -public interface SpringApplicationLifecycleMXBean { - - /** - * Specify if the application has fully started and is now ready. - * @return {@code true} if the application is ready - * @see org.springframework.boot.context.event.ApplicationReadyEvent - */ - boolean isReady(); - - /** - * Shutdown the application. - * @see org.springframework.context.ConfigurableApplicationContext#close() - */ - void shutdown(); - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleRegistrar.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleRegistrar.java deleted file mode 100644 index 198b180058d..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleRegistrar.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.autoconfigure.lifecycle; - -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; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationListener; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.util.Assert; - -/** - * Register a {@link SpringApplicationLifecycleMXBean} implementation to the platform - * {@link MBeanServer}. - * - * @author Stephane Nicoll - * @since 1.3.0 - */ -public class SpringApplicationLifecycleRegistrar implements ApplicationContextAware, InitializingBean, DisposableBean, - ApplicationListener { - - private static final Log logger = LogFactory.getLog(SpringApplicationLifecycle.class); - - private ConfigurableApplicationContext applicationContext; - - private final ObjectName objectName; - - private boolean ready = false; - - public SpringApplicationLifecycleRegistrar(String name) throws MalformedObjectNameException { - this.objectName = new ObjectName(name); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, - "ApplicationContext does not implement ConfigurableApplicationContext"); - this.applicationContext = (ConfigurableApplicationContext) applicationContext; - } - - @Override - public void onApplicationEvent(ApplicationReadyEvent event) { - ready = true; - } - - @Override - public void afterPropertiesSet() throws Exception { - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - server.registerMBean(new SpringApplicationLifecycle(), objectName); - if (logger.isDebugEnabled()) { - logger.debug("Application lifecycle MBean registered with name '" + objectName + "'"); - } - } - - @Override - public void destroy() throws Exception { - ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName); - } - - - private class SpringApplicationLifecycle implements SpringApplicationLifecycleMXBean { - - @Override - public boolean isReady() { - return ready; - } - - @Override - public void shutdown() { - logger.info("Application shutdown requested."); - applicationContext.close(); - } - } - -} - diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 45243e99b0c..059d9715f81 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -37,7 +37,6 @@ org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfig org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ -org.springframework.boot.autoconfigure.lifecycle.SpringApplicationLifecycleAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfigurationTests.java deleted file mode 100644 index 7e8574183b4..00000000000 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/lifecycle/SpringApplicationLifecycleAutoConfigurationTests.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.autoconfigure.lifecycle; - -import java.lang.management.ManagementFactory; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectInstance; -import javax.management.ObjectName; - -import org.junit.After; -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.boot.autoconfigure.jmx.JmxAutoConfiguration; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.boot.test.EnvironmentTestUtils; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.ContextRefreshedEvent; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Tests for {@link SpringApplicationLifecycleAutoConfiguration}. - * - * @author Stephane Nicoll - */ -public class SpringApplicationLifecycleAutoConfigurationTests { - - public static final String ENABLE_LIFECYCLE_PROP = "spring.application.lifecycle.enabled=true"; - - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - private AnnotationConfigApplicationContext context; - - private MBeanServer mBeanServer; - - @Before - public void setup() throws MalformedObjectNameException { - this.mBeanServer = ManagementFactory.getPlatformMBeanServer(); - } - - @After - public void tearDown() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void notRegisteredByDefault() throws MalformedObjectNameException, InstanceNotFoundException { - load(); - - 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(objectInstance); - - assertEquals("Simple context does not trigger proper event", - false, isCurrentApplicationReady(objectName)); - this.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), null, this.context)); - assertEquals("Application should be ready", - true, isCurrentApplicationReady(objectName)); - - assertTrue("context has been started", this.context.isActive()); - mBeanServer.invoke(objectName, "shutdown", null, null); - assertFalse("Context should have been closed", this.context.isActive()); - - thrown.expect(InstanceNotFoundException.class); // JMX cleanup - this.mBeanServer.getObjectInstance(objectName); - } - - @Test - public void registerWithCustomJmxName() throws InstanceNotFoundException { - String customJmxName = "org.acme:name=FooBar"; - System.setProperty(SpringApplicationLifecycleAutoConfiguration.JMX_NAME_PROPERTY, customJmxName); - try { - load(ENABLE_LIFECYCLE_PROP); - - try { - this.mBeanServer.getObjectInstance(createObjectName(customJmxName)); - } - catch (InstanceNotFoundException e) { - fail("lifecycle MBean should have been exposed with custom name"); - } - - thrown.expect(InstanceNotFoundException.class); // Should not be exposed - this.mBeanServer.getObjectInstance(createDefaultObjectName()); - } - finally { - System.clearProperty(SpringApplicationLifecycleAutoConfiguration.JMX_NAME_PROPERTY); - } - } - - @Test - public void registerWithSpringApplication() throws Exception { - final ObjectName objectName = createDefaultObjectName(); - SpringApplication application = new SpringApplication(ExampleConfig.class, - SpringApplicationLifecycleAutoConfiguration.class); - application.setWebEnvironment(false); - application.addListeners(new ApplicationListener() { - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - try { - assertFalse("Application should not be ready yet", isCurrentApplicationReady(objectName)); - } - catch (Exception e) { - throw new IllegalStateException("Could not contact spring application lifecycle bean", e); - } - } - }); - application.run("--" + ENABLE_LIFECYCLE_PROP); - assertTrue("application should be ready now", isCurrentApplicationReady(objectName)); - } - - private ObjectName createDefaultObjectName() { - return createObjectName(SpringApplicationLifecycleAutoConfiguration.DEFAULT_JMX_NAME); - } - - private ObjectName createObjectName(String jmxName) { - try { - return new ObjectName(jmxName); - } - catch (MalformedObjectNameException e) { - throw new IllegalStateException("Invalid jmx name " + jmxName, e); - } - } - - private Boolean isCurrentApplicationReady(ObjectName objectName) throws Exception { - return (Boolean) this.mBeanServer.getAttribute(objectName, "Ready"); - } - - private void load(String... environment) { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(applicationContext, environment); - applicationContext.register(JmxAutoConfiguration.class, SpringApplicationLifecycleAutoConfiguration.class); - applicationContext.refresh(); - this.context = applicationContext; - } - - - @Configuration - static class ExampleConfig { - } - -} - diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java index 3c11166c804..9515bb80846 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2014 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. @@ -48,7 +48,7 @@ class RunProcessCommand extends AbstractCommand { protected ExitStatus run(Collection args) throws IOException { this.process = new RunProcess(this.command); - int code = this.process.run(true, args.toArray(new String[args.size()])); + int code = this.process.run(args.toArray(new String[args.size()])); if (code == 0) { return ExitStatus.OK; } diff --git a/spring-boot-integration-tests/pom.xml b/spring-boot-integration-tests/pom.xml index 131b9aea835..404fce9fb26 100644 --- a/spring-boot-integration-tests/pom.xml +++ b/spring-boot-integration-tests/pom.xml @@ -21,7 +21,6 @@ spring-boot-gradle-tests - spring-boot-maven-tests spring-boot-security-tests diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/pom.xml b/spring-boot-integration-tests/spring-boot-maven-tests/pom.xml deleted file mode 100644 index be2335a755d..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-integration-tests - 1.3.0.BUILD-SNAPSHOT - - spring-boot-maven-tests - pom - Spring Boot Maven Tests - - ${basedir}/.. - - - spring-boot-maven-tests-it - spring-boot-maven-tests-it-fork - - diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/pom.xml b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/pom.xml deleted file mode 100644 index a21e17756f7..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-maven-tests - 1.3.0.BUILD-SNAPSHOT - ../ - - spring-boot-maven-tests-it-fork - Spring Boot Maven Tests - Forked Integration test - - ${basedir}/../../.. - - - - - org.springframework.boot - spring-boot-starter-web - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-tomcat-port - - reserve-network-port - - process-resources - - - tomcat.http.port - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - pre-integration-test - - start - - - - --server.port=${tomcat.http.port} - - - - - post-integration-test - - stop - - - - - true - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - ${tomcat.http.port} - - - - - - - diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/main/java/sample/IntegrationTestApplication.java b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/main/java/sample/IntegrationTestApplication.java deleted file mode 100644 index a6256ed830f..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/main/java/sample/IntegrationTestApplication.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012-2015 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 sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Stephane Nicoll - */ -@SpringBootApplication -@RestController -public class IntegrationTestApplication { - - @RequestMapping("/") - public String home() { - return "Hello World!"; - } - - public static void main(String[] args) { - SpringApplication.run(IntegrationTestApplication.class, args); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/test/java/sample/IntegrationTestApplicationIT.java b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/test/java/sample/IntegrationTestApplicationIT.java deleted file mode 100644 index 10722a1552b..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it-fork/src/test/java/sample/IntegrationTestApplicationIT.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2015 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 sample; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.web.client.RestTemplate; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; - -/** - * @author Stephane Nicoll - */ -public class IntegrationTestApplicationIT { - - private int actualServerPort; - - @Before - public void setup() { - String port = System.getProperty("test.server.port"); - assertNotNull("System property 'test.server.port' must be set", port); - this.actualServerPort = Integer.parseInt(port); - } - - @Test - public void test() { - String content = new RestTemplate().getForObject( - "http://localhost:" + actualServerPort + "/", String.class); - assertThat(content, is("Hello World!")); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/pom.xml b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/pom.xml deleted file mode 100644 index 81435ab0f27..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-maven-tests - 1.3.0.BUILD-SNAPSHOT - ../ - - spring-boot-maven-tests-it - Spring Boot Maven Tests - Integration test - - ${basedir}/../../.. - - - - - org.springframework.boot - spring-boot-starter-web - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-tomcat-port - - reserve-network-port - - process-resources - - - tomcat.http.port - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - pre-integration-test - - start - - - - --server.port=${tomcat.http.port} - - - - - post-integration-test - - stop - - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - ${tomcat.http.port} - - - - - - - diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/main/java/sample/IntegrationTestApplication.java b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/main/java/sample/IntegrationTestApplication.java deleted file mode 100644 index a6256ed830f..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/main/java/sample/IntegrationTestApplication.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012-2015 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 sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Stephane Nicoll - */ -@SpringBootApplication -@RestController -public class IntegrationTestApplication { - - @RequestMapping("/") - public String home() { - return "Hello World!"; - } - - public static void main(String[] args) { - SpringApplication.run(IntegrationTestApplication.class, args); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/test/java/sample/IntegrationTestApplicationIT.java b/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/test/java/sample/IntegrationTestApplicationIT.java deleted file mode 100644 index 10722a1552b..00000000000 --- a/spring-boot-integration-tests/spring-boot-maven-tests/spring-boot-maven-tests-it/src/test/java/sample/IntegrationTestApplicationIT.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2015 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 sample; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.web.client.RestTemplate; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; - -/** - * @author Stephane Nicoll - */ -public class IntegrationTestApplicationIT { - - private int actualServerPort; - - @Before - public void setup() { - String port = System.getProperty("test.server.port"); - assertNotNull("System property 'test.server.port' must be set", port); - this.actualServerPort = Integer.parseInt(port); - } - - @Test - public void test() { - String content = new RestTemplate().getForObject( - "http://localhost:" + actualServerPort + "/", String.class); - assertThat(content, is("Hello World!")); - } - -} 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..98f00ef387e 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2014 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. @@ -31,7 +31,6 @@ import org.springframework.util.ReflectionUtils; * @author Phillip Webb * @author Dave Syer * @author Andy Wilkinson - * @author Stephane Nicoll * @since 1.1.0 */ public class RunProcess { @@ -51,18 +50,11 @@ public class RunProcess { this.command = command; } - public int run(boolean waitForProcess, String... args) throws IOException { - return run(waitForProcess, Arrays.asList(args)); + public int run(String... args) throws IOException { + return run(Arrays.asList(args)); } - /** - * Kill this process. - */ - public void kill() { - doKill(); - } - - protected int run(boolean waitForProcess, Collection args) throws IOException { + protected int run(Collection args) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.command().addAll(args); builder.redirectErrorStream(true); @@ -79,22 +71,17 @@ public class RunProcess { handleSigInt(); } }); - if (waitForProcess) { - try { - return process.waitFor(); - } - catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - return 1; - } + try { + return process.waitFor(); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + return 1; } - return 5; } finally { - if (waitForProcess) { - this.endTime = System.currentTimeMillis(); - this.process = null; - } + this.endTime = System.currentTimeMillis(); + this.process = null; } } @@ -176,11 +163,7 @@ public class RunProcess { if (hasJustEnded()) { return true; } - return doKill(); - } - - private boolean doKill() { // destroy the running process Process process = this.process; if (process != null) { 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 deleted file mode 100644 index 563a5ddec12..00000000000 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.maven; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.CodeSource; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import org.apache.maven.artifact.Artifact; -import org.apache.maven.model.Resource; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -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; - -/** - * Base class to run a spring application. - * - * @author Phillip Webb - * @author Stephane Nicoll - * @author David Liu - * @see RunMojo - * @see StartMojo - */ -public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { - - private static final String SPRING_LOADED_AGENT_CLASSNAME = "org.springsource.loaded.agent.SpringLoadedAgent"; - - /** - * The Maven project. - * @since 1.0 - */ - @Parameter(defaultValue = "${project}", readonly = true, required = true) - private MavenProject project; - - /** - * Add maven resources to the classpath directly, this allows live in-place editing of - * resources. Duplicate resources are removed from {@code target/classes} to prevent - * them to appear twice if {@code ClassLoader.getResources()} is called. - * @since 1.0 - */ - @Parameter(property = "run.addResources", defaultValue = "true") - private boolean addResources; - - /** - * Path to agent jar. NOTE: the use of agents means that processes will be started by - * forking a new JVM. - * @since 1.0 - */ - @Parameter(property = "run.agent") - private File[] agent; - - /** - * Flag to say that the agent requires -noverify. - * @since 1.0 - */ - @Parameter(property = "run.noverify") - private Boolean noverify; - - /** - * 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. - * @since 1.1 - */ - @Parameter(property = "run.jvmArguments") - private String jvmArguments; - - /** - * Arguments that should be passed to the application. On command line use commas to - * separate multiple arguments. - * @since 1.0 - */ - @Parameter(property = "run.arguments") - private String[] arguments; - - /** - * The name of the main class. If not specified the first compiled class found that - * contains a 'main' method will be used. - * @since 1.0 - */ - @Parameter - private String mainClass; - - /** - * Additional folders besides the classes directory that should be added to the - * classpath. - * @since 1.0 - */ - @Parameter - private String[] folders; - - /** - * Directory containing the classes and resource files that should be packaged into - * the archive. - * @since 1.0 - */ - @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) - 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. - * @since 1.2 - */ - @Parameter(property = "fork") - private Boolean fork; - - /** - * Specify if the application process should be forked. - * @return {@code true} if the application process should be forked - */ - protected boolean isFork() { - return (Boolean.TRUE.equals(this.fork) - || (this.fork == null && (hasAgent() || hasJvmArgs()))); - } - - private boolean hasAgent() { - return (this.agent != null && this.agent.length > 0); - } - - private boolean hasJvmArgs() { - return (this.jvmArguments != null && this.jvmArguments.length() > 0); - } - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - final String startClassName = getStartClass(); - run(startClassName); - } - - private void findAgent() { - try { - if (this.agent == null || this.agent.length == 0) { - Class loaded = Class.forName(SPRING_LOADED_AGENT_CLASSNAME); - if (loaded != null) { - if (this.noverify == null) { - this.noverify = true; - } - CodeSource source = loaded.getProtectionDomain().getCodeSource(); - if (source != null) { - this.agent = new File[] {new File(source.getLocation().getFile())}; - } - } - } - } - catch (ClassNotFoundException ex) { - // ignore; - } - if (this.noverify == null) { - this.noverify = false; - } - } - - private void run(String startClassName) throws MojoExecutionException, MojoFailureException { - findAgent(); - if (isFork()) { - doRunWithForkedJvm(startClassName); - } - else { - if (hasAgent()) { - getLog().warn("Fork mode disabled, ignoring agent"); - } - if (hasJvmArgs()) { - getLog().warn( - "Fork mode disabled, ignoring JVM argument(s) [" - + this.jvmArguments + "]"); - } - runWithMavenJvm(startClassName, resolveApplicationArguments().asArray()); - } - } - - private void doRunWithForkedJvm(String startClassName) - throws MojoExecutionException, MojoFailureException { - List args = new ArrayList(); - addAgents(args); - addJvmArgs(args); - addClasspath(args); - args.add(startClassName); - addArgs(args); - runWithForkedJvm(args); - } - - /** - * Run with a forked VM, using the specified command line arguments. - * @param args the arguments (JVM arguments and application arguments) - * @throws MojoExecutionException - * @throws MojoFailureException - */ - protected abstract void runWithForkedJvm(List args) throws MojoExecutionException, MojoFailureException; - - - /** - * Run with the current VM, using the specified arguments. - * @param startClassName the class to run - * @param arguments the class arguments - * @throws MojoExecutionException - * @throws MojoFailureException - */ - protected abstract void runWithMavenJvm(String startClassName, String... arguments) - throws MojoExecutionException, MojoFailureException; - - /** - * Resolve the application arguments to use. - * @return a {@link RunArguments} defining the application arguments - */ - protected RunArguments resolveApplicationArguments() { - return new RunArguments(this.arguments); - } - - private void addArgs(List args) { - RunArguments applicationArguments = resolveApplicationArguments(); - Collections.addAll(args, applicationArguments.asArray()); - logArguments("Application argument(s): ", this.arguments); - } - - /** - * Resolve the JVM arguments to use. - * @return a {@link RunArguments} defining the JVM arguments - */ - protected RunArguments resolveJvmArguments() { - return new RunArguments(this.jvmArguments); - } - - private void addJvmArgs(List args) { - RunArguments jvmArguments = resolveJvmArguments(); - Collections.addAll(args, jvmArguments.asArray()); - logArguments("JVM argument(s): ", jvmArguments.asArray()); - } - - private void addAgents(List args) { - if (this.agent != null) { - getLog().info("Attaching agents: " + Arrays.asList(this.agent)); - for (File agent : this.agent) { - args.add("-javaagent:" + agent); - } - } - if (this.noverify) { - args.add("-noverify"); - } - } - - private void addClasspath(List args) throws MojoExecutionException { - try { - StringBuilder classpath = new StringBuilder(); - for (URL ele : getClassPathUrls()) { - classpath = classpath.append((classpath.length() > 0 ? File.pathSeparator - : "") + new File(ele.toURI())); - } - getLog().debug("Classpath for forked process: " + classpath); - args.add("-cp"); - args.add(classpath.toString()); - } - catch (Exception e) { - throw new MojoExecutionException("Could not build classpath", e); - } - } - - private final String getStartClass() throws MojoExecutionException { - String mainClass = this.mainClass; - if (mainClass == null) { - try { - mainClass = MainClassFinder.findSingleMainClass(this.classesDirectory); - } - catch (IOException ex) { - throw new MojoExecutionException(ex.getMessage(), ex); - } - } - if (mainClass == null) { - throw new MojoExecutionException("Unable to find a suitable main class, " - + "please add a 'mainClass' property"); - } - return mainClass; - } - - protected URL[] getClassPathUrls() throws MojoExecutionException { - try { - List urls = new ArrayList(); - addUserDefinedFolders(urls); - addResources(urls); - addProjectClasses(urls); - addDependencies(urls); - return urls.toArray(new URL[urls.size()]); - } - catch (MalformedURLException ex) { - throw new MojoExecutionException("Unable to build classpath", ex); - } - catch (IOException ex) { - throw new MojoExecutionException("Unable to build classpath", ex); - } - } - - private void addUserDefinedFolders(List urls) throws MalformedURLException { - if (this.folders != null) { - for (String folder : this.folders) { - urls.add(new File(folder).toURI().toURL()); - } - } - } - - private void addResources(List urls) throws IOException { - if (this.addResources) { - for (Resource resource : this.project.getResources()) { - File directory = new File(resource.getDirectory()); - urls.add(directory.toURI().toURL()); - FileUtils.removeDuplicatesFromOutputDirectory(this.classesDirectory, - directory); - } - } - } - - private void addProjectClasses(List urls) throws MalformedURLException { - urls.add(this.classesDirectory.toURI().toURL()); - } - - private void addDependencies(List urls) throws MalformedURLException, - MojoExecutionException { - FilterArtifacts filters = getFilters(new TestArtifactFilter()); - Set artifacts = filterDependencies(this.project.getArtifacts(), filters); - for (Artifact artifact : artifacts) { - if (artifact.getFile() != null) { - urls.add(artifact.getFile().toURI().toURL()); - } - } - } - - private void logArguments(String message, String[] args) { - StringBuffer sb = new StringBuffer(message); - for (String arg : args) { - sb.append(arg).append(" "); - } - getLog().debug(sb.toString().trim()); - } - - - private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { - public TestArtifactFilter() { - super("", Artifact.SCOPE_TEST); - } - - @Override - protected String getArtifactFeature(Artifact artifact) { - return artifact.getScope(); - } - } - - /** - * Isolated {@link ThreadGroup} to capture uncaught exceptions. - */ - class IsolatedThreadGroup extends ThreadGroup { - - private Throwable exception; - - public IsolatedThreadGroup(String name) { - super(name); - } - - @Override - public void uncaughtException(Thread thread, Throwable ex) { - if (!(ex instanceof ThreadDeath)) { - synchronized (this) { - this.exception = (this.exception == null ? ex : this.exception); - } - getLog().warn(ex); - } - } - - public synchronized void rethrowUncaughtException() throws MojoExecutionException { - if (this.exception != null) { - throw new MojoExecutionException("An exception occured while running. " - + this.exception.getMessage(), this.exception); - } - } - - } - - /** - * Runner used to launch the application. - */ - class LaunchRunner implements Runnable { - - private final String startClassName; - private final String[] args; - - public LaunchRunner(String startClassName, String... args) { - this.startClassName = startClassName; - this.args = (args != null ? args : new String[] {}); - } - - @Override - public void run() { - Thread thread = Thread.currentThread(); - ClassLoader classLoader = thread.getContextClassLoader(); - try { - Class startClass = classLoader.loadClass(this.startClassName); - Method mainMethod = startClass.getMethod("main", String[].class); - if (!mainMethod.isAccessible()) { - mainMethod.setAccessible(true); - } - mainMethod.invoke(null, new Object[] {this.args}); - } - catch (NoSuchMethodException ex) { - Exception wrappedEx = new Exception( - "The specified mainClass doesn't contain a " - + "main method with appropriate signature.", ex); - thread.getThreadGroup().uncaughtException(thread, wrappedEx); - } - catch (Exception ex) { - thread.getThreadGroup().uncaughtException(thread, ex); - } - } - - } - -} 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..dfcfe97149a 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2014 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. @@ -16,13 +16,10 @@ package org.springframework.boot.maven; -import java.util.Arrays; -import java.util.LinkedList; - import org.codehaus.plexus.util.cli.CommandLineUtils; /** - * Parse and expose arguments specified in a single string. + * Parse and expose arguments specified as {@link RunMojo} parameters. * * @author Stephane Nicoll * @since 1.1.0 @@ -31,25 +28,13 @@ class RunArguments { private static final String[] NO_ARGS = {}; - private final LinkedList args; + private final String[] args; public RunArguments(String arguments) { - this(parseArgs(arguments)); + this.args = parseArgs(arguments); } - public RunArguments(String[] args) { - this.args = new LinkedList(Arrays.asList(args)); - } - - public LinkedList getArgs() { - return args; - } - - public String[] asArray() { - return this.args.toArray(new String[this.args.size()]); - } - - private static String[] parseArgs(String arguments) { + private String[] parseArgs(String arguments) { if (arguments == null || arguments.trim().isEmpty()) { return NO_ARGS; } @@ -63,4 +48,8 @@ class RunArguments { } } + public String[] asArray() { + return this.args; + } + } 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..684b962894f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2014 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. @@ -16,16 +16,34 @@ package org.springframework.boot.maven; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLClassLoader; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Set; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Resource; 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; +import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; - +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.JavaExecutable; +import org.springframework.boot.loader.tools.MainClassFinder; import org.springframework.boot.loader.tools.RunProcess; /** @@ -33,15 +51,152 @@ import org.springframework.boot.loader.tools.RunProcess; * * @author Phillip Webb * @author Stephane Nicoll + * @author David Liu */ @Mojo(name = "run", requiresProject = true, defaultPhase = LifecyclePhase.VALIDATE, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) -public class RunMojo extends AbstractRunMojo { +public class RunMojo extends AbstractDependencyFilterMojo { + + private static final String SPRING_LOADED_AGENT_CLASSNAME = "org.springsource.loaded.agent.SpringLoadedAgent"; + + /** + * The Maven project. + * @since 1.0 + */ + @Parameter(defaultValue = "${project}", readonly = true, required = true) + private MavenProject project; + + /** + * Add maven resources to the classpath directly, this allows live in-place editing of + * resources. Duplicate resources are removed from {@code target/classes} to prevent + * them to appear twice if {@code ClassLoader.getResources()} is called. + * @since 1.0 + */ + @Parameter(property = "run.addResources", defaultValue = "true") + private boolean addResources; + + /** + * Path to agent jar. NOTE: the use of agents means that processes will be started by + * forking a new JVM. + * @since 1.0 + */ + @Parameter(property = "run.agent") + private File[] agent; + + /** + * Flag to say that the agent requires -noverify. + * @since 1.0 + */ + @Parameter(property = "run.noverify") + private Boolean noverify; + + /** + * 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. + * @since 1.1 + */ + @Parameter(property = "run.jvmArguments") + private String jvmArguments; + + /** + * Arguments that should be passed to the application. On command line use commas to + * separate multiple arguments. + * @since 1.0 + */ + @Parameter(property = "run.arguments") + private String[] arguments; + + /** + * The name of the main class. If not specified the first compiled class found that + * contains a 'main' method will be used. + * @since 1.0 + */ + @Parameter + private String mainClass; + + /** + * Additional folders besides the classes directory that should be added to the + * classpath. + * @since 1.0 + */ + @Parameter + private String[] folders; + + /** + * Directory containing the classes and resource files that should be packaged into + * the archive. + * @since 1.0 + */ + @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) + 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. + * @since 1.2 + */ + @Parameter(property = "fork") + private Boolean fork; @Override - protected void runWithForkedJvm(List args) throws MojoExecutionException { + public void execute() throws MojoExecutionException, MojoFailureException { + final String startClassName = getStartClass(); + run(startClassName); + } + + private void findAgent() { try { - new RunProcess(new JavaExecutable().toString()).run(true, args + if (this.agent == null || this.agent.length == 0) { + Class loaded = Class.forName(SPRING_LOADED_AGENT_CLASSNAME); + if (loaded != null) { + if (this.noverify == null) { + this.noverify = true; + } + CodeSource source = loaded.getProtectionDomain().getCodeSource(); + if (source != null) { + this.agent = new File[] { new File(source.getLocation().getFile()) }; + } + } + } + } + catch (ClassNotFoundException ex) { + // ignore; + } + if (this.noverify == null) { + this.noverify = false; + } + } + + private void run(String startClassName) throws MojoExecutionException { + findAgent(); + boolean hasAgent = (this.agent != null && this.agent.length > 0); + boolean hasJvmArgs = (this.jvmArguments != null && this.jvmArguments.length() > 0); + if (Boolean.TRUE.equals(this.fork) + || (this.fork == null && (hasAgent || hasJvmArgs))) { + runWithForkedJvm(startClassName); + } + else { + if (hasAgent) { + getLog().warn("Fork mode disabled, ignoring agent"); + } + if (hasJvmArgs) { + getLog().warn( + "Fork mode disabled, ignoring JVM argument(s) [" + + this.jvmArguments + "]"); + } + runWithMavenJvm(startClassName); + } + } + + private void runWithForkedJvm(String startClassName) throws MojoExecutionException { + List args = new ArrayList(); + addAgents(args); + addJvmArgs(args); + addClasspath(args); + args.add(startClassName); + addArgs(args); + try { + new RunProcess(new JavaExecutable().toString()).run(args .toArray(new String[args.size()])); } catch (Exception ex) { @@ -49,16 +204,131 @@ public class RunMojo extends AbstractRunMojo { } } - protected void runWithMavenJvm(String startClassName, String... arguments) throws MojoExecutionException { + private void runWithMavenJvm(String startClassName) throws MojoExecutionException { IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(startClassName); Thread launchThread = new Thread(threadGroup, new LaunchRunner(startClassName, - arguments), startClassName + ".main()"); + this.arguments), startClassName + ".main()"); launchThread.setContextClassLoader(new URLClassLoader(getClassPathUrls())); launchThread.start(); join(threadGroup); threadGroup.rethrowUncaughtException(); } + private void addAgents(List args) { + if (this.agent != null) { + getLog().info("Attaching agents: " + Arrays.asList(this.agent)); + for (File agent : this.agent) { + args.add("-javaagent:" + agent); + } + } + if (this.noverify) { + args.add("-noverify"); + } + } + + private void addJvmArgs(List args) { + RunArguments jvmArguments = new RunArguments(this.jvmArguments); + Collections.addAll(args, jvmArguments.asArray()); + logArguments("JVM argument(s): ", jvmArguments.asArray()); + } + + private void addClasspath(List args) throws MojoExecutionException { + try { + StringBuilder classpath = new StringBuilder(); + for (URL ele : getClassPathUrls()) { + classpath = classpath.append((classpath.length() > 0 ? File.pathSeparator + : "") + new File(ele.toURI())); + } + getLog().debug("Classpath for forked process: " + classpath); + args.add("-cp"); + args.add(classpath.toString()); + } + catch (Exception e) { + throw new MojoExecutionException("Could not build classpath", e); + } + } + + private void addArgs(List args) { + Collections.addAll(args, this.arguments); + logArguments("Application argument(s): ", this.arguments); + } + + private final String getStartClass() throws MojoExecutionException { + String mainClass = this.mainClass; + if (mainClass == null) { + try { + mainClass = MainClassFinder.findSingleMainClass(this.classesDirectory); + } + catch (IOException ex) { + throw new MojoExecutionException(ex.getMessage(), ex); + } + } + if (mainClass == null) { + throw new MojoExecutionException("Unable to find a suitable main class, " + + "please add a 'mainClass' property"); + } + return mainClass; + } + + private URL[] getClassPathUrls() throws MojoExecutionException { + try { + List urls = new ArrayList(); + addUserDefinedFolders(urls); + addResources(urls); + addProjectClasses(urls); + addDependencies(urls); + return urls.toArray(new URL[urls.size()]); + } + catch (MalformedURLException ex) { + throw new MojoExecutionException("Unable to build classpath", ex); + } + catch (IOException ex) { + throw new MojoExecutionException("Unable to build classpath", ex); + } + } + + private void addUserDefinedFolders(List urls) throws MalformedURLException { + if (this.folders != null) { + for (String folder : this.folders) { + urls.add(new File(folder).toURI().toURL()); + } + } + } + + private void addResources(List urls) throws IOException { + if (this.addResources) { + for (Resource resource : this.project.getResources()) { + File directory = new File(resource.getDirectory()); + urls.add(directory.toURI().toURL()); + FileUtils.removeDuplicatesFromOutputDirectory(this.classesDirectory, + directory); + } + } + } + + private void addProjectClasses(List urls) throws MalformedURLException { + urls.add(this.classesDirectory.toURI().toURL()); + } + + private void addDependencies(List urls) throws MalformedURLException, + MojoExecutionException { + FilterArtifacts filters = getFilters(new TestArtifactFilter()); + Set artifacts = filterDependencies(this.project.getArtifacts(), filters); + for (Artifact artifact : artifacts) { + if (artifact.getFile() != null) { + urls.add(artifact.getFile().toURI().toURL()); + } + } + } + + private void logArguments(String message, String[] args) { + StringBuffer sb = new StringBuffer(message); + for (String arg : args) { + sb.append(arg).append(" "); + } + getLog().debug(sb.toString().trim()); + } + private void join(ThreadGroup threadGroup) { boolean hasNonDaemonThreads; do { @@ -80,4 +350,84 @@ public class RunMojo extends AbstractRunMojo { while (hasNonDaemonThreads); } + private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { + public TestArtifactFilter() { + super("", Artifact.SCOPE_TEST); + } + + @Override + protected String getArtifactFeature(Artifact artifact) { + return artifact.getScope(); + } + } + + /** + * Isolated {@link ThreadGroup} to capture uncaught exceptions. + */ + class IsolatedThreadGroup extends ThreadGroup { + + private Throwable exception; + + public IsolatedThreadGroup(String name) { + super(name); + } + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!(ex instanceof ThreadDeath)) { + synchronized (this) { + this.exception = (this.exception == null ? ex : this.exception); + } + getLog().warn(ex); + } + } + + public synchronized void rethrowUncaughtException() throws MojoExecutionException { + if (this.exception != null) { + throw new MojoExecutionException("An exception occured while running. " + + this.exception.getMessage(), this.exception); + } + } + + } + + /** + * Runner used to launch the application. + */ + class LaunchRunner implements Runnable { + + private final String startClassName; + private final String[] args; + + public LaunchRunner(String startClassName, String... args) { + this.startClassName = startClassName; + this.args = (args != null ? args : new String[] {}); + } + + @Override + public void run() { + Thread thread = Thread.currentThread(); + ClassLoader classLoader = thread.getContextClassLoader(); + try { + Class startClass = classLoader.loadClass(this.startClassName); + Method mainMethod = startClass.getMethod("main", + new Class[] { String[].class }); + if (!mainMethod.isAccessible()) { + mainMethod.setAccessible(true); + } + mainMethod.invoke(null, new Object[] { this.args }); + } + catch (NoSuchMethodException ex) { + Exception wrappedEx = new Exception( + "The specified mainClass doesn't contain a " + + "main method with appropriate signature.", ex); + thread.getThreadGroup().uncaughtException(thread, wrappedEx); + } + catch (Exception ex) { + thread.getThreadGroup().uncaughtException(thread, ex); + } + } + + } + } 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 deleted file mode 100644 index df26ad9c2aa..00000000000 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.maven; - -import java.io.IOException; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanServerConnection; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.ReflectionException; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import org.apache.maven.plugin.MojoExecutionException; - -/** - * A JMX client for the {@code SpringApplicationLifecycle} mbean. Permits to obtain - * 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"; - - private final MBeanServerConnection mBeanServerConnection; - - private final ObjectName objectName; - - public SpringApplicationLifecycleClient(MBeanServerConnection mBeanServerConnection, String jmxName) { - this.mBeanServerConnection = mBeanServerConnection; - this.objectName = toObjectName(jmxName); - } - - /** - * Create a connector for an {@link javax.management.MBeanServer} exposed on the - * current machine and the current port. Security should be disabled. - * @param port the port on which the mbean server is exposed - * @return a connection - * @throws IOException if the connection to that server failed - */ - public static JMXConnector createLocalJmxConnector(int port) throws IOException { - String url = "service:jmx:rmi:///jndi/rmi://127.0.0.1:" + port + "/jmxrmi"; - JMXServiceURL serviceUrl = new JMXServiceURL(url); - return JMXConnectorFactory.connect(serviceUrl, null); - } - - /** - * 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"); - } - catch (InstanceNotFoundException e) { - return false; // Instance not available yet - } - catch (AttributeNotFoundException e) { - throw new IllegalStateException("Unexpected: attribute 'Ready' not available", e); - } - catch (ReflectionException e) { - throw new MojoExecutionException("Failed to retrieve Ready attribute", e.getCause()); - } - catch (MBeanException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - } - - /** - * Stop the application managed by this instance. - * @throws MojoExecutionException if the JMX service could not be contacted - * @throws IOException if an I/O error occurs - * @throws InstanceNotFoundException if the lifecycle mbean cannot be found - */ - public void stop() throws MojoExecutionException, IOException, InstanceNotFoundException { - try { - this.mBeanServerConnection.invoke(this.objectName, "shutdown", null, null); - } - catch (ReflectionException e) { - throw new MojoExecutionException("Shutdown failed", e.getCause()); - } - catch (MBeanException e) { - throw new MojoExecutionException("Could not invoke shutdown operation", e); - } - } - - private ObjectName toObjectName(String name) { - try { - return new ObjectName(name); - } - catch (MalformedObjectNameException ex) { - throw new IllegalArgumentException("Invalid jmx name '" + name + "'"); - } - } - -} 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 deleted file mode 100644 index d9729ff8741..00000000000 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2012-2015 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.springframework.boot.maven; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.ConnectException; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; -import javax.management.MBeanServerConnection; -import javax.management.ReflectionException; -import javax.management.remote.JMXConnector; - -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; -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. - * - * @author Stephane Nicoll - * @since 1.3.0 - * @see StopMojo - */ -@Mojo(name = "start", requiresProject = true, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST) -public class StartMojo extends AbstractRunMojo { - - private static final String ENABLE_MBEAN_PROPERTY = "--spring.application.lifecycle.enabled=true"; - - private static final String JMX_NAME_PROPERTY_PREFIX = "--spring.application.lifecycle.jmx-name="; - - /** - * 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. - */ - @Parameter - private int jmxPort = 9001; - - /** - * 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) - */ - @Parameter - private int maxAttempts = 60; - - 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); - } - - try { - waitForSpringApplication(); - } - catch (MojoExecutionException e) { - runProcess.kill(); - throw e; - } - catch (MojoFailureException e) { - runProcess.kill(); - throw e; - } - } - - @Override - protected RunArguments resolveApplicationArguments() { - RunArguments applicationArguments = super.resolveApplicationArguments(); - applicationArguments.getArgs().addLast(ENABLE_MBEAN_PROPERTY); - if (isFork()) { - applicationArguments.getArgs().addLast(JMX_NAME_PROPERTY_PREFIX + this.jmxName); - } - return applicationArguments; - } - - @Override - protected RunArguments resolveJvmArguments() { - RunArguments jvmArguments = super.resolveJvmArguments(); - 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.authenticate=false"); - remoteJmxArguments.add("-Dcom.sun.management.jmxremote.ssl=false"); - jvmArguments.getArgs().addAll(remoteJmxArguments); - } - return jvmArguments; - } - - - 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 { - SpringApplicationLifecycleClient helper = new SpringApplicationLifecycleClient( - ManagementFactory.getPlatformMBeanServer(), this.jmxName); - getLog().debug("Waiting for spring application to start..."); - for (int i = 0; i < maxAttempts; i++) { - if (helper.isReady()) { - return; - } - getLog().debug("Spring application is not ready yet, waiting " + wait + "ms (attempt " + (i + 1) + ")"); - synchronized (this.lock) { - try { - this.lock.wait(wait); - } - catch (InterruptedException e) { - 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"); - } - - private void waitForSpringApplication() throws MojoFailureException, MojoExecutionException { - try { - if (Boolean.TRUE.equals(isFork())) { - waitForForkedSpringApplication(); - } - else { - doWaitForSpringApplication(ManagementFactory.getPlatformMBeanServer()); - } - } - catch (IOException e) { - throw new MojoFailureException("Could not contact Spring Boot application", e); - } - catch (Exception e) { - throw new MojoExecutionException("Could not figure out if the application has started", e); - } - - } - - private void waitForForkedSpringApplication() throws IOException, MojoFailureException, MojoExecutionException { - final JMXConnector jmxConnector; - 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"); - } - getLog().debug("Connected to local MBeanServer at port " + this.jmxPort); - try { - MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); - doWaitForSpringApplication(mBeanServerConnection); - } - finally { - jmxConnector.close(); - } - } - catch (IOException e) { - throw e; - } - catch (Exception e) { - throw new MojoExecutionException("Failed to connect to MBean server at port " + this.jmxPort, e); - } - } - - private void doWaitForSpringApplication(MBeanServerConnection connection) - throws IOException, MojoExecutionException, MojoFailureException { - - final SpringApplicationLifecycleClient client = - new SpringApplicationLifecycleClient(connection, this.jmxName); - try { - execute(this.wait, this.maxAttempts, new RetryCallback() { - @Override - public Boolean retry() throws Exception { - boolean ready = client.isReady(); - // Wait until the app is ready - return (ready ? true : null); - } - }); - } - catch (ReflectionException e) { - throw new MojoExecutionException("Unable to retrieve Ready attribute", e.getCause()); - } - catch (Exception e) { - throw new MojoFailureException("Could not invoke shutdown operation", e); - } - } - - public T execute(long wait, int maxAttempts, RetryCallback callback) throws Exception { - getLog().debug("Waiting for spring application to start..."); - for (int i = 0; i < maxAttempts; i++) { - T result = callback.retry(); - if (result != null) { - return result; - } - getLog().debug("Spring application is not ready yet, waiting " + wait + "ms (attempt " + (i + 1) + ")"); - synchronized (this.lock) { - try { - this.lock.wait(wait); - } - catch (InterruptedException e) { - 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"); - } - - private static boolean hasCauseWithType(Throwable t, Class type) { - return type.isAssignableFrom(t.getClass()) || t.getCause() != null && hasCauseWithType(t.getCause(), type); - } - - - interface RetryCallback { - - /** - * 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 deleted file mode 100644 index e103551d593..00000000000 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2012-2015 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.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; - -import org.apache.maven.plugin.AbstractMojo; -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; - -/** - * Stop a spring application that has been started by the "start" goal. Typically invoked - * once a test suite has completed. - * - * @author Stephane Nicoll - * @since 1.3.0 - */ -@Mojo(name = "stop", requiresProject = true, defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST) -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 - */ - @Parameter(property = "fork") - private Boolean fork; - - /** - * 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. - */ - @Parameter - private int jmxPort = 9001; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - getLog().info("Stopping application..."); - try { - if (Boolean.TRUE.equals(this.fork)) { - stopForkedProcess(); - } - else { - stop(); - } - } - catch (IOException e) { - // The response won't be received as the server has died - ignoring - getLog().debug("Service is not reachable anymore (" + e.getMessage() + ")"); - } - } - - private void stop() throws IOException, MojoFailureException, MojoExecutionException { - doStop(ManagementFactory.getPlatformMBeanServer()); - } - - private void stopForkedProcess() throws IOException, MojoFailureException, MojoExecutionException { - JMXConnector jmxConnector = SpringApplicationLifecycleClient.createLocalJmxConnector(this.jmxPort); - try { - MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); - doStop(mBeanServerConnection); - } - 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); - } - } - -} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/it-random-port.apt.vm b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/it-random-port.apt.vm deleted file mode 100644 index 2acd9495686..00000000000 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/it-random-port.apt.vm +++ /dev/null @@ -1,82 +0,0 @@ - ----- - Random port for integration tests - ----- - Stephane Nicoll - ----- - 2015-04-16 - ----- - - One nice feature of the Spring Boot test integration is that it can allocate a free - port for the web application. When the <<>> goal of the plugin is used, the - Spring Boot application is started separately, making it difficult to pass the actual - port to the integration test itself. - - The example below showcases how you could achieve the same feature using the - {{{http://mojo.codehaus.org/build-helper-maven-plugin/}build-helper-plugin}}: - ---- - - ... - - ... - - ... - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-tomcat-port - - reserve-network-port - - process-resources - - - tomcat.http.port - - - - - - - ${project.groupId} - ${project.artifactId} - ${project.version} - - - pre-integration-test - - start - - - - --server.port=${tomcat.http.port} - - - - - post-integration-test - - stop - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - ${tomcat.http.port} - - - - ... - - ... - ---- - - You can now retrieve the <<>> system property in any of your integration test - to create a proper <<>> to the server. diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index 1c041ec32e7..515b38b41a0 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -19,10 +19,6 @@ Spring Boot Maven Plugin * {{{./repackage-mojo.html}spring-boot:repackage}} repackages your jar/war to be executable. - * {{{./start-mojo.html}spring-boot:start}} and {{{./stop-mojo.html}spring-boot:stop}} to manage - the lifecycle of your Spring Boot application (i.e. for integration tests). - - * Usage General instructions on how to use the Spring Boot Plugin can be found on the {{{./usage.html}usage page}}. Some @@ -46,8 +42,6 @@ Spring Boot Maven Plugin * {{{./examples/run-debug.html}Debug the application}} - * {{{./examples/it-random-port.html}Random port for integration tests}} - [] diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index 9d252b44c2c..f4e983e67ec 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -9,19 +9,8 @@ Usage - The plugin provides several goals to work with a Spring Boot application: - - * <<>>: create a jar or war file that is auto-executable. It can replace the regular artifact or can be - attached to the build lifecyle with a separate <>. - - * <<>>: run your Spring Boot application with several options to pass parameters to it. - - * <<>> and <<>>: integrate your Spring Boot application to the <<>> phase so that - the application starts before it. - - [] - - Each goal is further described below. + The plugin offers a goal for repackaging an application as an executable JAR/WAR as well as a goal + for running the application. * Repackaging an application @@ -151,49 +140,3 @@ mvn spring-boot:run in such a way that any dependency that is excluded in the plugin's configuration gets excluded from the classpath as well. See {{{./examples/exclude-dependency.html}Exclude a dependency}} for more details. - -* Working with integration tests - - While you may start your Spring Boot application very easily from your test (or test suite) itself, - it may be desirable to handle that in the build itself. To make sure that the lifecycle of you Spring - Boot application is properly managed your integration tests, you can use the <<>> and - <<>> goals as desribed below: - ---- - - ... - - ... - - ${project.groupId} - ${project.artifactId} - ${project.version} - - - pre-integration-test - - start - - - - post-integration-test - - stop - - - - - ... - - ... - ---- - - Such setup can now use the {{{http://maven.apache.org/surefire/maven-failsafe-plugin/}failsafe-plugin}} to - run your integration tests as you would expect. - - For more detailed examples of how to configure this goal see: - - * {{{./examples/it-random-port.html}Random port for integration tests}} - - [] diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index b8c6591f21b..e72b40577cf 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -10,7 +10,6 @@ -