Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This guide walks you through the process of using Spring Integration to create a

== What you'll build

You'll create a flow using Spring Integration.
You'll create a flow with Spring Integration using traditional XML configuration.

== What you'll need

Expand Down Expand Up @@ -59,9 +59,15 @@ This simple flow is illustrated like this:

image::images/blogToFile.png[A flow that reads RSS feed entries, transforms them to a String, and appends them to a file.]

Ignore the `auto-startup` attribute for now; we'll revisit that later when discussing testing; just notice that it will be `true` by default which means the posts will be fetched when the application starts.
Also note the property placeholder in the `filename-generator-expression`; this means the default will be `SpringBlog` but can be overridden with a property

== Make the application executable

Although it is common to configure a Spring Integration flow within a larger application, perhaps even a web application, there's no reason that it can't be defined in a simpler standalone application. That's what you do next, creating a main class that kicks off the integration flow and also declares a handful of beans to support the integration flow. You also build the application into a standalone executable JAR file. We use Spring Boot's `SpringApplication` to create the application context.
Although it is common to configure a Spring Integration flow within a larger application, perhaps even a web application, there's no reason that it can't be defined in a simpler standalone application.
That's what you do next, creating a main class that kicks off the integration flow and also declares a handful of beans to support the integration flow. You also build the application into a standalone executable JAR file.
We use Spring Boot's `SpringApplication` to create the application context.
Since this guide uses an the XML namespace for the integration flow, notice that we use `@ImportResource` to load it into the application context.


`src/main/java/hello/Application.java`
Expand Down Expand Up @@ -100,8 +106,29 @@ Spring Integration Java DSL: Line by line tutorial @ https://spring.io/blog/2014
Spring for Apache Hadoop 2.1.0.M2 Released @ https://spring.io/blog/2014/11/14/spring-for-apache-hadoop-2-1-0-m2-released
....

== Testing

Examine the `complete` project and you will see a test case.

`src/test/java/hello/FlowTests.java`
[source,java]
----
include::complete/src/test/java/hello/FlowTests.java[]
----

This uses Spring Boot's test support to set a property `auto.startup` to `false`.
It is generally not a good idea to rely on a network connection for tests, especially in a CI environment.
So, instead, we prevent the feed adapter from starting and inject a `SyndEntry` into the `news` channel for processing by the rest of the flow.
The test also sets the `feed.file.name` so the test writes to a different file; then:

- verifies the adapter is stopped
- creates a test `SyndEntry`
- deletes the test output file (if it's present)
- sends the message
- verifies the file exists
- reads the file and verifies that the data is as expected

== Summary
Congratulations! You have developed a simple application that uses Spring Integration to fetch blog posts from spring.io, process them, and write them to a file.

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/footer.adoc[]

1 change: 1 addition & 0 deletions complete/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
compile("org.springframework.boot:spring-boot-starter-integration")
compile("org.springframework.integration:spring-integration-feed")
compile("org.springframework.integration:spring-integration-file")
testCompile("org.springframework.boot:spring-boot-starter-test")
testCompile("junit:junit")
}

Expand Down
6 changes: 6 additions & 0 deletions complete/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>


Expand Down
6 changes: 5 additions & 1 deletion complete/src/main/java/hello/Application.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource("/hello/integration.xml")
public class Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = new SpringApplication("/hello/integration.xml").run(args);
ConfigurableApplicationContext ctx = new SpringApplication(Application.class).run(args);
System.out.println("Hit Enter to terminate");
System.in.read();
ctx.close();
Expand Down
6 changes: 3 additions & 3 deletions complete/src/main/resources/hello/integration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">

<feed:inbound-channel-adapter id="news" url="https://spring.io/blog.atom">
<feed:inbound-channel-adapter id="news" url="http://spring.io/blog.atom" auto-startup="${auto.startup:true}">
<int:poller fixed-rate="5000"/>
</feed:inbound-channel-adapter>

<int:transformer
<int:transformer
input-channel="news"
expression="payload.title + ' @ ' + payload.link + '#{systemProperties['line.separator']}'"
output-channel="file"/>
Expand All @@ -22,6 +22,6 @@
mode="APPEND"
charset="UTF-8"
directory="/tmp/si"
filename-generator-expression="'SpringBlog'"/>
filename-generator-expression="'${feed.file.name:SpringBlog}'"/>

</beans>
50 changes: 50 additions & 0 deletions complete/src/test/java/hello/FlowTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package hello;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.context.junit4.SpringRunner;

import com.rometools.rome.feed.synd.SyndEntryImpl;

@RunWith(SpringRunner.class)
@SpringBootTest({ "auto.startup=false", // we don't want to start the real feed
"feed.file.name=Test" }) // use a different file
public class FlowTests {

@Autowired
private SourcePollingChannelAdapter newsAdapter;

@Autowired
private MessageChannel news;

@Test
public void test() throws Exception {
assertThat(this.newsAdapter.isRunning()).isFalse();
SyndEntryImpl syndEntry = new SyndEntryImpl();
syndEntry.setTitle("Test Title");
syndEntry.setLink("http://foo/bar");
File out = new File("/tmp/si/Test");
out.delete();
assertThat(out.exists()).isFalse();
this.news.send(MessageBuilder.withPayload(syndEntry).build());
assertThat(out.exists()).isTrue();
BufferedReader br = new BufferedReader(new FileReader(out));
String line = br.readLine();
assertThat(line).isEqualTo("Test Title @ http://foo/bar");
br.close();
out.delete();
}

}
1 change: 1 addition & 0 deletions initial/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
compile("org.springframework.boot:spring-boot-starter-integration")
compile("org.springframework.integration:spring-integration-feed")
compile("org.springframework.integration:spring-integration-file")
testCompile("org.springframework.boot:spring-boot-starter-test")
testCompile("junit:junit")
}

Expand Down
6 changes: 6 additions & 0 deletions initial/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>


Expand Down