INTSAMPLES-39 Dynamic FTP Router
Demonstrates the use of Spring 3.1 to instantiate multiple application contexts, each with a differently configured ftp outbound adapter, together with a POJO Channel resolver used to send messages to the appropriate context.
This commit is contained in:
69
advanced/dynamic-ftp/pom.xml
Normal file
69
advanced/dynamic-ftp/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.integration.samples</groupId>
|
||||
<artifactId>dynamic-ftp</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<name>Dynamic FTP Demo</name>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<spring.framework.version>3.1.0.RELEASE</spring.framework.version>
|
||||
<spring.integration.version>2.1.0.RC1</spring.integration.version>
|
||||
<log4j.version>1.2.16</log4j.version>
|
||||
<junit.version>4.7</junit.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-ftp</artifactId>
|
||||
<version>${spring.integration.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<!-- test-scoped dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
<compilerArgument>-Xlint:all</compilerArgument>
|
||||
<showWarnings>true</showWarnings>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>repository.springframework.maven.release</id>
|
||||
<name>Spring Framework Maven Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>repository.springframework.maven.milestone</id>
|
||||
<name>Spring Framework Maven Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>repository.springframework.maven.snapshot</id>
|
||||
<name>Spring Framework Maven Snapshot Repository</name>
|
||||
<url>http://maven.springframework.org/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
28
advanced/dynamic-ftp/readme.txt
Normal file
28
advanced/dynamic-ftp/readme.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
This example demonstrates one technique for sending files to dynamic destinations.
|
||||
|
||||
See DynamicFtpChannelResolver. The resolve() method maps a customer to a
|
||||
channel, where the channel is defined in a separate application context
|
||||
for each customer. The application context property placeholders are configured
|
||||
using the Spring 3.1 Environment management by supplying a custom property
|
||||
source.
|
||||
|
||||
A real implementation would provide these properties based on the customer; this
|
||||
sample simply uses the customer as part of the host name.
|
||||
|
||||
The application context is loaded from the file in src/main/resources/...
|
||||
|
||||
DynamicFtpChannelResolverTests is a simple JUnit test case that verifies
|
||||
the same channel is used for the same customer each time, and that a
|
||||
different channel is used for a different customer.
|
||||
|
||||
FtpOutboundChannelAdapterSample shows how messages sent with a different customer
|
||||
header are routed to a different ftp adapter. It simply verifies that the
|
||||
correct UnknownHostException is returned.
|
||||
|
||||
Notice in the config file how an expression-based router is used to invoke
|
||||
the DynamicFtpChannelResolver to obtain a reference to the appropriate
|
||||
channel for the customer. Notice that the channel resolver is a simple
|
||||
POJO, invoked using SpEL...
|
||||
|
||||
<int:router input-channel="toDynRouter"
|
||||
expression="@channelResolver.resolve(headers['customer'])"/>
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.integration.samples.ftp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
|
||||
/**
|
||||
* Demonstrates how a dynamic Spring Integration flow snippet can be used
|
||||
* to send files to dynamic destinations.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
public class DynamicFtpChannelResolver {
|
||||
|
||||
private final Map<String, MessageChannel> channels = new HashMap<String, MessageChannel>();
|
||||
|
||||
/**
|
||||
* Resolve a customer to a channel, where each customer gets a private
|
||||
* application context and the channel is the inbound channel to that
|
||||
* application context.
|
||||
*
|
||||
* @param customer
|
||||
* @return a channel
|
||||
*/
|
||||
public MessageChannel resolve(String customer) {
|
||||
MessageChannel channel = this.channels.get(customer);
|
||||
if (channel == null) {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] { "/META-INF/spring/integration/dynamic-ftp-outbound-adapter-context.xml" },
|
||||
false);
|
||||
this.setEnvironmentForCustomer(ctx, customer);
|
||||
ctx.refresh();
|
||||
channel = ctx.getBean("toFtpChannel", MessageChannel.class);
|
||||
this.channels.put(customer, channel);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Spring 3.1. environment support to set properties for the
|
||||
* customer-specific application context.
|
||||
*
|
||||
* @param ctx
|
||||
* @param customer
|
||||
*/
|
||||
private void setEnvironmentForCustomer(ConfigurableApplicationContext ctx,
|
||||
String customer) {
|
||||
StandardEnvironment env = new StandardEnvironment();
|
||||
Properties props = new Properties();
|
||||
// populate properties for customer
|
||||
props.setProperty("host", "host.for." + customer);
|
||||
props.setProperty("user", "user");
|
||||
props.setProperty("password", "password");
|
||||
props.setProperty("remote.directory", "/tmp");
|
||||
PropertiesPropertySource pps = new PropertiesPropertySource("ftpprops", props);
|
||||
env.getPropertySources().addLast(pps);
|
||||
ctx.setEnvironment(env);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-ftp="http://www.springframework.org/schema/integration/ftp"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
|
||||
http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp-2.1.xsd">
|
||||
|
||||
<context:property-placeholder />
|
||||
|
||||
<bean id="ftpClientFactory" class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
|
||||
<property name="host" value="${host}"/>
|
||||
<property name="username" value="${user}"/>
|
||||
<property name="password" value="${password}"/>
|
||||
</bean>
|
||||
|
||||
<int:channel id="toFtpChannel"/>
|
||||
|
||||
<int-ftp:outbound-channel-adapter id="ftpOutbound"
|
||||
channel="toFtpChannel"
|
||||
remote-directory="${remote.directory}"
|
||||
session-factory="ftpClientFactory"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.integration.samples.ftp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
public class DynamicFtpChannelResolverTests {
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.samples.ftp.DynamicFtpChannelResolver#resolve(java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testResolve() {
|
||||
DynamicFtpChannelResolver dynamicFtpChannelResolver = new DynamicFtpChannelResolver();
|
||||
MessageChannel channel1 = dynamicFtpChannelResolver.resolve("customer1");
|
||||
assertNotNull(channel1);
|
||||
MessageChannel channel2 = dynamicFtpChannelResolver.resolve("customer2");
|
||||
assertNotNull(channel2);
|
||||
assertNotSame(channel1, channel2);
|
||||
MessageChannel channel1a = dynamicFtpChannelResolver.resolve("customer1");
|
||||
assertSame(channel1, channel1a);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.integration.samples.ftp;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
*
|
||||
*/
|
||||
public class FtpOutboundChannelAdapterSample {
|
||||
|
||||
@Test
|
||||
public void runDemo() throws Exception{
|
||||
ApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext("META-INF/spring/integration/DynamicFtpOutboundChannelAdapterSample-context.xml");
|
||||
MessageChannel channel = ctx.getBean("toDynRouter", MessageChannel.class);
|
||||
File file = File.createTempFile("temp", "txt");
|
||||
Message<File> message = MessageBuilder.withPayload(file)
|
||||
.setHeader("customer", "cust1")
|
||||
.build();
|
||||
try {
|
||||
channel.send(message);
|
||||
} catch (MessageHandlingException e) {
|
||||
assertTrue(e.getCause().getCause() instanceof UnknownHostException);
|
||||
assertEquals("host.for.cust1", e.getCause().getCause().getMessage());
|
||||
}
|
||||
// send another so we can see in the log we don't create the ac again.
|
||||
try {
|
||||
channel.send(message);
|
||||
} catch (MessageHandlingException e) {
|
||||
assertTrue(e.getCause().getCause() instanceof UnknownHostException);
|
||||
assertEquals("host.for.cust1", e.getCause().getCause().getMessage());
|
||||
}
|
||||
// send to a different customer; again, check the log to see a new ac is built
|
||||
message = MessageBuilder.withPayload(file)
|
||||
.setHeader("customer", "cust2").build();
|
||||
try {
|
||||
channel.send(message);
|
||||
} catch (MessageHandlingException e) {
|
||||
assertTrue(e.getCause().getCause() instanceof UnknownHostException);
|
||||
assertEquals("host.for.cust2", e.getCause().getCause().getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
|
||||
|
||||
<bean id="channelResolver" class="org.springframework.integration.samples.ftp.DynamicFtpChannelResolver" />
|
||||
|
||||
<int:channel id="toDynRouter" />
|
||||
|
||||
<int:router input-channel="toDynRouter"
|
||||
expression="@channelResolver.resolve(headers['customer'])"/>
|
||||
|
||||
</beans>
|
||||
8
advanced/dynamic-ftp/src/test/resources/log4j.properties
Normal file
8
advanced/dynamic-ftp/src/test/resources/log4j.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
log4j.rootCategory=WARN, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
|
||||
|
||||
log4j.category.org.springframework=WARN
|
||||
log4j.category.org.springframework.integration=DEBUG
|
||||
Reference in New Issue
Block a user