From 148e7b52c26601927efe3323cf93f3dc9d68ab49 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 12 May 2014 11:21:48 -0400 Subject: [PATCH] si4demo Spring Integration 4.0 Demo https://spring.io/blog/2014/05/15/webinar-replay-spring-integration-4-0-the-new-frontier --- README.md | 5 + dsl/si4demo/README.md | 37 ++++ dsl/si4demo/pom.xml | 61 +++++++ .../src/main/java/demo/Application.java | 159 ++++++++++++++++++ .../src/main/java/dsl/Application.java | 157 +++++++++++++++++ .../src/main/resources/application.yml | 6 + .../src/test/java/demo/ApplicationTests.java | 18 ++ 7 files changed, 443 insertions(+) create mode 100644 dsl/si4demo/README.md create mode 100644 dsl/si4demo/pom.xml create mode 100644 dsl/si4demo/src/main/java/demo/Application.java create mode 100644 dsl/si4demo/src/main/java/dsl/Application.java create mode 100644 dsl/si4demo/src/main/resources/application.yml create mode 100644 dsl/si4demo/src/test/java/demo/ApplicationTests.java diff --git a/README.md b/README.md index 70bc6f08..0eeeac4c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Welcome to the **Spring Integration Samples** repository which provides **50+ sa * Intermediate * Advanced * Applications +* DSL Inside of each category you'll find a **README.md** file, which will contain a more detailed description of that category. Each sample also comes with its own **README.md** file explaining further details, e.g. how to run the respective sample. @@ -33,6 +34,10 @@ Inside of each category you'll find a **README.md** file, which will contain a m Below is a short description of each category. +## DSL + +This directory holds demos/samples for Spring Integration 4.0 Java Configuration as well as the Java DSL Extension. + ## Basic This is a good place to get started. The samples here are technically motivated and demonstrate the bare minimum with regard to configuration and code to help you to get introduced to the basic concepts, API and configuration of Spring Integration. For example, if you are looking for an answer on how to wire a **Service Activator** to a **Channel** or how to apply a **Gateway** to your message exchange or how to get started with using the **MAIL** or **XML** module, this would be the right place to find a relevant sample. The bottom line is that this is a good starting point. diff --git a/dsl/si4demo/README.md b/dsl/si4demo/README.md new file mode 100644 index 00000000..1e9ecebc --- /dev/null +++ b/dsl/si4demo/README.md @@ -0,0 +1,37 @@ +#Spring Integration 4.0 Java Config/DSL Demo + +This sample is the demo used in the [Spring Integration 4.0 Webinar](https://spring.io/blog/2014/05/15/webinar-replay-spring-integration-4-0-the-new-frontier) + +It's currently using the spring-boot 1.1.0.M1 milestone so you may have to add the __repo.spring.io/repo__ repository to your settings.xml. + +There are two demo applications: + +__demo.Application__ is a Spring Boot application using Spring Integration 4.0 Java configuration features. + +__dsl.Application__ is the equivalent application using the new Java DSL that is currently being developed in the [extensions github repository](https://github.com/spring-projects/spring-integration-extensions/tree/master/spring-integration-java-dsl) + +In both cases, you can use Telnet or curl to search twitter + + + $ telnet localhost 9876 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + #springintegration + [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ... + + $ curl http://localhost:8080/foo -H"content-type:text/plain" -d '#springintegration' + [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ... + +The DSL version also accepts typing in a hashtag for the search in the console. The DSL version also adds a filter to only allow hashtags starting with `#spring`, and only returns the first tweet. + +Twitter now requires authentication to perform searches; visit the [twitter developer site](http://dev.twitter.com) to set up the application and enter the keys/secrets in _application.yml_ on the classpath. An 'empty' yaml file is provided in _src/main/resources: + + twitter: + oauth: + consumerKey: + consumerSecret: + accessToken: + accessTokenSecret: + + diff --git a/dsl/si4demo/pom.xml b/dsl/si4demo/pom.xml new file mode 100644 index 00000000..806e9ab9 --- /dev/null +++ b/dsl/si4demo/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + org.springframework.integration + si4demo + 0.0.1-SNAPSHOT + + demo + Demo project + + + org.springframework.boot + spring-boot-starter-parent + 1.1.0.M1 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-integration + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.integration + spring-integration-twitter + 4.0.0.RELEASE + + + org.springframework.integration + spring-integration-java-dsl + 1.0.0.M1 + + + + + UTF-8 + demo.Application + 1.7 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/dsl/si4demo/src/main/java/demo/Application.java b/dsl/si4demo/src/main/java/demo/Application.java new file mode 100644 index 00000000..6ff67d99 --- /dev/null +++ b/dsl/si4demo/src/main/java/demo/Application.java @@ -0,0 +1,159 @@ +/* + * Copyright 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 demo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.annotation.Transformer; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway; +import org.springframework.integration.http.inbound.RequestMapping; +import org.springframework.integration.ip.tcp.TcpInboundGateway; +import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory; +import org.springframework.integration.json.ObjectToJsonTransformer; +import org.springframework.integration.transformer.ObjectToStringTransformer; +import org.springframework.integration.twitter.outbound.TwitterSearchOutboundGateway; +import org.springframework.messaging.MessageChannel; +import org.springframework.social.twitter.api.Twitter; +import org.springframework.social.twitter.api.impl.TwitterTemplate; + +/** + * + * Spring Boot app offering telnet and http access to twitter search. Uses + * Spring Integration 4.0 Java Configuration. + * + *
+ * $ telnet localhost 9876
+ * Trying 127.0.0.1...
+ * Connected to localhost.
+ * Escape character is '^]'.
+ * #springintegration
+ * [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ...
+ * 
+ * + *
+ * $ curl http://localhost:8080/foo -H"content-type:text/plain" -d '#springintegration'
+ * [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ...
+ * 
+ * + * @author Gary Russell + * @since 4.0 + * + */ +@Configuration +@ComponentScan +@EnableAutoConfiguration +public class Application { + + public static void main(String[] args) throws Exception { + ConfigurableApplicationContext ctx = SpringApplication.run(Application.class); + System.in.read(); + ctx.close(); + } + + @Autowired + private Environment env; + + @Bean + TcpNetServerConnectionFactory cf() { + return new TcpNetServerConnectionFactory(9876); + } + + @Bean + TcpInboundGateway tcpGate() { + TcpInboundGateway gateway = new TcpInboundGateway(); + gateway.setConnectionFactory(cf()); + gateway.setRequestChannel(requestChannel()); + return gateway; + } + + @Bean + public HttpRequestHandlingMessagingGateway httpGate() { + HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + RequestMapping mapping = new RequestMapping(); + mapping.setMethods(HttpMethod.POST); + mapping.setPathPatterns("/foo"); + gateway.setRequestMapping(mapping); + gateway.setRequestChannel(requestChannel()); + gateway.setRequestPayloadType(byte[].class); + return gateway; + } + + @Bean + public MessageChannel requestChannel() { + return new DirectChannel(); + } + +/* + * This was the first demonstration - an echo service before + * we added twitter. + */ +// @MessageEndpoint +// public static class Echo { +// +// @ServiceActivator(inputChannel="requestChannel") +// public String echo(byte[] in) { +// return "echo:" + new String(in); +// } +// } + + @Bean + @Transformer(inputChannel="requestChannel", outputChannel="searchChannel") + public org.springframework.integration.transformer.Transformer converttoString() { + return new ObjectToStringTransformer(); + } + + @Bean + public MessageChannel searchChannel() { + return new DirectChannel(); + } + + @Bean + @ServiceActivator(inputChannel="searchChannel") + public TwitterSearchOutboundGateway twitterGate() { + TwitterSearchOutboundGateway gateway = new TwitterSearchOutboundGateway(twitter()); + gateway.setOutputChannel(toJsonChannel()); + return gateway; + } + + @Bean + public MessageChannel toJsonChannel() { + return new DirectChannel(); + } + + @Bean + @Transformer(inputChannel="toJsonChannel") + public org.springframework.integration.transformer.Transformer converttoJson() { + return new ObjectToJsonTransformer(); + } + + @Bean + public Twitter twitter() { + return new TwitterTemplate(env.getProperty("twitter.oauth.consumerKey"), + env.getProperty("twitter.oauth.consumerSecret"), + env.getProperty("twitter.oauth.accessToken"), + env.getProperty("twitter.oauth.accessTokenSecret")); + } + +} diff --git a/dsl/si4demo/src/main/java/dsl/Application.java b/dsl/si4demo/src/main/java/dsl/Application.java new file mode 100644 index 00000000..42c763b2 --- /dev/null +++ b/dsl/si4demo/src/main/java/dsl/Application.java @@ -0,0 +1,157 @@ +/* + * Copyright 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 dsl; + +import java.util.Scanner; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; +import org.springframework.integration.annotation.IntegrationComponentScan; +import org.springframework.integration.annotation.MessagingGateway; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.dsl.IntegrationFlow; +import org.springframework.integration.dsl.IntegrationFlows; +import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway; +import org.springframework.integration.http.inbound.RequestMapping; +import org.springframework.integration.ip.tcp.TcpInboundGateway; +import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory; +import org.springframework.integration.json.ObjectToJsonTransformer; +import org.springframework.integration.transformer.ObjectToStringTransformer; +import org.springframework.integration.twitter.outbound.TwitterSearchOutboundGateway; +import org.springframework.messaging.MessageChannel; +import org.springframework.social.twitter.api.Twitter; +import org.springframework.social.twitter.api.impl.TwitterTemplate; + +/** + * + * Spring Boot app offering telnet and http access to twitter search. Uses the Spring Integration 4.0 Java DSL extension. + * Adds a filter and only returns the first tweet. + * + *
+ * $ telnet localhost 9876
+ * Trying 127.0.0.1...
+ * Connected to localhost.
+ * Escape character is '^]'.
+ * #springintegration
+ * [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ...
+ * 
+ * + *
+ * $ curl http://localhost:8080/foo -H"content-type:text/plain" -d '#springintegration'
+ * [{"extraData":{},"id":461548132401438720,"text":"RT @gprussell: Spring Integration 4.0.0.RELEASE is out! ...
+ * 
+ * + * It also supports typing a hashtag into the console. + * @author Gary Russell + * @since 4.0 + * + */ +@Configuration +@ComponentScan +@IntegrationComponentScan +@EnableAutoConfiguration +public class Application { + + public static void main(String[] args) throws Exception { + ConfigurableApplicationContext ctx = SpringApplication.run(Application.class); + Scanner scanner = new Scanner(System.in); + String hashTag = scanner.nextLine(); + System.out.println(ctx.getBean(Gateway.class).sendReceive(hashTag)); + scanner.close(); + ctx.close(); + } + + @MessagingGateway(defaultRequestChannel="requestChannel") + public interface Gateway { + + String sendReceive(String in); + + } + + @Autowired + private Environment env; + + @Bean + TcpNetServerConnectionFactory cf() { + return new TcpNetServerConnectionFactory(9876); + } + + @Bean + TcpInboundGateway tcpGate() { + TcpInboundGateway gateway = new TcpInboundGateway(); + gateway.setConnectionFactory(cf()); + gateway.setRequestChannel(requestChannel()); + return gateway; + } + + @Bean + public HttpRequestHandlingMessagingGateway httpGate() { + HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + RequestMapping mapping = new RequestMapping(); + mapping.setMethods(HttpMethod.POST); + mapping.setPathPatterns("/foo"); + gateway.setRequestMapping(mapping); + gateway.setRequestChannel(requestChannel()); + gateway.setRequestPayloadType(byte[].class); + return gateway; + } + + @Bean + public MessageChannel requestChannel() { + return new DirectChannel(); + } + + @Bean + public IntegrationFlow flow() { + return IntegrationFlows.from("requestChannel") + .transform(new ObjectToStringTransformer()) + .filter((String p) -> p.startsWith("#spring"), + f -> f.discardChannel("rejected")) + .handle(twitterGate()) + .transform("payload[0]") + .transform(new ObjectToJsonTransformer()) + .get(); + } + + @Bean + public IntegrationFlow errorFlow() { + return IntegrationFlows.from("rejected") + .transform("'Error: hashtag must start with #spring; got' + payload") + .get(); + } + + @Bean + public TwitterSearchOutboundGateway twitterGate() { + TwitterSearchOutboundGateway gateway = new TwitterSearchOutboundGateway(twitter()); + return gateway; + } + + @Bean + public Twitter twitter() { + return new TwitterTemplate(env.getProperty("twitter.oauth.consumerKey"), + env.getProperty("twitter.oauth.consumerSecret"), + env.getProperty("twitter.oauth.accessToken"), + env.getProperty("twitter.oauth.accessTokenSecret")); + } + +} diff --git a/dsl/si4demo/src/main/resources/application.yml b/dsl/si4demo/src/main/resources/application.yml new file mode 100644 index 00000000..1e769b81 --- /dev/null +++ b/dsl/si4demo/src/main/resources/application.yml @@ -0,0 +1,6 @@ +twitter: + oauth: + consumerKey: + consumerSecret: + accessToken: + accessTokenSecret: diff --git a/dsl/si4demo/src/test/java/demo/ApplicationTests.java b/dsl/si4demo/src/test/java/demo/ApplicationTests.java new file mode 100644 index 00000000..b4f14b77 --- /dev/null +++ b/dsl/si4demo/src/test/java/demo/ApplicationTests.java @@ -0,0 +1,18 @@ +package demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Application.class) +@WebAppConfiguration +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +}