diff --git a/pom.xml b/pom.xml
index 9cd0fbe58c..e21afb6da1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,7 @@
7.0.42
8.1.9.v20130131
1.7.3
+ 1.0.0.M1
http://github.com/SpringSource/spring-bootstrap
@@ -432,6 +433,11 @@
hsqldb
2.2.9
+
+ org.projectreactor
+ reactor-spring
+ ${reactor.version}
+
org.mockito
mockito-core
diff --git a/spring-autoconfigure/pom.xml b/spring-autoconfigure/pom.xml
index fa7a2a6d09..5dc7022bed 100644
--- a/spring-autoconfigure/pom.xml
+++ b/spring-autoconfigure/pom.xml
@@ -110,6 +110,11 @@
thymeleaf-extras-springsecurity3
true
+
+ org.projectreactor
+ reactor-spring
+ true
+
${project.groupId}
diff --git a/spring-autoconfigure/src/main/java/org/springframework/autoconfigure/reactor/ReactorAutoConfiguration.java b/spring-autoconfigure/src/main/java/org/springframework/autoconfigure/reactor/ReactorAutoConfiguration.java
new file mode 100644
index 0000000000..dd98cdadef
--- /dev/null
+++ b/spring-autoconfigure/src/main/java/org/springframework/autoconfigure/reactor/ReactorAutoConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * 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.autoconfigure.reactor;
+
+import org.springframework.autoconfigure.AutoConfigureAfter;
+import org.springframework.autoconfigure.web.WebMvcAutoConfiguration;
+import org.springframework.bootstrap.context.condition.ConditionalOnClass;
+import org.springframework.bootstrap.context.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+
+import reactor.core.Environment;
+import reactor.core.Reactor;
+import reactor.spring.context.ConsumerBeanPostProcessor;
+
+/**
+ * @author Dave Syer
+ */
+@Configuration
+@ConditionalOnClass(Reactor.class)
+@ConditionalOnMissingBean(Reactor.class)
+@AutoConfigureAfter(WebMvcAutoConfiguration.class)
+public class ReactorAutoConfiguration {
+
+ @Bean
+ public Environment reactorEnvironment() {
+ return new Environment(); // TODO: use Spring Environment to configure?
+ }
+
+ @Bean
+ public Reactor rootReactor() {
+ return reactorEnvironment().getRootReactor();
+ }
+
+ @Bean
+ @Order(Ordered.LOWEST_PRECEDENCE)
+ protected ConsumerBeanPostProcessor reactorConsumerBeanPostProcessor() {
+ return new ConsumerBeanPostProcessor();
+ }
+
+}
diff --git a/spring-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-autoconfigure/src/main/resources/META-INF/spring.factories
index 8c5efd0348..ae06447374 100644
--- a/spring-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -7,6 +7,7 @@ org.springframework.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
org.springframework.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
+org.springframework.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.autoconfigure.web.ServerPropertiesAutoConfiguration,\
diff --git a/spring-autoconfigure/src/test/java/org/springframework/autoconfigure/reactor/ReactorAutoConfigurationTests.java b/spring-autoconfigure/src/test/java/org/springframework/autoconfigure/reactor/ReactorAutoConfigurationTests.java
new file mode 100644
index 0000000000..c53a418191
--- /dev/null
+++ b/spring-autoconfigure/src/test/java/org/springframework/autoconfigure/reactor/ReactorAutoConfigurationTests.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 org.springframework.autoconfigure.reactor;
+
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+import reactor.core.Reactor;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Dave Syer
+ */
+public class ReactorAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+
+ @Test
+ public void reactorIsAvailable() {
+ this.context.register(ReactorAutoConfiguration.class);
+ this.context.refresh();
+ assertNotNull(this.context.getBean(Reactor.class));
+ this.context.close();
+ }
+
+}
diff --git a/spring-cli/samples/reactor.groovy b/spring-cli/samples/reactor.groovy
new file mode 100644
index 0000000000..9b1ebd84bc
--- /dev/null
+++ b/spring-cli/samples/reactor.groovy
@@ -0,0 +1,21 @@
+package org.test
+
+@EnableReactor
+@Log
+class Runner implements CommandLineRunner {
+
+ @Autowired
+ Reactor reactor
+
+ void run(String... args) {
+ reactor.notify("hello", Event.wrap("Phil"))
+ log.info "Notified Phil"
+ }
+
+ @On(reactor="reactor", selector="hello")
+ void receive(Event event) {
+ log.info "Hello ${event.data}"
+ }
+}
+
+
diff --git a/spring-cli/src/main/java/org/springframework/cli/compiler/autoconfigure/ReactorCompilerAutoConfiguration.java b/spring-cli/src/main/java/org/springframework/cli/compiler/autoconfigure/ReactorCompilerAutoConfiguration.java
new file mode 100644
index 0000000000..69d029aa4a
--- /dev/null
+++ b/spring-cli/src/main/java/org/springframework/cli/compiler/autoconfigure/ReactorCompilerAutoConfiguration.java
@@ -0,0 +1,67 @@
+/*
+ * 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.cli.compiler.autoconfigure;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.control.customizers.ImportCustomizer;
+import org.springframework.cli.compiler.AstUtils;
+import org.springframework.cli.compiler.CompilerAutoConfiguration;
+import org.springframework.cli.compiler.DependencyCustomizer;
+
+/**
+ * {@link CompilerAutoConfiguration} for the Recator.
+ *
+ * @author Dave Syer
+ */
+public class ReactorCompilerAutoConfiguration extends CompilerAutoConfiguration {
+
+ @Override
+ public boolean matches(ClassNode classNode) {
+ return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableReactor");
+ }
+
+ @Override
+ public void applyDependencies(DependencyCustomizer dependencies) {
+ dependencies
+ .ifAnyMissingClasses("org.reactor.Reactor")
+ .add("org.projectreactor", "reactor-spring",
+ dependencies.getProperty("reactor.version"), false)
+ .add("org.projectreactor", "reactor-core",
+ dependencies.getProperty("reactor.version"));
+ }
+
+ @Override
+ public void applyImports(ImportCustomizer imports) {
+ imports.addImports("reactor.core.Reactor", "reactor.event.Event",
+ "reactor.spring.context.annotation.On",
+ "reactor.spring.context.annotation.Reply",
+ EnableReactor.class.getCanonicalName());
+ }
+
+ @Target(ElementType.TYPE)
+ @Documented
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface EnableReactor {
+
+ }
+}
diff --git a/spring-cli/src/main/resources/META-INF/services/org.springframework.cli.compiler.CompilerAutoConfiguration b/spring-cli/src/main/resources/META-INF/services/org.springframework.cli.compiler.CompilerAutoConfiguration
index c42fcbfc78..208fd86164 100644
--- a/spring-cli/src/main/resources/META-INF/services/org.springframework.cli.compiler.CompilerAutoConfiguration
+++ b/spring-cli/src/main/resources/META-INF/services/org.springframework.cli.compiler.CompilerAutoConfiguration
@@ -1,5 +1,6 @@
org.springframework.cli.compiler.autoconfigure.SpringCompilerAutoConfiguration
org.springframework.cli.compiler.autoconfigure.SpringMvcCompilerAutoConfiguration
org.springframework.cli.compiler.autoconfigure.SpringBatchCompilerAutoConfiguration
+org.springframework.cli.compiler.autoconfigure.ReactorCompilerAutoConfiguration
org.springframework.cli.compiler.autoconfigure.SpringIntegrationCompilerAutoConfiguration
org.springframework.cli.compiler.autoconfigure.SpringSecurityCompilerAutoConfiguration
diff --git a/spring-cli/src/main/resources/META-INF/springcli.properties b/spring-cli/src/main/resources/META-INF/springcli.properties
index 92129e177f..353e4c6b8f 100644
--- a/spring-cli/src/main/resources/META-INF/springcli.properties
+++ b/spring-cli/src/main/resources/META-INF/springcli.properties
@@ -5,4 +5,5 @@ spring.security.version: ${spring.security.version}
spring.integration.version: ${spring.integration.version}
groovy.version: ${groovy.version}
jetty.version: ${jetty.version}
-tomcat.version: ${tomcat.version}
\ No newline at end of file
+tomcat.version: ${tomcat.version}
+reactor.version: ${reactor.version}
\ No newline at end of file
diff --git a/spring-cli/src/test/java/org/springframework/cli/SampleIntegrationTests.java b/spring-cli/src/test/java/org/springframework/cli/SampleIntegrationTests.java
index dedd2a1fb1..10f1ec8918 100644
--- a/spring-cli/src/test/java/org/springframework/cli/SampleIntegrationTests.java
+++ b/spring-cli/src/test/java/org/springframework/cli/SampleIntegrationTests.java
@@ -117,6 +117,18 @@ public class SampleIntegrationTests {
output.contains("completed with the following parameters"));
}
+ @Test
+ public void reactorSample() throws Exception {
+ start("samples/reactor.groovy", "Phil");
+ String output = getOutput();
+ int count = 0;
+ while (!output.contains("Hello Phil") && count++ < 5) {
+ Thread.sleep(200);
+ output = getOutput();
+ }
+ assertTrue("Wrong output: " + output, output.contains("Hello Phil"));
+ }
+
@Test
public void jobWebSample() throws Exception {
start("samples/job.groovy", "samples/web.groovy", "foo=bar");
diff --git a/spring-cli/src/test/resources/logback.xml b/spring-cli/src/test/resources/logback.xml
index 8232e3a3cb..407f13b26a 100644
--- a/spring-cli/src/test/resources/logback.xml
+++ b/spring-cli/src/test/resources/logback.xml
@@ -14,6 +14,6 @@
-
+
diff --git a/spring-zero-samples/spring-zero-sample-web-ui/pom.xml b/spring-zero-samples/spring-zero-sample-web-ui/pom.xml
index 6ae465bd3e..fe64c8eba5 100644
--- a/spring-zero-samples/spring-zero-sample-web-ui/pom.xml
+++ b/spring-zero-samples/spring-zero-sample-web-ui/pom.xml
@@ -26,6 +26,10 @@
nz.net.ultraq.thymeleaf
thymeleaf-layout-dialect
+