diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java
index 1b0642cb464..abc91425bff 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.jmx;
import javax.management.MBeanServer;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@@ -26,7 +28,13 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
+import org.springframework.context.annotation.MBeanExportConfiguration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.jmx.export.MBeanExporter;
+import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
+import org.springframework.jmx.export.annotation.AnnotationMBeanExporter;
+import org.springframework.jmx.export.naming.ObjectNamingStrategy;
import org.springframework.jmx.support.MBeanServerFactoryBean;
/**
@@ -42,10 +50,33 @@ import org.springframework.jmx.support.MBeanServerFactoryBean;
@ConditionalOnExpression("${spring.jmx.enabled:true}")
public class JmxAutoConfiguration {
- @Configuration
+ @Autowired
+ private Environment environment;
+
+ @Autowired
+ private BeanFactory beanFactory;
+
+ @Autowired
+ private ObjectNamingStrategy namingStrategy;
+
+ @Bean
@ConditionalOnMissingBean(value = MBeanExporter.class, search = SearchStrategy.CURRENT)
- @EnableMBeanExport(defaultDomain = "${spring.jmx.default_domain:}", server = "${spring.jmx.server:mbeanServer}")
- public static class MBeanExport {
+ public AnnotationMBeanExporter mbeanExporter() {
+ // Re-use the @EnableMBeanExport configuration
+ MBeanExportConfiguration config = new MBeanExportConfiguration();
+ config.setEnvironment(this.environment);
+ config.setBeanFactory(this.beanFactory);
+ config.setImportMetadata(new StandardAnnotationMetadata(Empty.class));
+ // But add a custom naming strategy
+ AnnotationMBeanExporter exporter = config.mbeanExporter();
+ exporter.setNamingStrategy(this.namingStrategy);
+ return exporter;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(ObjectNamingStrategy.class)
+ public ParentAwareNamingStrategy objectNamingStrategy() {
+ return new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource());
}
@Bean
@@ -56,4 +87,9 @@ public class JmxAutoConfiguration {
return factory;
}
+ @EnableMBeanExport(defaultDomain = "${spring.jmx.default_domain:}", server = "${spring.jmx.server:mbeanServer}")
+ private static class Empty {
+
+ }
+
}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/ParentAwareNamingStrategy.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/ParentAwareNamingStrategy.java
new file mode 100644
index 00000000000..85b8ee74de3
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/ParentAwareNamingStrategy.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012-2013 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.jmx;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.jmx.export.metadata.JmxAttributeSource;
+import org.springframework.jmx.export.naming.MetadataNamingStrategy;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * @author Dave Syer
+ * @since 1.1.1
+ */
+public class ParentAwareNamingStrategy extends MetadataNamingStrategy implements
+ ApplicationContextAware {
+
+ private ApplicationContext applicationContext;
+ private boolean ensureUniqueRuntimeObjectNames = false;
+
+ public ParentAwareNamingStrategy(JmxAttributeSource attributeSource) {
+ super(attributeSource);
+ }
+
+ /**
+ * @param ensureUniqueRuntimeObjectNames the ensureUniqueRuntimeObjectNames to set
+ */
+ public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
+ this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
+ }
+
+ @Override
+ public ObjectName getObjectName(Object managedBean, String beanKey)
+ throws MalformedObjectNameException {
+ StringBuilder builder = new StringBuilder(beanKey);
+ if (parentContextContainsSameBean(this.applicationContext, beanKey)) {
+ builder.append(",context="
+ + ObjectUtils.getIdentityHexString(this.applicationContext));
+ }
+ if (this.ensureUniqueRuntimeObjectNames) {
+ builder.append(",identity=" + ObjectUtils.getIdentityHexString(managedBean));
+ }
+ ObjectName name = super.getObjectName(managedBean, beanKey);
+ return name;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext)
+ throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ private boolean parentContextContainsSameBean(ApplicationContext applicationContext,
+ String beanKey) {
+ if (applicationContext.getParent() != null) {
+ try {
+ this.applicationContext.getParent().getBean(beanKey);
+ return true;
+ }
+ catch (BeansException ex) {
+ return parentContextContainsSameBean(applicationContext.getParent(),
+ beanKey);
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java
index d3774b7344e..e47277431eb 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java
@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.integration;
import org.junit.Test;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.integration.support.channel.HeaderChannelRegistry;
@@ -29,10 +30,18 @@ import static org.junit.Assert.assertNotNull;
*/
public class IntegrationAutoConfigurationTests {
- private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Test
public void integrationIsAvailable() {
+ this.context.register(IntegrationAutoConfiguration.class);
+ this.context.refresh();
+ assertNotNull(this.context.getBean(HeaderChannelRegistry.class));
+ this.context.close();
+ }
+
+ @Test
+ public void addJmxAuto() {
this.context.register(JmxAutoConfiguration.class,
IntegrationAutoConfiguration.class);
this.context.refresh();
@@ -40,4 +49,18 @@ public class IntegrationAutoConfigurationTests {
this.context.close();
}
+ @Test
+ public void parentContext() {
+ this.context.register(IntegrationAutoConfiguration.class);
+ this.context.refresh();
+ AnnotationConfigApplicationContext parent = this.context;
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.setParent(parent);
+ this.context.register(IntegrationAutoConfiguration.class);
+ this.context.refresh();
+ assertNotNull(this.context.getBean(HeaderChannelRegistry.class));
+ ((ConfigurableApplicationContext) this.context.getParent()).close();
+ this.context.close();
+ }
+
}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java
index f1c07a1a1b2..699c878bf22 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java
@@ -21,6 +21,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -51,6 +52,9 @@ public class JmxAutoConfigurationTests {
public void tearDown() {
if (this.context != null) {
this.context.close();
+ if (this.context.getParent() != null) {
+ ((ConfigurableApplicationContext) this.context.getParent()).close();
+ }
}
}
@@ -104,6 +108,18 @@ public class JmxAutoConfigurationTests {
ReflectionTestUtils.getField(naming, "defaultDomain"));
}
+ @Test
+ public void testParentContext() {
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.register(JmxAutoConfiguration.class);
+ this.context.refresh();
+ AnnotationConfigApplicationContext parent = this.context;
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.setParent(parent);
+ this.context.register(JmxAutoConfiguration.class);
+ this.context.refresh();
+ }
+
@Configuration
public static class TestConfiguration {
diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml
index c9073459726..eb8a92b2484 100644
--- a/spring-boot-samples/pom.xml
+++ b/spring-boot-samples/pom.xml
@@ -39,6 +39,7 @@
spring-boot-sample-integration
spring-boot-sample-jetty
spring-boot-sample-liquibase
+ spring-boot-sample-parent-context
spring-boot-sample-profile
spring-boot-sample-secure
spring-boot-sample-servlet
diff --git a/spring-boot-samples/spring-boot-sample-integration/pom.xml b/spring-boot-samples/spring-boot-sample-integration/pom.xml
index b785a692e8e..7bccbd6087c 100644
--- a/spring-boot-samples/spring-boot-sample-integration/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-integration/pom.xml
@@ -23,6 +23,10 @@
org.springframework.boot
spring-boot-starter-integration
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
org.springframework.integration
spring-integration-jmx
diff --git a/spring-boot-samples/spring-boot-sample-integration/src/main/java/sample/integration/ServiceProperties.java b/spring-boot-samples/spring-boot-sample-integration/src/main/java/sample/integration/ServiceProperties.java
index b367ed44e31..1b472cc44ac 100644
--- a/spring-boot-samples/spring-boot-sample-integration/src/main/java/sample/integration/ServiceProperties.java
+++ b/spring-boot-samples/spring-boot-sample-integration/src/main/java/sample/integration/ServiceProperties.java
@@ -17,12 +17,16 @@
package sample.integration;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
@ConfigurationProperties(prefix = "service", ignoreUnknownFields = false)
+@ManagedResource
public class ServiceProperties {
private String greeting = "Hello";
+ @ManagedAttribute
public String getGreeting() {
return this.greeting;
}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/pom.xml b/spring-boot-samples/spring-boot-sample-parent-context/pom.xml
new file mode 100644
index 00000000000..6d7709f49a9
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.1.1.BUILD-SNAPSHOT
+
+ spring-boot-sample-parent-context
+ spring-boot-sample-parent-context
+ Spring Boot Integration Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter-integration
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.integration
+ spring-integration-jmx
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/HelloWorldService.java
new file mode 100644
index 00000000000..f318887c452
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/HelloWorldService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012-2013 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.parent;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class HelloWorldService {
+
+ @Autowired
+ private ServiceProperties configuration;
+
+ public String getHelloMessage(String name) {
+ return this.configuration.getGreeting() + " " + name;
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleEndpoint.java b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleEndpoint.java
new file mode 100644
index 00000000000..d17d8dfbaac
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleEndpoint.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-2013 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.parent;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.annotation.MessageEndpoint;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.util.StreamUtils;
+
+@MessageEndpoint
+public class SampleEndpoint {
+
+ @Autowired
+ private HelloWorldService helloWorldService;
+
+ @ServiceActivator
+ public String hello(File input) throws Exception {
+ FileInputStream in = new FileInputStream(input);
+ String name = new String(StreamUtils.copyToByteArray(in));
+ in.close();
+ return this.helloWorldService.getHelloMessage(name);
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleParentContextApplication.java b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleParentContextApplication.java
new file mode 100644
index 00000000000..de4b2857d07
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/SampleParentContextApplication.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2013 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.parent;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+
+@Configuration
+@EnableAutoConfiguration
+@EnableConfigurationProperties(ServiceProperties.class)
+@ComponentScan
+public class SampleParentContextApplication {
+
+ public static void main(String[] args) throws Exception {
+ new SpringApplicationBuilder(Parent.class).child(SampleParentContextApplication.class).run(args);
+ }
+
+ @EnableAutoConfiguration
+ @ImportResource("integration-context.xml")
+ protected static class Parent {
+
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/ServiceProperties.java b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/ServiceProperties.java
new file mode 100644
index 00000000000..b5481589899
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/java/sample/parent/ServiceProperties.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ * 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.parent;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+@ConfigurationProperties(prefix = "service", ignoreUnknownFields = false)
+@ManagedResource
+public class ServiceProperties {
+
+ private String greeting = "Hello";
+
+ @ManagedAttribute
+ public String getGreeting() {
+ return this.greeting;
+ }
+
+ public void setGreeting(String greeting) {
+ this.greeting = greeting;
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/application.properties
new file mode 100644
index 00000000000..f1309dd4e46
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/application.properties
@@ -0,0 +1 @@
+service.greeting: Hello
\ No newline at end of file
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/integration-context.xml b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/integration-context.xml
new file mode 100644
index 00000000000..6b8f92e816d
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/integration-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml
new file mode 100644
index 00000000000..178cf3322a0
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/consumer/SampleIntegrationApplicationTests.java b/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/consumer/SampleIntegrationApplicationTests.java
new file mode 100644
index 00000000000..0df6e46aa09
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/consumer/SampleIntegrationApplicationTests.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012-2013 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.parent.consumer;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternUtils;
+import org.springframework.util.StreamUtils;
+
+import sample.parent.SampleParentContextApplication;
+import sample.parent.producer.ProducerApplication;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Basic integration tests for service demo application.
+ *
+ * @author Dave Syer
+ */
+public class SampleIntegrationApplicationTests {
+
+ private static ConfigurableApplicationContext context;
+
+ @BeforeClass
+ public static void start() throws Exception {
+ context = SpringApplication.run(SampleParentContextApplication.class);
+ }
+
+ @AfterClass
+ public static void stop() {
+ if (context != null) {
+ context.close();
+ }
+ }
+
+ @Test
+ public void testVanillaExchange() throws Exception {
+ SpringApplication.run(ProducerApplication.class, "World");
+ String output = getOutput();
+ assertTrue("Wrong output: " + output, output.contains("Hello World"));
+ }
+
+ private String getOutput() throws Exception {
+ Future future = Executors.newSingleThreadExecutor().submit(
+ new Callable() {
+ @Override
+ public String call() throws Exception {
+ Resource[] resources = new Resource[0];
+ while (resources.length == 0) {
+ Thread.sleep(200);
+ resources = ResourcePatternUtils.getResourcePatternResolver(
+ new DefaultResourceLoader()).getResources(
+ "file:target/output/**");
+ }
+ StringBuilder builder = new StringBuilder();
+ for (Resource resource : resources) {
+ builder.append(new String(StreamUtils
+ .copyToByteArray(resource.getInputStream())));
+ }
+ return builder.toString();
+ }
+ });
+ return future.get(30, TimeUnit.SECONDS);
+ }
+}
diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/producer/ProducerApplication.java b/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/producer/ProducerApplication.java
new file mode 100644
index 00000000000..4ae50ad3d64
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-parent-context/src/test/java/sample/parent/producer/ProducerApplication.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2013 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.parent.producer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ProducerApplication implements CommandLineRunner {
+
+ @Override
+ public void run(String... args) throws Exception {
+ new File("target/input").mkdirs();
+ if (args.length > 0) {
+ FileOutputStream stream = new FileOutputStream("target/input/data"
+ + System.currentTimeMillis() + ".txt");
+ for (String arg : args) {
+ stream.write(arg.getBytes());
+ }
+ stream.flush();
+ stream.close();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(ProducerApplication.class, args);
+ }
+
+}