From 83e0ea22c1adc47db0f9ebfea9336923f43dccad Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 25 Apr 2013 16:06:17 +0100 Subject: [PATCH] [bs-19] Add samples and CLI support for Spring Integration $ cd spring-bootstrap-cli $ export SPRING_HOME=target $ src/main/scripts/spring run samples/integration.groovy The big disadvantage at the moment is that there is no goo way to detect Spring Integration in the AST (at least not as good as @Enable*). So for now we are looking for @MessageEndpoint or a class name with SpringIntegration in it. [#48151147] --- .../samples/integration.groovy | 15 ++ spring-bootstrap-cli/samples/job.groovy | 2 +- spring-bootstrap-cli/samples/service.groovy | 1 - .../cli/compiler/GroovyCompiler.java | 2 + ...ingBootstrapCompilerAutoConfiguration.java | 18 ++- ...gIntegrationCompilerAutoConfiguration.java | 64 +++++++++ .../bootstrap/cli/SampleIntegrationTests.java | 12 +- .../.springBeans | 14 ++ .../dependency-reduced-pom.xml | 135 ++++++++++++++++++ .../pom.xml | 46 ++++++ .../sample/service/HelloWorldService.java | 16 +++ .../IntegrationBootstrapApplication.java | 21 +++ .../sample/service/SampleEndpoint.java | 22 +++ .../sample/service/ServiceProperties.java | 33 +++++ .../src/main/resources/application.properties | 2 + .../main/resources/integration-context.xml | 11 ++ .../IntegrationBootstrapApplicationTests.java | 60 ++++++++ spring-bootstrap/pom.xml | 5 + 18 files changed, 475 insertions(+), 4 deletions(-) create mode 100644 spring-bootstrap-cli/samples/integration.groovy create mode 100644 spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringIntegrationCompilerAutoConfiguration.java create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/.springBeans create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/dependency-reduced-pom.xml create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/pom.xml create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/HelloWorldService.java create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplication.java create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/SampleEndpoint.java create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/ServiceProperties.java create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/application.properties create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/integration-context.xml create mode 100644 spring-bootstrap-samples/spring-bootstrap-integration-sample/src/test/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplicationTests.java diff --git a/spring-bootstrap-cli/samples/integration.groovy b/spring-bootstrap-cli/samples/integration.groovy new file mode 100644 index 00000000000..5d5ce230393 --- /dev/null +++ b/spring-bootstrap-cli/samples/integration.groovy @@ -0,0 +1,15 @@ +package org.test + +@Component +class SpringIntegrationExample implements CommandLineRunner { + + def builder = new IntegrationBuilder() + def flow = builder.messageFlow { + transform {"Hello, $it!"} + } + + @Override + public void run(String... args) { + print flow.sendAndReceive("World") + } +} diff --git a/spring-bootstrap-cli/samples/job.groovy b/spring-bootstrap-cli/samples/job.groovy index b3b7a47f9c0..c2497ffdabb 100644 --- a/spring-bootstrap-cli/samples/job.groovy +++ b/spring-bootstrap-cli/samples/job.groovy @@ -1,6 +1,5 @@ package org.test -@GrabResolver(name='spring-milestone', root='http://repo.springframework.org/milestone') @Grab("org.hsqldb:hsqldb-j5:2.0.0") @Configuration @EnableBatchProcessing @@ -33,6 +32,7 @@ class JobConfig { } } +import groovy.util.logging.Log import org.springframework.util.StringUtils import groovy.util.logging.Log diff --git a/spring-bootstrap-cli/samples/service.groovy b/spring-bootstrap-cli/samples/service.groovy index 218af45fcb1..746e8a58442 100644 --- a/spring-bootstrap-cli/samples/service.groovy +++ b/spring-bootstrap-cli/samples/service.groovy @@ -1,6 +1,5 @@ package org.test -@GrabResolver(name='spring-snapshot', root='http://repo.springframework.org/snapshot') @Grab("org.springframework.bootstrap:spring-bootstrap-service:0.0.1-SNAPSHOT") @Controller diff --git a/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/GroovyCompiler.java b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/GroovyCompiler.java index b553956c27f..24e13086689 100644 --- a/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/GroovyCompiler.java +++ b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/GroovyCompiler.java @@ -33,6 +33,7 @@ import org.codehaus.groovy.control.customizers.CompilationCustomizer; import org.codehaus.groovy.control.customizers.ImportCustomizer; import org.springframework.bootstrap.cli.compiler.autoconfigure.SpringBatchCompilerAutoConfiguration; import org.springframework.bootstrap.cli.compiler.autoconfigure.SpringBootstrapCompilerAutoConfiguration; +import org.springframework.bootstrap.cli.compiler.autoconfigure.SpringIntegrationCompilerAutoConfiguration; import org.springframework.bootstrap.cli.compiler.autoconfigure.SpringMvcCompilerAutoConfiguration; /** @@ -56,6 +57,7 @@ public class GroovyCompiler { new SpringBootstrapCompilerAutoConfiguration(), new SpringMvcCompilerAutoConfiguration(), new SpringBatchCompilerAutoConfiguration(), + new SpringIntegrationCompilerAutoConfiguration(), new SpringBootstrapCompilerAutoConfiguration() }; private GroovyCompilerConfiguration configuration; diff --git a/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringBootstrapCompilerAutoConfiguration.java b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringBootstrapCompilerAutoConfiguration.java index aeb5af56b17..6243b114954 100644 --- a/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringBootstrapCompilerAutoConfiguration.java +++ b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringBootstrapCompilerAutoConfiguration.java @@ -16,8 +16,12 @@ package org.springframework.bootstrap.cli.compiler.autoconfigure; +import groovy.grape.Grape; import groovy.lang.GroovyClassLoader; +import java.util.HashMap; +import java.util.Map; + import org.codehaus.groovy.ast.AnnotationNode; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.classgen.GeneratorContext; @@ -78,9 +82,21 @@ public class SpringBootstrapCompilerAutoConfiguration extends CompilerAutoConfig public void applyToMainClass(GroovyClassLoader loader, GroovyCompilerConfiguration configuration, GeneratorContext generatorContext, SourceUnit source, ClassNode classNode) throws CompilationFailedException { - if (true) { + if (true) { // FIXME: add switch for auto config addEnableAutoConfigurationAnnotation(source, classNode); } + // FIXME: allow the extra resolvers to be switched on (off by default) + addExtraResolvers(); + } + + private void addExtraResolvers() { + Map resolver = new HashMap(); + resolver.put("name", "spring-milestone"); + resolver.put("root", "http://repo.springframework.org/milestone"); + Grape.addResolver(resolver); + resolver.put("name", "spring-snapshot"); + resolver.put("root", "http://repo.springframework.org/snapshot"); + Grape.addResolver(resolver); } private void addEnableAutoConfigurationAnnotation(SourceUnit source, diff --git a/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringIntegrationCompilerAutoConfiguration.java b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringIntegrationCompilerAutoConfiguration.java new file mode 100644 index 00000000000..a07fe762561 --- /dev/null +++ b/spring-bootstrap-cli/src/main/java/org/springframework/bootstrap/cli/compiler/autoconfigure/SpringIntegrationCompilerAutoConfiguration.java @@ -0,0 +1,64 @@ +/* + * 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.bootstrap.cli.compiler.autoconfigure; + +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.control.customizers.ImportCustomizer; +import org.springframework.bootstrap.cli.compiler.AstUtils; +import org.springframework.bootstrap.cli.compiler.CompilerAutoConfiguration; +import org.springframework.bootstrap.cli.compiler.DependencyCustomizer; + +/** + * {@link CompilerAutoConfiguration} for Spring Batch. + * + * @author Dave Syer + */ +public class SpringIntegrationCompilerAutoConfiguration extends CompilerAutoConfiguration { + + @Override + public boolean matches(ClassNode classNode) { + // Slightly weird detection algorithm because there is no @Enable annotation for + // Integration + return AstUtils.hasLeastOneAnnotation(classNode, "MessageEndpoint") + || classNode.getName().contains("SpringIntegration"); + } + + @Override + public void applyDependencies(DependencyCustomizer dependencies) { + dependencies + .ifAnyMissingClasses("org.springframework.integration.Message") + .add("org.springframework.integration", "spring-integration-core", + "2.2.3.RELEASE") + .add("org.springframework.integration", + "spring-integration-dsl-groovy-core", "1.0.0.M1"); + dependencies.ifAnyMissingClasses("groovy.util.XmlParser").add( + "org.codehaus.groovy", "groovy-xml", "2.1.3"); + } + + @Override + public void applyImports(ImportCustomizer imports) { + imports.addImports("org.springframework.integration.Message", + "org.springframework.integration.MessageChannel", + "org.springframework.integration.MessageHeaders", + "org.springframework.integration.annotation.MessageEndpoint", + "org.springframework.integration.annotation.Header", + "org.springframework.integration.annotation.Headers", + "org.springframework.integration.annotation.Payload", + "org.springframework.integration.annotation.Payloads", + "org.springframework.integration.dsl.groovy.builder.IntegrationBuilder"); + } +} diff --git a/spring-bootstrap-cli/src/test/java/org/springframework/bootstrap/cli/SampleIntegrationTests.java b/spring-bootstrap-cli/src/test/java/org/springframework/bootstrap/cli/SampleIntegrationTests.java index 02cae2ab195..c7c4e3086e2 100644 --- a/spring-bootstrap-cli/src/test/java/org/springframework/bootstrap/cli/SampleIntegrationTests.java +++ b/spring-bootstrap-cli/src/test/java/org/springframework/bootstrap/cli/SampleIntegrationTests.java @@ -55,7 +55,7 @@ public class SampleIntegrationTests { @BeforeClass public static void clean() { // SpringBootstrapCli.main("clean"); - // System.setProperty("ivy.message.logger.level", "4"); + // System.setProperty("ivy.message.logger.level", "3"); } @Test @@ -63,6 +63,11 @@ public class SampleIntegrationTests { start("samples/app.groovy"); } + @Test + public void jobSample() throws Exception { + start("samples/job.groovy"); + } + @Test public void webSample() throws Exception { start("samples/web.groovy"); @@ -73,4 +78,9 @@ public class SampleIntegrationTests { start("samples/service.groovy"); } + @Test + public void integrationSample() throws Exception { + start("samples/integration.groovy"); + } + } diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/.springBeans b/spring-bootstrap-samples/spring-bootstrap-integration-sample/.springBeans new file mode 100644 index 00000000000..51f8f5d53e2 --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/.springBeans @@ -0,0 +1,14 @@ + + + 1 + + + + + + + src/main/resources/integration-context.xml + + + + diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/dependency-reduced-pom.xml b/spring-bootstrap-samples/spring-bootstrap-integration-sample/dependency-reduced-pom.xml new file mode 100644 index 00000000000..84fbc0f02fc --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/dependency-reduced-pom.xml @@ -0,0 +1,135 @@ + + + + spring-bootstrap-samples + org.springframework.bootstrap + 0.0.1-SNAPSHOT + + 4.0.0 + spring-bootstrap-service-sample + + + + maven-shade-plugin + + + + + + tomcat + + + org.apache.tomcat.embed + tomcat-embed-core + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + + + + + jetty + + + org.eclipse.jetty + jetty-webapp + 8.1.9.v20130131 + compile + + + javax.servlet + org.eclipse.jetty.orbit + + + + + org.eclipse.jetty + jetty-jsp + 8.1.9.v20130131 + compile + + + + + juli + + + org.slf4j + slf4j-jdk14 + 1.7.2 + compile + + + + + log4j + + + org.slf4j + slf4j-log4j12 + + + log4j + log4j + + + + + logback + + + ch.qos.logback + logback-classic + + + + + + + junit + junit + 4.11 + test + + + hamcrest-core + org.hamcrest + + + + + org.mockito + mockito-core + 1.9.5 + test + + + objenesis + org.objenesis + + + hamcrest-core + org.hamcrest + + + + + org.hamcrest + hamcrest-library + 1.3 + test + + + hamcrest-core + org.hamcrest + + + + + + ${project.basedir}/../.. + org.springframework.bootstrap.sample.service.ServiceBootstrapApplication + + + diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/pom.xml b/spring-bootstrap-samples/spring-bootstrap-integration-sample/pom.xml new file mode 100644 index 00000000000..a6d8a37b751 --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + org.springframework.bootstrap + spring-bootstrap-samples + 0.0.1-SNAPSHOT + + spring-bootstrap-integration-sample + jar + + ${project.basedir}/../.. + org.springframework.bootstrap.sample.service.IntegrationBootstrapApplication + 2.2.3.RELEASE + + + + ${project.groupId} + spring-bootstrap-service + ${project.version} + + + org.springframework.integration + spring-integration-core + ${spring.integration.version} + + + org.springframework.integration + spring-integration-stream + ${spring.integration.version} + + + ch.qos.logback + logback-classic + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/HelloWorldService.java b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/HelloWorldService.java new file mode 100644 index 00000000000..6835eca0cce --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/HelloWorldService.java @@ -0,0 +1,16 @@ +package org.springframework.bootstrap.sample.service; + +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-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplication.java b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplication.java new file mode 100644 index 00000000000..b5dbc1e7e69 --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplication.java @@ -0,0 +1,21 @@ +package org.springframework.bootstrap.sample.service; + +import org.springframework.bootstrap.SpringApplication; +import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; +import org.springframework.bootstrap.service.annotation.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 +@ImportResource("integration-context.xml") +public class IntegrationBootstrapApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(IntegrationBootstrapApplication.class, args); + } + +} diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/SampleEndpoint.java b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/SampleEndpoint.java new file mode 100644 index 00000000000..3bec2bfd80e --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/SampleEndpoint.java @@ -0,0 +1,22 @@ +package org.springframework.bootstrap.sample.service; + +import java.util.Collections; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.annotation.MessageEndpoint; +import org.springframework.integration.annotation.ServiceActivator; + +@MessageEndpoint +public class SampleEndpoint { + + @Autowired + private HelloWorldService helloWorldService; + + @ServiceActivator + public Map hello(String input) { + return Collections.singletonMap("message", + this.helloWorldService.getHelloMessage(input)); + } + +} diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/ServiceProperties.java b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/ServiceProperties.java new file mode 100644 index 00000000000..68ae4f51934 --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/java/org/springframework/bootstrap/sample/service/ServiceProperties.java @@ -0,0 +1,33 @@ +/* + * 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.bootstrap.sample.service; + +import org.springframework.bootstrap.context.annotation.ConfigurationProperties; + +@ConfigurationProperties(name = "service", ignoreUnknownFields = false) +public class ServiceProperties { + + private String greeting = "Hello"; + + public String getGreeting() { + return this.greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + +} diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/application.properties b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/application.properties new file mode 100644 index 00000000000..2ec8b7cad2a --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/application.properties @@ -0,0 +1,2 @@ +logging.file: /tmp/logs/app.log +service.greeting: Hello \ No newline at end of file diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/integration-context.xml b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/integration-context.xml new file mode 100644 index 00000000000..112c2efce4e --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/main/resources/integration-context.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/test/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplicationTests.java b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/test/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplicationTests.java new file mode 100644 index 00000000000..f2669782579 --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-integration-sample/src/test/java/org/springframework/bootstrap/sample/service/IntegrationBootstrapApplicationTests.java @@ -0,0 +1,60 @@ +package org.springframework.bootstrap.sample.service; + +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.bootstrap.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.integration.Message; +import org.springframework.integration.core.MessagingTemplate; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.support.channel.BeanFactoryChannelResolver; + +import static org.junit.Assert.assertEquals; + +/** + * Basic integration tests for service demo application. + * + * @author Dave Syer + * + */ +public class IntegrationBootstrapApplicationTests { + + private static ConfigurableApplicationContext context; + + @BeforeClass + public static void start() throws Exception { + Future future = Executors + .newSingleThreadExecutor().submit( + new Callable() { + @Override + public ConfigurableApplicationContext call() throws Exception { + return (ConfigurableApplicationContext) SpringApplication + .run(IntegrationBootstrapApplication.class); + } + }); + context = future.get(10, TimeUnit.SECONDS); + } + + @AfterClass + public static void stop() { + if (context != null) { + context.close(); + } + } + + @Test + public void testVanillaExchange() throws Exception { + MessagingTemplate template = new MessagingTemplate(); + template.setChannelResolver(new BeanFactoryChannelResolver(context)); + Message result = template.sendAndReceive("input", + MessageBuilder.withPayload("Phil").build()); + assertEquals("{message=Hello Phil}", result.getPayload().toString()); + } + +} diff --git a/spring-bootstrap/pom.xml b/spring-bootstrap/pom.xml index c95633e154d..7bd43d7e57a 100644 --- a/spring-bootstrap/pom.xml +++ b/spring-bootstrap/pom.xml @@ -67,6 +67,11 @@ spring-jdbc true + + org.springframework + spring-tx + true + org.springframework spring-orm