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:
Gary Russell
2011-12-15 16:32:08 -05:00
parent 8cd7b0b4e8
commit be5bcb3e95
8 changed files with 346 additions and 0 deletions

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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>

View 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